1 /*
2 * Copyright 2001-2009, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Marc Flerackers, mflerackers@androme.be
8 * Marcus Overhagen
9 */
10
11
12 #include <Polygon.h>
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include <AffineTransform.h>
19
20
21 // Limit to avoid integer overflow when calculating the size to allocate
22 #define MAX_POINT_COUNT 10000000
23
24
BPolygon(const BPoint * points,int32 count)25 BPolygon::BPolygon(const BPoint* points, int32 count)
26 :
27 fBounds(0.0f, 0.0f, -1.0f, -1.0f),
28 fCount(0),
29 fPoints(NULL)
30 {
31 _AddPoints(points, count, true);
32 }
33
34
BPolygon(const BPolygon & other)35 BPolygon::BPolygon(const BPolygon& other)
36 :
37 fBounds(0.0f, 0.0f, -1.0f, -1.0f),
38 fCount(0),
39 fPoints(NULL)
40 {
41 *this = other;
42 }
43
44
BPolygon(const BPolygon * other)45 BPolygon::BPolygon(const BPolygon* other)
46 :
47 fBounds(0.0f, 0.0f, -1.0f, -1.0f),
48 fCount(0),
49 fPoints(NULL)
50 {
51 *this = *other;
52 }
53
54
BPolygon()55 BPolygon::BPolygon()
56 :
57 fBounds(0.0f, 0.0f, -1.0f, -1.0f),
58 fCount(0),
59 fPoints(NULL)
60 {
61 }
62
63
~BPolygon()64 BPolygon::~BPolygon()
65 {
66 free(fPoints);
67 }
68
69
70 BPolygon&
operator =(const BPolygon & other)71 BPolygon::operator=(const BPolygon& other)
72 {
73 // Make sure we aren't trying to perform a "self assignment".
74 if (this == &other)
75 return *this;
76
77 free(fPoints);
78 fPoints = NULL;
79 fCount = 0;
80 fBounds.Set(0.0f, 0.0f, -1.0f, -1.0f);
81
82 if (_AddPoints(other.fPoints, other.fCount, false))
83 fBounds = other.fBounds;
84
85 return *this;
86 }
87
88
89 BRect
Frame() const90 BPolygon::Frame() const
91 {
92 return fBounds;
93 }
94
95
96 void
AddPoints(const BPoint * points,int32 count)97 BPolygon::AddPoints(const BPoint* points, int32 count)
98 {
99 _AddPoints(points, count, true);
100 }
101
102
103 int32
CountPoints() const104 BPolygon::CountPoints() const
105 {
106 return fCount;
107 }
108
109
110 void
MapTo(BRect source,BRect destination)111 BPolygon::MapTo(BRect source, BRect destination)
112 {
113 for (uint32 i = 0; i < fCount; i++)
114 _MapPoint(fPoints + i, source, destination);
115
116 _MapRectangle(&fBounds, source, destination);
117 }
118
119
120 void
PrintToStream() const121 BPolygon::PrintToStream() const
122 {
123 for (uint32 i = 0; i < fCount; i++)
124 fPoints[i].PrintToStream();
125 }
126
127
128 //void
129 //BPolygon::TransformBy(const BAffineTransform& transform)
130 //{
131 // transform.Apply(fPoints, (int32)fCount);
132 // _ComputeBounds();
133 //}
134 //
135 //
136 //BPolygon&
137 //BPolygon::TransformBySelf(const BAffineTransform& transform)
138 //{
139 // TransformBy(transform);
140 // return *this;
141 //}
142 //
143 //
144 //BPolygon
145 //BPolygon::TransformByCopy(const BAffineTransform& transform) const
146 //{
147 // BPolygon copy(this);
148 // copy.TransformBy(transform);
149 // return copy;
150 //}
151
152
153 // #pragma mark - BPolygon private methods
154
155
156 bool
_AddPoints(const BPoint * points,int32 count,bool computeBounds)157 BPolygon::_AddPoints(const BPoint* points, int32 count, bool computeBounds)
158 {
159 if (points == NULL || count <= 0)
160 return false;
161 if (count > MAX_POINT_COUNT || (fCount + count) > MAX_POINT_COUNT) {
162 fprintf(stderr, "BPolygon::_AddPoints(%" B_PRId32 ") - too many points"
163 "\n", count);
164 return false;
165 }
166
167 BPoint* newPoints = (BPoint*)realloc((void*)fPoints, (fCount + count)
168 * sizeof(BPoint));
169 if (newPoints == NULL) {
170 fprintf(stderr, "BPolygon::_AddPoints(%" B_PRId32 ") out of memory\n",
171 count);
172 return false;
173 }
174
175 fPoints = newPoints;
176 memcpy((void*)(fPoints + fCount), points, count * sizeof(BPoint));
177 fCount += count;
178
179 if (computeBounds)
180 _ComputeBounds();
181
182 return true;
183 }
184
185
186 void
_ComputeBounds()187 BPolygon::_ComputeBounds()
188 {
189 if (fCount == 0) {
190 fBounds = BRect(0.0, 0.0, -1.0f, -1.0f);
191 return;
192 }
193
194 fBounds = BRect(fPoints[0], fPoints[0]);
195
196 for (uint32 i = 1; i < fCount; i++) {
197 if (fPoints[i].x < fBounds.left)
198 fBounds.left = fPoints[i].x;
199
200 if (fPoints[i].y < fBounds.top)
201 fBounds.top = fPoints[i].y;
202
203 if (fPoints[i].x > fBounds.right)
204 fBounds.right = fPoints[i].x;
205
206 if (fPoints[i].y > fBounds.bottom)
207 fBounds.bottom = fPoints[i].y;
208 }
209 }
210
211
212 void
_MapPoint(BPoint * point,const BRect & source,const BRect & destination)213 BPolygon::_MapPoint(BPoint* point, const BRect& source,
214 const BRect& destination)
215 {
216 point->x = (point->x - source.left) * destination.Width() / source.Width()
217 + destination.left;
218 point->y = (point->y - source.top) * destination.Height() / source.Height()
219 + destination.top;
220 }
221
222
223 void
_MapRectangle(BRect * rect,const BRect & source,const BRect & destination)224 BPolygon::_MapRectangle(BRect* rect, const BRect& source,
225 const BRect& destination)
226 {
227 BPoint leftTop = rect->LeftTop();
228 BPoint bottomRight = rect->RightBottom();
229
230 _MapPoint(&leftTop, source, destination);
231 _MapPoint(&bottomRight, source, destination);
232
233 *rect = BRect(leftTop, bottomRight);
234 }
235