xref: /haiku/src/kits/interface/Polygon.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
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(%ld) - too many points\n",
161 			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(%ld) out of memory\n", count);
169 		return false;
170 	}
171 
172 	fPoints = newPoints;
173 	memcpy(fPoints + fCount, points, count * sizeof(BPoint));
174 	fCount += count;
175 
176 	if (computeBounds)
177 		_ComputeBounds();
178 
179 	return true;
180 }
181 
182 
183 void
184 BPolygon::_ComputeBounds()
185 {
186 	if (fCount == 0) {
187 		fBounds = BRect(0.0, 0.0, -1.0f, -1.0f);
188 		return;
189 	}
190 
191 	fBounds = BRect(fPoints[0], fPoints[0]);
192 
193 	for (uint32 i = 1; i < fCount; i++) {
194 		if (fPoints[i].x < fBounds.left)
195 			fBounds.left = fPoints[i].x;
196 		if (fPoints[i].y < fBounds.top)
197 			fBounds.top = fPoints[i].y;
198 		if (fPoints[i].x > fBounds.right)
199 			fBounds.right = fPoints[i].x;
200 		if (fPoints[i].y > fBounds.bottom)
201 			fBounds.bottom = fPoints[i].y;
202 	}
203 }
204 
205 
206 void
207 BPolygon::_MapPoint(BPoint* point, const BRect& srcRect, const BRect& dstRect)
208 {
209 	point->x = (point->x - srcRect.left) * dstRect.Width() / srcRect.Width()
210 		+ dstRect.left;
211 	point->y = (point->y - srcRect.top) * dstRect.Height() / srcRect.Height()
212 		+ dstRect.top;
213 }
214 
215 
216 void
217 BPolygon::_MapRectangle(BRect* rect, const BRect& srcRect,
218 	const BRect& dstRect)
219 {
220 	BPoint leftTop = rect->LeftTop();
221 	BPoint bottomRight = rect->RightBottom();
222 
223 	_MapPoint(&leftTop, srcRect, dstRect);
224 	_MapPoint(&bottomRight, srcRect, dstRect);
225 
226 	*rect = BRect(leftTop, bottomRight);
227 }
228