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