xref: /haiku/src/kits/interface/Polygon.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 
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 
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 
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 
55 BPolygon::BPolygon()
56 	:
57 	fBounds(0.0f, 0.0f, -1.0f, -1.0f),
58 	fCount(0),
59 	fPoints(NULL)
60 {
61 }
62 
63 
64 BPolygon::~BPolygon()
65 {
66 	free(fPoints);
67 }
68 
69 
70 BPolygon&
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
90 BPolygon::Frame() const
91 {
92 	return fBounds;
93 }
94 
95 
96 void
97 BPolygon::AddPoints(const BPoint* points, int32 count)
98 {
99 	_AddPoints(points, count, true);
100 }
101 
102 
103 int32
104 BPolygon::CountPoints() const
105 {
106 	return fCount;
107 }
108 
109 
110 void
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
121 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
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(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(fPoints + fCount, points, count * sizeof(BPoint));
177 	fCount += count;
178 
179 	if (computeBounds)
180 		_ComputeBounds();
181 
182 	return true;
183 }
184 
185 
186 void
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
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
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