2 * Copyright 2006-2012, Haiku.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus <superstippi@gmx.de>
9 #include "VectorPath.h"
15 #include <agg_basics.h>
16 #include <agg_bounding_rect.h>
17 #include <agg_conv_curve.h>
18 #include <agg_curves.h>
22 # include <debugger.h>
24 #endif // ICON_O_MATIC
27 #include <TypeConstants.h>
32 # include "CommonPropertyIDs.h"
33 # include "IconProperty.h"
35 # include "Property.h"
36 # include "PropertyObject.h"
37 #endif // ICON_O_MATIC
39 #include "Transformable.h"
42 #define obj_new(type, n) ((type *)malloc ((n) * sizeof(type)))
43 #define obj_renew(p, type, n) ((type *)realloc (p, (n) * sizeof(type)))
46 #define ALLOC_CHUNKS 20
50 get_path_storage(agg::path_storage
& path
, const control_point
* points
,
51 int32 count
, bool closed
)
54 path
.move_to(points
[0].point
.x
, points
[0].point
.y
);
56 for (int32 i
= 1; i
< count
; i
++) {
57 path
.curve4(points
[i
- 1].point_out
.x
, points
[i
- 1].point_out
.y
,
58 points
[i
].point_in
.x
, points
[i
].point_in
.y
,
59 points
[i
].point
.x
, points
[i
].point
.y
);
62 // curve from last to first control point
64 points
[count
- 1].point_out
.x
, points
[count
- 1].point_out
.y
,
65 points
[0].point_in
.x
, points
[0].point_in
.y
,
66 points
[0].point
.x
, points
[0].point
.y
);
80 PathListener::PathListener()
85 PathListener::~PathListener()
94 VectorPath::VectorPath()
105 fCachedBounds(0.0, 0.0, -1.0, -1.0)
110 VectorPath::VectorPath(const VectorPath
& from
)
121 fCachedBounds(0.0, 0.0, -1.0, -1.0)
127 VectorPath::VectorPath(BMessage
* archive
)
138 fCachedBounds(0.0, 0.0, -1.0, -1.0)
145 if (archive
->GetInfo("point", &typeFound
, &countFound
) >= B_OK
146 && typeFound
== B_POINT_TYPE
147 && _SetPointCount(countFound
)) {
148 memset(fPath
, 0, fAllocCount
* sizeof(control_point
));
154 for (int32 i
= 0; i
< fPointCount
155 && archive
->FindPoint("point", i
, &point
) >= B_OK
156 && archive
->FindPoint("point in", i
, &pointIn
) >= B_OK
157 && archive
->FindPoint("point out", i
, &pointOut
) >= B_OK
158 && archive
->FindBool("connected", i
, &connected
) >= B_OK
; i
++) {
159 fPath
[i
].point
= point
;
160 fPath
[i
].point_in
= pointIn
;
161 fPath
[i
].point_out
= pointOut
;
162 fPath
[i
].connected
= connected
;
165 if (archive
->FindBool("path closed", &fClosed
) < B_OK
)
171 VectorPath::~VectorPath()
177 if (fListeners
.CountItems() > 0) {
178 PathListener
* listener
= (PathListener
*)fListeners
.ItemAt(0);
180 sprintf(message
, "VectorPath::~VectorPath() - "
181 "there are still listeners attached! %p/%s",
182 listener
, typeid(*listener
).name());
195 VectorPath::MakePropertyObject() const
197 PropertyObject
* object
= IconObject::MakePropertyObject();
202 object
->AddProperty(new BoolProperty(PROPERTY_CLOSED
, fClosed
));
205 BMessage
* archive
= new BMessage();
206 if (Archive(archive
) == B_OK
) {
207 object
->AddProperty(new IconProperty(PROPERTY_PATH
,
208 kPathPropertyIconBits
, kPathPropertyIconWidth
,
209 kPathPropertyIconHeight
, kPathPropertyIconFormat
, archive
));
217 VectorPath::SetToPropertyObject(const PropertyObject
* object
)
219 AutoNotificationSuspender
_(this);
220 IconObject::SetToPropertyObject(object
);
222 SetClosed(object
->Value(PROPERTY_CLOSED
, fClosed
));
224 IconProperty
* pathProperty
= dynamic_cast<IconProperty
*>(
225 object
->FindProperty(PROPERTY_PATH
));
226 if (pathProperty
&& pathProperty
->Message()) {
227 VectorPath
archivedPath(pathProperty
->Message());
228 *this = archivedPath
;
231 return HasPendingNotifications();
236 VectorPath::Archive(BMessage
* into
, bool deep
) const
238 status_t ret
= IconObject::Archive(into
, deep
);
242 if (fPointCount
> 0) {
243 // improve BMessage efficency by preallocating storage for all points
244 // with the first call
245 ret
= into
->AddData("point", B_POINT_TYPE
, &fPath
[0].point
,
246 sizeof(BPoint
), true, fPointCount
);
248 ret
= into
->AddData("point in", B_POINT_TYPE
, &fPath
[0].point_in
,
249 sizeof(BPoint
), true, fPointCount
);
252 ret
= into
->AddData("point out", B_POINT_TYPE
, &fPath
[0].point_out
,
253 sizeof(BPoint
), true, fPointCount
);
256 ret
= into
->AddData("connected", B_BOOL_TYPE
, &fPath
[0].connected
,
257 sizeof(bool), true, fPointCount
);
260 // add the rest of the points
261 for (int32 i
= 1; i
< fPointCount
&& ret
>= B_OK
; i
++) {
262 ret
= into
->AddData("point", B_POINT_TYPE
, &fPath
[i
].point
,
265 ret
= into
->AddData("point in", B_POINT_TYPE
, &fPath
[i
].point_in
,
269 ret
= into
->AddData("point out", B_POINT_TYPE
,
270 &fPath
[i
].point_out
, sizeof(BPoint
));
273 ret
= into
->AddData("connected", B_BOOL_TYPE
,
274 &fPath
[i
].connected
, sizeof(bool));
280 ret
= into
->AddBool("path closed", fClosed
);
282 fprintf(stderr
, "failed adding points!\n");
285 fprintf(stderr
, "failed adding close!\n");
289 ret
= into
->AddString("class", "VectorPath");
294 #endif // ICON_O_MATIC
301 VectorPath::operator=(const VectorPath
& from
)
303 _SetPointCount(from
.fPointCount
);
304 fClosed
= from
.fClosed
;
306 memcpy(fPath
, from
.fPath
, fPointCount
* sizeof(control_point
));
307 fCachedBounds
= from
.fCachedBounds
;
309 fprintf(stderr
, "VectorPath() -> allocation failed in operator=!\n");
312 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
321 VectorPath::operator==(const VectorPath
& other
) const
323 if (fClosed
!= other
.fClosed
)
326 if (fPointCount
!= other
.fPointCount
)
329 if (fPath
== NULL
&& other
.fPath
== NULL
)
332 if (fPath
== NULL
|| other
.fPath
== NULL
)
335 for (int32 i
= 0; i
< fPointCount
; i
++) {
336 if (fPath
[i
].point
!= other
.fPath
[i
].point
337 || fPath
[i
].point_in
!= other
.fPath
[i
].point_in
338 || fPath
[i
].point_out
!= other
.fPath
[i
].point_out
339 || fPath
[i
].connected
!= other
.fPath
[i
].connected
) {
349 VectorPath::MakeEmpty()
359 VectorPath::AddPoint(BPoint point
)
361 int32 index
= fPointCount
;
363 if (_SetPointCount(fPointCount
+ 1)) {
364 _SetPoint(index
, point
);
365 _NotifyPointAdded(index
);
374 VectorPath::AddPoint(const BPoint
& point
, const BPoint
& pointIn
,
375 const BPoint
& pointOut
, bool connected
)
377 int32 index
= fPointCount
;
379 if (_SetPointCount(fPointCount
+ 1)) {
380 _SetPoint(index
, point
, pointIn
, pointOut
, connected
);
381 _NotifyPointAdded(index
);
390 VectorPath::AddPoint(BPoint point
, int32 index
)
394 if (index
> fPointCount
)
397 if (_SetPointCount(fPointCount
+ 1)) {
399 if (index
< fPointCount
- 1) {
400 for (int32 i
= fPointCount
; i
> index
; i
--) {
401 fPath
[i
].point
= fPath
[i
- 1].point
;
402 fPath
[i
].point_in
= fPath
[i
- 1].point_in
;
403 fPath
[i
].point_out
= fPath
[i
- 1].point_out
;
404 fPath
[i
].connected
= fPath
[i
- 1].connected
;
407 _SetPoint(index
, point
);
408 _NotifyPointAdded(index
);
416 VectorPath::RemovePoint(int32 index
)
418 if (index
>= 0 && index
< fPointCount
) {
419 if (index
< fPointCount
- 1) {
421 for (int32 i
= index
; i
< fPointCount
- 1; i
++) {
422 fPath
[i
].point
= fPath
[i
+ 1].point
;
423 fPath
[i
].point_in
= fPath
[i
+ 1].point_in
;
424 fPath
[i
].point_out
= fPath
[i
+ 1].point_out
;
425 fPath
[i
].connected
= fPath
[i
+ 1].connected
;
430 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
432 _NotifyPointRemoved(index
);
440 VectorPath::SetPoint(int32 index
, BPoint point
)
442 if (index
== fPointCount
)
444 if (index
>= 0 && index
< fPointCount
) {
445 BPoint offset
= point
- fPath
[index
].point
;
446 fPath
[index
].point
= point
;
447 fPath
[index
].point_in
+= offset
;
448 fPath
[index
].point_out
+= offset
;
450 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
452 _NotifyPointChanged(index
);
460 VectorPath::SetPoint(int32 index
, BPoint point
, BPoint pointIn
, BPoint pointOut
,
463 if (index
== fPointCount
)
465 if (index
>= 0 && index
< fPointCount
) {
466 fPath
[index
].point
= point
;
467 fPath
[index
].point_in
= pointIn
;
468 fPath
[index
].point_out
= pointOut
;
469 fPath
[index
].connected
= connected
;
471 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
473 _NotifyPointChanged(index
);
481 VectorPath::SetPointIn(int32 i
, BPoint point
)
483 if (i
== fPointCount
)
485 if (i
>= 0 && i
< fPointCount
) {
486 // first, set the "in" point
487 fPath
[i
].point_in
= point
;
488 // now see what to do about the "out" point
489 if (fPath
[i
].connected
) {
490 // keep all three points in one line
491 BPoint v
= fPath
[i
].point
- fPath
[i
].point_in
;
492 float distIn
= sqrtf(v
.x
* v
.x
+ v
.y
* v
.y
);
494 float distOut
= agg::calc_distance(
495 fPath
[i
].point
.x
, fPath
[i
].point
.y
,
496 fPath
[i
].point_out
.x
, fPath
[i
].point_out
.y
);
497 float scale
= (distIn
+ distOut
) / distIn
;
500 fPath
[i
].point_out
= fPath
[i
].point_in
+ v
;
504 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
506 _NotifyPointChanged(i
);
514 VectorPath::SetPointOut(int32 i
, BPoint point
, bool mirrorDist
)
516 if (i
== fPointCount
)
518 if (i
>= 0 && i
< fPointCount
) {
519 // first, set the "out" point
520 fPath
[i
].point_out
= point
;
521 // now see what to do about the "out" point
523 // mirror "in" point around main control point
524 BPoint v
= fPath
[i
].point
- fPath
[i
].point_out
;
525 fPath
[i
].point_in
= fPath
[i
].point
+ v
;
526 } else if (fPath
[i
].connected
) {
527 // keep all three points in one line
528 BPoint v
= fPath
[i
].point
- fPath
[i
].point_out
;
529 float distOut
= sqrtf(v
.x
* v
.x
+ v
.y
* v
.y
);
531 float distIn
= agg::calc_distance(
532 fPath
[i
].point
.x
, fPath
[i
].point
.y
,
533 fPath
[i
].point_in
.x
, fPath
[i
].point_in
.y
);
534 float scale
= (distIn
+ distOut
) / distOut
;
537 fPath
[i
].point_in
= fPath
[i
].point_out
+ v
;
541 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
543 _NotifyPointChanged(i
);
551 VectorPath::SetInOutConnected(int32 index
, bool connected
)
553 if (index
>= 0 && index
< fPointCount
) {
554 fPath
[index
].connected
= connected
;
555 _NotifyPointChanged(index
);
566 VectorPath::GetPointAt(int32 index
, BPoint
& point
) const
568 if (index
== fPointCount
)
570 if (index
>= 0 && index
< fPointCount
) {
571 point
= fPath
[index
].point
;
579 VectorPath::GetPointInAt(int32 index
, BPoint
& point
) const
581 if (index
== fPointCount
)
583 if (index
>= 0 && index
< fPointCount
) {
584 point
= fPath
[index
].point_in
;
592 VectorPath::GetPointOutAt(int32 index
, BPoint
& point
) const
594 if (index
== fPointCount
)
596 if (index
>= 0 && index
< fPointCount
) {
597 point
= fPath
[index
].point_out
;
605 VectorPath::GetPointsAt(int32 index
, BPoint
& point
, BPoint
& pointIn
,
606 BPoint
& pointOut
, bool* connected
) const
608 if (index
>= 0 && index
< fPointCount
) {
609 point
= fPath
[index
].point
;
610 pointIn
= fPath
[index
].point_in
;
611 pointOut
= fPath
[index
].point_out
;
614 *connected
= fPath
[index
].connected
;
623 VectorPath::CountPoints() const
635 distance_to_curve(const BPoint
& p
, const BPoint
& a
, const BPoint
& aOut
,
636 const BPoint
& bIn
, const BPoint
& b
)
638 agg::curve4_inc
curve(a
.x
, a
.y
, aOut
.x
, aOut
.y
, bIn
.x
, bIn
.y
, b
.x
, b
.y
);
640 float segDist
= FLT_MAX
;
641 double x1
, y1
, x2
, y2
;
642 unsigned cmd
= curve
.vertex(&x1
, &y1
);
643 while (!agg::is_stop(cmd
)) {
644 cmd
= curve
.vertex(&x2
, &y2
);
645 // first figure out if point is between segment start and end points
646 double a
= agg::calc_distance(p
.x
, p
.y
, x2
, y2
);
647 double b
= agg::calc_distance(p
.x
, p
.y
, x1
, y1
);
649 float currentDist
= min_c(a
, b
);
651 if (a
> 0.0 && b
> 0.0) {
652 double c
= agg::calc_distance(x1
, y1
, x2
, y2
);
654 double alpha
= acos((b
* b
+ c
* c
- a
* a
) / (2 * b
* c
));
655 double beta
= acos((a
* a
+ c
* c
- b
* b
) / (2 * a
* c
));
657 if (alpha
<= M_PI_2
&& beta
<= M_PI_2
) {
658 currentDist
= fabs(agg::calc_line_point_distance(x1
, y1
, x2
, y2
,
663 if (currentDist
< segDist
)
664 segDist
= currentDist
;
674 VectorPath::GetDistance(BPoint p
, float* distance
, int32
* index
) const
676 if (fPointCount
> 1) {
677 // generate a curve for each segment of the path
678 // then iterate over the segments of the curve measuring the distance
681 for (int32 i
= 0; i
< fPointCount
- 1; i
++) {
682 float segDist
= distance_to_curve(p
, fPath
[i
].point
,
683 fPath
[i
].point_out
, fPath
[i
+ 1].point_in
, fPath
[i
+ 1].point
);
684 if (segDist
< *distance
) {
690 float segDist
= distance_to_curve(p
, fPath
[fPointCount
- 1].point
,
691 fPath
[fPointCount
- 1].point_out
, fPath
[0].point_in
,
693 if (segDist
< *distance
) {
695 *index
= fPointCount
;
705 VectorPath::FindBezierScale(int32 index
, BPoint point
, double* scale
) const
707 if (index
>= 0 && index
< fPointCount
&& scale
) {
711 double dt
= 1.0 / maxStep
;
714 double min
= FLT_MAX
;
717 for (int step
= 1; step
< maxStep
; step
++) {
720 GetPoint(index
, t
, curvePoint
);
721 double d
= agg::calc_distance(curvePoint
.x
, curvePoint
.y
,
736 VectorPath::GetPoint(int32 index
, double t
, BPoint
& point
) const
738 if (index
>= 0 && index
< fPointCount
) {
739 double t1
= (1 - t
) * (1 - t
) * (1 - t
);
740 double t2
= (1 - t
) * (1 - t
) * t
* 3;
741 double t3
= (1 - t
) * t
* t
* 3;
742 double t4
= t
* t
* t
;
744 if (index
< fPointCount
- 1) {
745 point
.x
= fPath
[index
].point
.x
* t1
+ fPath
[index
].point_out
.x
* t2
746 + fPath
[index
+ 1].point_in
.x
* t3
747 + fPath
[index
+ 1].point
.x
* t4
;
749 point
.y
= fPath
[index
].point
.y
* t1
+ fPath
[index
].point_out
.y
* t2
750 + fPath
[index
+ 1].point_in
.y
* t3
751 + fPath
[index
+ 1].point
.y
* t4
;
752 } else if (fClosed
) {
753 point
.x
= fPath
[fPointCount
- 1].point
.x
* t1
754 + fPath
[fPointCount
- 1].point_out
.x
* t2
755 + fPath
[0].point_in
.x
* t3
+ fPath
[0].point
.x
* t4
;
757 point
.y
= fPath
[fPointCount
- 1].point
.y
* t1
758 + fPath
[fPointCount
- 1].point_out
.y
* t2
759 + fPath
[0].point_in
.y
* t3
+ fPath
[0].point
.y
* t4
;
767 #endif // ICON_O_MATIC
771 VectorPath::SetClosed(bool closed
)
773 if (fClosed
!= closed
) {
775 _NotifyClosedChanged();
782 VectorPath::Bounds() const
784 // the bounds of the actual curves, not the control points!
785 if (!fCachedBounds
.IsValid())
786 fCachedBounds
= _Bounds();
787 return fCachedBounds
;
792 VectorPath::_Bounds() const
794 agg::path_storage path
;
797 if (get_path_storage(path
, fPath
, fPointCount
, fClosed
)) {
798 agg::conv_curve
<agg::path_storage
> curve(path
);
802 double left
, top
, right
, bottom
;
804 agg::bounding_rect(curve
, pathID
, 0, 1, &left
, &top
, &right
, &bottom
);
806 b
.Set(left
, top
, right
, bottom
);
807 } else if (fPointCount
== 1) {
808 b
.Set(fPath
[0].point
.x
, fPath
[0].point
.y
, fPath
[0].point
.x
,
811 b
.Set(0.0, 0.0, -1.0, -1.0);
818 VectorPath::ControlPointBounds() const
820 if (fPointCount
> 0) {
821 BRect
r(fPath
[0].point
, fPath
[0].point
);
822 for (int32 i
= 0; i
< fPointCount
; i
++) {
824 r
.left
= min_c(r
.left
, fPath
[i
].point
.x
);
825 r
.top
= min_c(r
.top
, fPath
[i
].point
.y
);
826 r
.right
= max_c(r
.right
, fPath
[i
].point
.x
);
827 r
.bottom
= max_c(r
.bottom
, fPath
[i
].point
.y
);
828 // include "in" point
829 r
.left
= min_c(r
.left
, fPath
[i
].point_in
.x
);
830 r
.top
= min_c(r
.top
, fPath
[i
].point_in
.y
);
831 r
.right
= max_c(r
.right
, fPath
[i
].point_in
.x
);
832 r
.bottom
= max_c(r
.bottom
, fPath
[i
].point_in
.y
);
833 // include "out" point
834 r
.left
= min_c(r
.left
, fPath
[i
].point_out
.x
);
835 r
.top
= min_c(r
.top
, fPath
[i
].point_out
.y
);
836 r
.right
= max_c(r
.right
, fPath
[i
].point_out
.x
);
837 r
.bottom
= max_c(r
.bottom
, fPath
[i
].point_out
.y
);
841 return BRect(0.0, 0.0, -1.0, -1.0);
846 VectorPath::Iterate(Iterator
* iterator
, float smoothScale
) const
848 if (fPointCount
> 1) {
849 // generate a curve for each segment of the path
850 // then iterate over the segments of the curve
851 agg::curve4_inc curve
;
852 curve
.approximation_scale(smoothScale
);
854 for (int32 i
= 0; i
< fPointCount
- 1; i
++) {
855 iterator
->MoveTo(fPath
[i
].point
);
856 curve
.init(fPath
[i
].point
.x
, fPath
[i
].point
.y
,
857 fPath
[i
].point_out
.x
, fPath
[i
].point_out
.y
,
858 fPath
[i
+ 1].point_in
.x
, fPath
[i
+ 1].point_in
.y
,
859 fPath
[i
+ 1].point
.x
, fPath
[i
+ 1].point
.y
);
862 unsigned cmd
= curve
.vertex(&x
, &y
);
863 while (!agg::is_stop(cmd
)) {
866 cmd
= curve
.vertex(&x
, &y
);
870 iterator
->MoveTo(fPath
[fPointCount
- 1].point
);
871 curve
.init(fPath
[fPointCount
- 1].point
.x
,
872 fPath
[fPointCount
- 1].point
.y
,
873 fPath
[fPointCount
- 1].point_out
.x
,
874 fPath
[fPointCount
- 1].point_out
.y
,
875 fPath
[0].point_in
.x
, fPath
[0].point_in
.y
,
876 fPath
[0].point
.x
, fPath
[0].point
.y
);
879 unsigned cmd
= curve
.vertex(&x
, &y
);
880 while (!agg::is_stop(cmd
)) {
883 cmd
= curve
.vertex(&x
, &y
);
891 VectorPath::CleanUp()
893 if (fPointCount
== 0)
898 // remove last point if it is coincident with the first
899 if (fClosed
&& fPointCount
>= 1) {
900 if (fPath
[0].point
== fPath
[fPointCount
- 1].point
) {
901 fPath
[0].point_in
= fPath
[fPointCount
- 1].point_in
;
902 _SetPointCount(fPointCount
- 1);
907 for (int32 i
= 0; i
< fPointCount
; i
++) {
908 // check for unnecessary, duplicate points
910 if (fPath
[i
- 1].point
== fPath
[i
].point
911 && fPath
[i
- 1].point
== fPath
[i
- 1].point_out
912 && fPath
[i
].point
== fPath
[i
].point_in
) {
913 // the previous point can be removed
914 BPoint in
= fPath
[i
- 1].point_in
;
915 if (RemovePoint(i
- 1)) {
917 fPath
[i
].point_in
= in
;
922 // re-establish connections of in-out control points if
923 // they line up with the main control point
924 if (fPath
[i
].point_in
== fPath
[i
].point_out
925 || fPath
[i
].point
== fPath
[i
].point_out
926 || fPath
[i
].point
== fPath
[i
].point_in
927 || (fabs(agg::calc_line_point_distance(fPath
[i
].point_in
.x
,
928 fPath
[i
].point_in
.y
, fPath
[i
].point
.x
, fPath
[i
].point
.y
,
929 fPath
[i
].point_out
.x
, fPath
[i
].point_out
.y
)) < 0.01
930 && fabs(agg::calc_line_point_distance(fPath
[i
].point_out
.x
,
931 fPath
[i
].point_out
.y
, fPath
[i
].point
.x
, fPath
[i
].point
.y
,
932 fPath
[i
].point_in
.x
, fPath
[i
].point_in
.y
)) < 0.01)) {
933 fPath
[i
].connected
= true;
939 _NotifyPathChanged();
944 VectorPath::Reverse()
946 VectorPath
temp(*this);
948 for (int32 i
= fPointCount
- 1; i
>= 0; i
--) {
949 temp
.SetPoint(index
, fPath
[i
].point
, fPath
[i
].point_out
,
950 fPath
[i
].point_in
, fPath
[i
].connected
);
955 _NotifyPathReversed();
960 VectorPath::ApplyTransform(const Transformable
& transform
)
962 if (transform
.IsIdentity())
965 for (int32 i
= 0; i
< fPointCount
; i
++) {
966 transform
.Transform(&(fPath
[i
].point
));
967 transform
.Transform(&(fPath
[i
].point_out
));
968 transform
.Transform(&(fPath
[i
].point_in
));
971 _NotifyPathChanged();
976 VectorPath::PrintToStream() const
978 for (int32 i
= 0; i
< fPointCount
; i
++) {
979 printf("point %" B_PRId32
": (%f, %f) -> (%f, %f) -> (%f, %f) (%d)\n", i
,
980 fPath
[i
].point_in
.x
, fPath
[i
].point_in
.y
,
981 fPath
[i
].point
.x
, fPath
[i
].point
.y
,
982 fPath
[i
].point_out
.x
, fPath
[i
].point_out
.y
, fPath
[i
].connected
);
988 VectorPath::GetAGGPathStorage(agg::path_storage
& path
) const
990 return get_path_storage(path
, fPath
, fPointCount
, fClosed
);
1000 VectorPath::AddListener(PathListener
* listener
)
1002 if (listener
&& !fListeners
.HasItem((void*)listener
))
1003 return fListeners
.AddItem((void*)listener
);
1009 VectorPath::RemoveListener(PathListener
* listener
)
1011 return fListeners
.RemoveItem((void*)listener
);
1016 VectorPath::CountListeners() const
1018 return fListeners
.CountItems();
1023 VectorPath::ListenerAtFast(int32 index
) const
1025 return (PathListener
*)fListeners
.ItemAtFast(index
);
1028 #endif // ICON_O_MATIC
1035 VectorPath::_SetPoint(int32 index
, BPoint point
)
1037 fPath
[index
].point
= point
;
1038 fPath
[index
].point_in
= point
;
1039 fPath
[index
].point_out
= point
;
1041 fPath
[index
].connected
= true;
1043 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
1048 VectorPath::_SetPoint(int32 index
, const BPoint
& point
, const BPoint
& pointIn
,
1049 const BPoint
& pointOut
, bool connected
)
1051 fPath
[index
].point
= point
;
1052 fPath
[index
].point_in
= pointIn
;
1053 fPath
[index
].point_out
= pointOut
;
1055 fPath
[index
].connected
= connected
;
1057 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
1065 VectorPath::_SetPointCount(int32 count
)
1067 // handle reallocation if we run out of room
1068 if (count
>= fAllocCount
) {
1069 fAllocCount
= ((count
) / ALLOC_CHUNKS
+ 1) * ALLOC_CHUNKS
;
1071 fPath
= obj_renew(fPath
, control_point
, fAllocCount
);
1073 fPath
= obj_new(control_point
, fAllocCount
);
1075 if (fPath
!= NULL
) {
1076 memset(fPath
+ fPointCount
, 0,
1077 (fAllocCount
- fPointCount
) * sizeof(control_point
));
1081 // update point count
1083 fPointCount
= count
;
1085 // reallocation might have failed
1088 fprintf(stderr
, "VectorPath::_SetPointCount(%" B_PRId32
") - allocation failed!\n",
1092 fCachedBounds
.Set(0.0, 0.0, -1.0, -1.0);
1094 return fPath
!= NULL
;
1104 VectorPath::_NotifyPointAdded(int32 index
) const
1106 BList
listeners(fListeners
);
1107 int32 count
= listeners
.CountItems();
1108 for (int32 i
= 0; i
< count
; i
++) {
1109 PathListener
* listener
= (PathListener
*)listeners
.ItemAtFast(i
);
1110 listener
->PointAdded(index
);
1116 VectorPath::_NotifyPointChanged(int32 index
) const
1118 BList
listeners(fListeners
);
1119 int32 count
= listeners
.CountItems();
1120 for (int32 i
= 0; i
< count
; i
++) {
1121 PathListener
* listener
= (PathListener
*)listeners
.ItemAtFast(i
);
1122 listener
->PointChanged(index
);
1128 VectorPath::_NotifyPointRemoved(int32 index
) const
1130 BList
listeners(fListeners
);
1131 int32 count
= listeners
.CountItems();
1132 for (int32 i
= 0; i
< count
; i
++) {
1133 PathListener
* listener
= (PathListener
*)listeners
.ItemAtFast(i
);
1134 listener
->PointRemoved(index
);
1140 VectorPath::_NotifyPathChanged() const
1142 BList
listeners(fListeners
);
1143 int32 count
= listeners
.CountItems();
1144 for (int32 i
= 0; i
< count
; i
++) {
1145 PathListener
* listener
= (PathListener
*)listeners
.ItemAtFast(i
);
1146 listener
->PathChanged();
1152 VectorPath::_NotifyClosedChanged() const
1154 BList
listeners(fListeners
);
1155 int32 count
= listeners
.CountItems();
1156 for (int32 i
= 0; i
< count
; i
++) {
1157 PathListener
* listener
= (PathListener
*)listeners
.ItemAtFast(i
);
1158 listener
->PathClosedChanged();
1164 VectorPath::_NotifyPathReversed() const
1166 BList
listeners(fListeners
);
1167 int32 count
= listeners
.CountItems();
1168 for (int32 i
= 0; i
< count
; i
++) {
1169 PathListener
* listener
= (PathListener
*)listeners
.ItemAtFast(i
);
1170 listener
->PathReversed();
1174 #endif // ICON_O_MATIC