xref: /haiku/src/kits/interface/Polygon.cpp (revision 0562493379cd52eb7103531f895f10bb8e77c085)
1 /*
2  * Copyright 2001-2007, 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  */
9 
10 
11 #include <AffineTransform.h>
12 #include <Polygon.h>
13 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 
19 // Limit to avoid integer overflow when calculating the size to allocate
20 #define MAX_POINT_COUNT 10000000
21 
22 
23 BPolygon::BPolygon(const BPoint *ptArray, int32 numPoints)
24 	:
25 	fBounds(0.0, 0.0, 0.0, 0.0),
26 	fCount(numPoints),
27 	fPoints(NULL)
28 {
29 	if (fCount) {
30 		if (fCount > MAX_POINT_COUNT)
31 			debugger("BPolygon::BPolygon too many points");
32 
33 		// Note the use of memcpy here.  The assumption is that an array of BPoints can
34 		// be copied bit by bit and not use a copy constructor or an assignment
35 		// operator.  This breaks the containment of BPoint but will result in better
36 		// performance.  An example where the memcpy will fail would be if BPoint begins
37 		// to do lazy copying through reference counting.  By copying the bits, we will
38 		// copy reference counting state which will not be relevant at the destination.
39 		// Luckily, BPoint is a very simple class which isn't likely to change much.
40 		//
41 		// Similar use of memcpy appears later in this implementation also.
42 		size_t size = fCount * sizeof(BPoint);
43 		fPoints = (BPoint *)malloc(size);
44 		if (!fPoints) {
45 			fprintf(stderr, "BPolygon::BPolygon out of memory\n");
46 			fCount = 0;
47 			return;
48 		}
49 		memcpy(fPoints, ptArray, size);
50 		_ComputeBounds();
51 	}
52 }
53 
54 
55 BPolygon::BPolygon(const BPolygon *poly)
56 	:
57 	fBounds(0.0, 0.0, 0.0, 0.0),
58 	fCount(0),
59 	fPoints(NULL)
60 {
61 	*this = *poly;
62 }
63 
64 
65 BPolygon::BPolygon()
66 	:
67 	fBounds(0.0, 0.0, 0.0, 0.0),
68 	fCount(0),
69 	fPoints(NULL)
70 {
71 }
72 
73 
74 BPolygon::~BPolygon()
75 {
76 	free(fPoints);
77 }
78 
79 
80 BPolygon &
81 BPolygon::operator=(const BPolygon &from)
82 {
83 	// Make sure we aren't trying to perform a "self assignment".
84 	if (this != &from) {
85 		free(fPoints);
86 		fBounds = from.fBounds;
87 		fCount = from.fCount;
88 		if (fCount) {
89 			if (fCount > MAX_POINT_COUNT)
90 				debugger("BPolygon::operator= too many points");
91 			fPoints = (BPoint *)malloc(fCount * sizeof(BPoint));
92 			if (!fPoints) {
93 				fprintf(stderr, "BPolygon::operator= out of memory\n");
94 				fCount = 0;
95 			} else {
96 				memcpy(fPoints, from.fPoints, fCount * sizeof(BPoint));
97 			}
98 		} else {
99 			fPoints = NULL;
100 		}
101 	}
102 	return *this;
103 }
104 
105 
106 BRect
107 BPolygon::Frame() const
108 {
109 	return fBounds;
110 }
111 
112 
113 void
114 BPolygon::AddPoints(const BPoint *ptArray, int32 numPoints)
115 {
116 	if (numPoints < 0)
117 		debugger("BPolygon::AddPoints negative points");
118 	if (numPoints > MAX_POINT_COUNT || (fCount + numPoints) > MAX_POINT_COUNT)
119 		debugger("BPolygon::AddPoints too many points");
120 
121 	if (numPoints > 0) {
122 		BPoint *points = (BPoint *)realloc(fPoints, (fCount + numPoints) * sizeof(BPoint));
123 		if (!points) {
124 			fprintf(stderr, "BPolygon::AddPoints out of memory\n");
125 		} else {
126 			fPoints = points;
127 			memcpy(fPoints + fCount, ptArray, numPoints * sizeof(BPoint));
128 			fCount += numPoints;
129 			_ComputeBounds();
130 		}
131 	}
132 }
133 
134 
135 int32
136 BPolygon::CountPoints() const
137 {
138 	return fCount;
139 }
140 
141 
142 void
143 BPolygon::MapTo(BRect srcRect, BRect dstRect)
144 {
145 	for (uint32 i = 0; i < fCount; i++)
146 		_MapPoint(fPoints + i, srcRect, dstRect);
147 	_MapRectangle(&fBounds, srcRect, dstRect);
148 }
149 
150 
151 void
152 BPolygon::PrintToStream () const
153 {
154 	for (uint32 i = 0; i < fCount; i++)
155 		fPoints[i].PrintToStream();
156 }
157 
158 
159 void
160 BPolygon::Transform(const BAffineTransform& transform)
161 {
162 	transform.Apply(fPoints, (int32)fCount);
163 	_ComputeBounds();
164 }
165 
166 
167 BPolygon&
168 BPolygon::TransformBySelf(const BAffineTransform& transform)
169 {
170 	Transform(transform);
171 	return *this;
172 }
173 
174 
175 BPolygon*
176 BPolygon::TransformByCopy(const BAffineTransform& transform) const
177 {
178 	BPolygon* copy = new BPolygon(this);
179 	copy->Transform(transform);
180 	return copy;
181 }
182 
183 
184 void
185 BPolygon::_ComputeBounds()
186 {
187 	if (fCount == 0) {
188 		fBounds = BRect(0.0, 0.0, 0.0, 0.0);
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, BRect srcRect, 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, BRect srcRect, 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