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
25BPolygon::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
35BPolygon::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
45BPolygon::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
55BPolygon::BPolygon()
56	:
57	fBounds(0.0f, 0.0f, -1.0f, -1.0f),
58	fCount(0),
59	fPoints(NULL)
60{
61}
62
63
64BPolygon::~BPolygon()
65{
66	free(fPoints);
67}
68
69
70BPolygon&
71BPolygon::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
89BRect
90BPolygon::Frame() const
91{
92	return fBounds;
93}
94
95
96void
97BPolygon::AddPoints(const BPoint* points, int32 count)
98{
99	_AddPoints(points, count, true);
100}
101
102
103int32
104BPolygon::CountPoints() const
105{
106	return fCount;
107}
108
109
110void
111BPolygon::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
120void
121BPolygon::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
156bool
157BPolygon::_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((void*)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((void*)(fPoints + fCount), points, count * sizeof(BPoint));
177	fCount += count;
178
179	if (computeBounds)
180		_ComputeBounds();
181
182	return true;
183}
184
185
186void
187BPolygon::_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
212void
213BPolygon::_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
223void
224BPolygon::_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