View Javadoc

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 }