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