1 /* file : PointSet2D.java
2 *
3 * Project : geometry
4 *
5 * ===========================================
6 *
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * See the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library. if not, write to :
20 * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 * Created on 5 mai 2006
24 *
25 */
26
27 package math.geom2d.point;
28
29 import java.awt.Graphics2D;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Iterator;
34
35 import math.geom2d.AffineTransform2D;
36 import math.geom2d.Box2D;
37 import math.geom2d.Point2D;
38 import math.geom2d.Shape2D;
39 import math.geom2d.circulinear.CirculinearCurve2DUtils;
40 import math.geom2d.circulinear.CirculinearDomain2D;
41 import math.geom2d.circulinear.CirculinearShape2D;
42 import math.geom2d.transform.CircleInversion2D;
43
44 /**
45 * Represent the union of a finite number of Point2D.
46 *
47 * @author dlegland
48 */
49 public class PointArray2D
50 implements PointSet2D, CirculinearShape2D, Cloneable {
51
52 // ===================================================================
53 // inner variables
54
55 /**
56 * The inner collection of points composing the set.
57 */
58 protected ArrayList<Point2D> points = null;
59
60 // ===================================================================
61 // constructors
62
63 /**
64 * Creates a new PointArray2D without any points.
65 */
66 public PointArray2D() {
67 this(0);
68 }
69
70 /**
71 * Creates a new empty PointArray2D, but preallocates the memory for storing a
72 * given amount of points.
73 *
74 * @param n the expected number of points in the PointArray2D.
75 */
76 public PointArray2D(int n) {
77 points = new ArrayList<Point2D>();
78 }
79
80 /**
81 * Instances of Point2D are directly added, other Point are converted to
82 * Point2D with the same location.
83 */
84 public PointArray2D(java.awt.geom.Point2D[] points) {
85 this(points.length);
86 for (java.awt.geom.Point2D element : points)
87 if (Point2D.class.isInstance(element))
88 this.points.add((Point2D) element);
89 else
90 this.points.add(new Point2D(element));
91 }
92
93 /**
94 * Points must be a collection of java.awt.Point. Instances of Point2D are
95 * directly added, other Point are converted to Point2D with the same
96 * location.
97 *
98 * @param points
99 */
100 public PointArray2D(Collection<? extends java.awt.geom.Point2D> points) {
101 this(points.size());
102
103 for (java.awt.geom.Point2D point : points) {
104 if (point instanceof Point2D)
105 this.points.add((Point2D) point);
106 else
107 this.points.add(new Point2D(point));
108 }
109 }
110
111 // ===================================================================
112 // static factory methods
113
114 public final static PointSet2D create(Collection<? extends java.awt.geom.Point2D> points) {
115 return new PointArray2D(points);
116 }
117
118 public final static PointSet2D create(Point2D[] points) {
119 return new PointArray2D(points);
120 }
121
122 public final static PointSet2D create(int size) {
123 return new PointArray2D(size);
124 }
125
126 // ===================================================================
127 // methods implementing the PointSet2D interface
128
129 /**
130 * Add a new point to the set of point. If point is not an instance of
131 * Point2D, a Point2D with same location is added instead of point.
132 *
133 * @param point
134 */
135 public void addPoint(java.awt.geom.Point2D point) {
136 if (point instanceof Point2D)
137 this.points.add((Point2D) point);
138 else
139 this.points.add(new Point2D(point));
140 }
141
142 /**
143 * Add a series of points
144 *
145 * @param points an array of points
146 */
147 public void addPoints(java.awt.geom.Point2D[] points) {
148 for (java.awt.geom.Point2D element : points)
149 this.addPoint(element);
150 }
151
152 public void addPoints(Collection<? extends Point2D> points) {
153 this.points.addAll(points);
154 }
155
156 /**
157 * return an iterator on the internal point collection.
158 *
159 * @return the collection of points
160 */
161 public Collection<Point2D> getPoints() {
162 return Collections.unmodifiableList(points);
163 }
164
165 /**
166 * remove all points of the set.
167 */
168 public void clearPoints() {
169 this.points.clear();
170 }
171
172 /**
173 * Returns the number of points in the set.
174 *
175 * @return the number of points
176 */
177 public int getPointNumber() {
178 return points.size();
179 }
180
181
182 // ===================================================================
183 // Methods implementing CirculinearShape2D interface
184
185 /* (non-Javadoc)
186 * @see math.geom2d.circulinear.CirculinearShape2D#getBuffer(double)
187 */
188 public CirculinearDomain2D getBuffer(double dist) {
189 return CirculinearCurve2DUtils.computeBuffer(this, dist);
190 }
191
192 public PointArray2D transform(CircleInversion2D inv) {
193
194 PointArray2D array = new PointArray2D(points.size());
195
196 for(Point2D point : points)
197 array.addPoint(point.transform(inv));
198
199 return array;
200 }
201
202 /**
203 * Return distance to the closest point of the collection
204 */
205 public double getDistance(java.awt.geom.Point2D p) {
206 return getDistance(p.getX(), p.getY());
207 }
208
209 /*
210 * (non-Javadoc)
211 *
212 * @see math.geom2d.Shape2D#getDistance(double, double)
213 */
214 public double getDistance(double x, double y) {
215 if (points.isEmpty())
216 return Double.NaN;
217 double dist = Double.MAX_VALUE;
218 for (Point2D point : points)
219 dist = Math.min(dist, point.getDistance(x, y));
220 return dist;
221 }
222
223 /**
224 * always return true.
225 */
226 public boolean isBounded() {
227 return true;
228 }
229
230 public boolean isEmpty() {
231 return points.size()==0;
232 }
233
234 /*
235 * (non-Javadoc)
236 *
237 * @see math.geom2d.Shape2D#getClippedShape(java.awt.geom.Rectangle2D)
238 */
239 public PointArray2D clip(Box2D box) {
240 // allocate memory for result
241 PointArray2D res = new PointArray2D(points.size());
242
243 // select only points inside of box
244 for (Point2D point : points) {
245 if(box.contains(point)) {
246 res.addPoint(point);
247 }
248 }
249
250 // use array the right size
251 res.points.trimToSize();
252
253 // return result
254 return res;
255 }
256
257 public Box2D getBoundingBox() {
258 // init with max values in each direction
259 double xmin = Double.MAX_VALUE;
260 double ymin = Double.MAX_VALUE;
261 double xmax = Double.MIN_VALUE;
262 double ymax = Double.MIN_VALUE;
263
264 // update max values with each point
265 for (Point2D point : points) {
266 xmin = Math.min(xmin, point.getX());
267 ymin = Math.min(ymin, point.getY());
268 xmax = Math.max(xmax, point.getX());
269 ymax = Math.max(ymax, point.getY());
270 }
271
272 // create the bounding box
273 return new Box2D(xmin, xmax, ymin, ymax);
274 }
275
276 /*
277 * (non-Javadoc)
278 *
279 * @see math.geom2d.Shape2D#transform(math.geom2d.AffineTransform2D)
280 */
281 public PointArray2D transform(AffineTransform2D trans) {
282 PointArray2D res = new PointArray2D(points.size());
283
284 for (Point2D point : points)
285 res.addPoint(point.transform(trans));
286
287 return res;
288 }
289
290 /*
291 * (non-Javadoc)
292 *
293 * @see java.awt.Shape#contains(double, double)
294 */
295 public boolean contains(double x, double y) {
296 for (Point2D point : points)
297 if (point.getDistance(x, y)<Shape2D.ACCURACY)
298 return true;
299 return false;
300 }
301
302 /*
303 * (non-Javadoc)
304 *
305 * @see java.awt.Shape#contains(java.awt.geom.Point2D)
306 */
307 public boolean contains(java.awt.geom.Point2D point) {
308 return contains(point.getX(), point.getY());
309 }
310
311 /**
312 * Draws the point set on the specified Graphics2D, using default radius
313 * equal to 1.
314 *
315 * @param g2 the graphics to draw the point set
316 */
317 public void draw(Graphics2D g2) {
318 this.draw(g2, 1);
319 }
320
321 /**
322 * Draws the point set on the specified Graphics2D, by filling a disc with a
323 * given radius.
324 *
325 * @param g2 the graphics to draw the point set
326 */
327 public void draw(Graphics2D g2, double r) {
328 for (Point2D point : points)
329 g2.fill(new java.awt.geom.Ellipse2D.Double(point.x-r, point.y-r,
330 2*r, 2*r));
331 }
332
333 /*
334 * (non-Javadoc)
335 *
336 * @see java.lang.Iterable#iterator()
337 */
338 public Iterator<Point2D> iterator() {
339 return points.iterator();
340 }
341
342 @Override
343 public boolean equals(Object obj) {
344 if(!(obj instanceof PointSet2D))
345 return false;
346
347 PointSet2D set = (PointSet2D) obj;
348 for(Point2D point : this){
349 if(!set.contains(point))
350 return false;
351 }
352
353 for(Point2D point : set){
354 if(!this.contains(point))
355 return false;
356 }
357
358 return true;
359 }
360
361 @Override
362 public PointArray2D clone() {
363 PointArray2D set = new PointArray2D(this.getPointNumber());
364 for(Point2D point : this)
365 set.addPoint(point.clone());
366 return set;
367 }
368 }