View Javadoc

1   /* File HRectangle2D.java 
2    *
3    * Project : Java Geometry Library
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  
24  // package
25  
26  package math.geom2d.polygon;
27  
28  import java.awt.Graphics2D;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Iterator;
32  
33  import math.geom2d.AffineTransform2D;
34  import math.geom2d.Box2D;
35  import math.geom2d.Point2D;
36  import math.geom2d.circulinear.CirculinearBoundarySet2D;
37  import math.geom2d.circulinear.CirculinearCurve2DUtils;
38  import math.geom2d.circulinear.CirculinearDomain2D;
39  import math.geom2d.circulinear.GenericCirculinearDomain2D;
40  import math.geom2d.domain.Domain2D;
41  import math.geom2d.line.LineSegment2D;
42  import math.geom2d.transform.CircleInversion2D;
43  
44  // Imports
45  
46  /**
47   * HRectangle2D defines a rectangle with edges parallel to main axis. Thus, it
48   * can not be rotated, contrary to Rectangle2D. This class is actually simply a
49   * wrapper of class <code>java.awt.geom.Rectangle2D.Double</code> with
50   * interface <code>AbstractPolygon</code>.
51   */
52  public class HRectangle2D extends java.awt.geom.Rectangle2D.Double implements
53          Polygon2D {
54  
55      // ===================================================================
56      // constants
57  
58      private static final long serialVersionUID = 1L;
59  
60      // ===================================================================
61      // class variables
62  
63      // ===================================================================
64      // constructors
65  
66      /** Main constructor */
67      public HRectangle2D(double x0, double y0, double w, double h) {
68          super(x0, y0, w, h);
69      }
70  
71      /** Empty constructor (size and position zero) */
72      public HRectangle2D() {
73          super(0, 0, 0, 0);
74      }
75  
76      /** Constructor from awt, to allow easy construction from existing apps. */
77      public HRectangle2D(java.awt.geom.Rectangle2D rect) {
78          super(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
79      }
80  
81      /** Main constructor */
82      public HRectangle2D(Point2D point, double w, double h) {
83          super(point.getX(), point.getY(), w, h);
84      }
85  
86      // ===================================================================
87      // query states
88  
89      /** Always returns true, because a rectangle is always bounded. */
90      public boolean isBounded() {
91          return true;
92      }
93  
94      // ===================================================================
95      // methods inherited from interface Polygon2D
96  
97  
98      public Collection<Point2D> getVertices() {
99          ArrayList<Point2D> points = new ArrayList<Point2D>(4);
100         points.add(new Point2D(x, y));
101         points.add(new Point2D(x+width, y));
102         points.add(new Point2D(x+width, y+height));
103         points.add(new Point2D(x, y+height));
104         return points;
105     }
106 
107     /**
108      * Returns the i-th vertex of the polygon.
109      * 
110      * @param i index of the vertex, between 0 and 3
111      */
112     public Point2D getVertex(int i) {
113         switch (i) {
114         case 0:
115             return new Point2D(x, y);
116         case 1:
117             return new Point2D(x+width, y);
118         case 2:
119             return new Point2D(x+width, y+height);
120         case 3:
121             return new Point2D(x, y+height);
122         default:
123             throw new IndexOutOfBoundsException();
124         }
125     }
126 
127     /**
128      * Returns the number of vertex, which is 4.
129      * 
130      * @since 0.6.3
131      */
132     public int getVertexNumber() {
133         return 4;
134     }
135 
136     public Collection<LineSegment2D> getEdges() {
137         ArrayList<LineSegment2D> edges = new ArrayList<LineSegment2D>(4);
138         edges.add(new LineSegment2D(x, y, x+width, y));
139         edges.add(new LineSegment2D(x+width, y, x+width, y+height));
140         edges.add(new LineSegment2D(x+width, y+height, x, y+height));
141         edges.add(new LineSegment2D(x, y+height, x, y));
142         return edges;
143     }
144 
145     public int getEdgeNumber() {
146         return 4;
147     }
148 
149     /* (non-Javadoc)
150      * @see math.geom2d.polygon.Polygon2D#getRings()
151      */
152     public Collection<LinearRing2D> getRings() {
153         ArrayList<LinearRing2D> rings = new ArrayList<LinearRing2D>(1);
154         rings.add(new LinearRing2D(this.getVertices()));
155         return rings;
156     }
157 
158 	
159 	// ===================================================================
160     // methods inherited from Domain2D interface
161 
162 	/* (non-Javadoc)
163 	 * @see math.geom2d.circulinear.CirculinearDomain2D#transform(math.geom2d.transform.CircleInversion2D)
164 	 */
165 	public CirculinearDomain2D transform(CircleInversion2D inv) {
166 		return new GenericCirculinearDomain2D(
167 				this.getBoundary().transform(inv));
168 	}
169 
170 	/* (non-Javadoc)
171 	 * @see math.geom2d.circulinear.CirculinearShape2D#getBuffer(double)
172 	 */
173 	public CirculinearDomain2D getBuffer(double dist) {
174 		return CirculinearCurve2DUtils.computeBuffer(
175 				this.getBoundary(), dist);
176 	}
177 
178     // ===================================================================
179     // methods inherited from interface Domain2D
180 
181     public CirculinearBoundarySet2D<LinearRing2D> getBoundary() {
182         Point2D pts[] = new Point2D[4];
183         pts[0] = new Point2D(x, y);
184         pts[1] = new Point2D(width+x, y);
185         pts[2] = new Point2D(width+x, y+height);
186         pts[3] = new Point2D(x, y+height);
187         return new CirculinearBoundarySet2D<LinearRing2D>(
188         		new LinearRing2D(pts));
189     }
190 
191     public Polygon2D complement() {
192         Point2D pts[] = new Point2D[4];
193         pts[0] = new Point2D(x, y);
194         pts[1] = new Point2D(x, y+height);
195         pts[2] = new Point2D(width+x, y+height);
196         pts[3] = new Point2D(width+x, y);
197         return new SimplePolygon2D(pts);
198     }
199 
200     public double getDistance(java.awt.geom.Point2D p) {
201         return Math.max(getSignedDistance(p.getX(), p.getY()), 0);
202     }
203 
204     public double getDistance(double x, double y) {
205         return Math.max(getSignedDistance(x, y), 0);
206     }
207 
208     /**
209      * Get the signed distance of the shape to the given point : this distance
210      * is positive if the point lies outside the shape, and is negative if the
211      * point lies inside the shape. In this case, absolute value of distance is
212      * equals to the distance to the border of the shape.
213      */
214     public double getSignedDistance(java.awt.geom.Point2D p) {
215         return getSignedDistance(p.getX(), p.getY());
216     }
217 
218     /**
219      * Get the signed distance of the shape to the given point : this distance
220      * is positive if the point lies outside the shape, and is negative if the
221      * point lies inside the shape. In this case, absolute value of distance is
222      * equals to the distance to the border of the shape.
223      */
224     public double getSignedDistance(double x, double y) {
225         double dist = getBoundary().getDistance(x, y);
226         if (contains(x, y))
227             return -dist;
228         else
229             return dist;
230     }
231 
232     /**
233      * Returns the clipping of the rectangle, as an instance of HRectangle2D. If
234      * rectangle is outside clipping box, returns an instance of HRectangle with
235      * 0 width and height.
236      */
237     public Domain2D clip(Box2D box) {
238         double xmin = Math.max(this.getMinX(), box.getMinX());
239         double xmax = Math.min(this.getMaxX(), box.getMaxX());
240         double ymin = Math.max(this.getMinY(), box.getMinY());
241         double ymax = Math.min(this.getMaxY(), box.getMaxY());
242         if (xmin>xmax||ymin>ymax)
243             return new HRectangle2D(xmin, ymin, 0, 0);
244         else
245             return new HRectangle2D(xmin, xmax, xmax-xmin, ymax-ymin);
246     }
247 
248     public void draw(Graphics2D g2) {
249         g2.draw(this.getBoundary().getGeneralPath());
250     }
251 
252     public void fill(Graphics2D g2) {
253         g2.fill(this.getBoundary().getGeneralPath());
254     }
255 
256     public Box2D getBoundingBox() {
257         return new Box2D(this.getMinX(), this.getMaxX(), this.getMinY(), this
258                 .getMaxY());
259     }
260 
261     // ===================================================================
262     // mutators
263 
264     // ===================================================================
265     // general methods
266 
267     /**
268      * Test if rectangles are the same. We consider two rectangles are equal if
269      * their corners are the same. Then, we can have different origins and
270      * different angles, but equal rectangles.
271      */
272     @Override
273     public boolean equals(Object obj) {
274 
275         // check class, and cast type
276         if (!(obj instanceof HRectangle2D))
277             return false;
278         HRectangle2D rect = (HRectangle2D) obj;
279 
280         // check all 4 corners of the first rectangle
281         boolean ok;
282         for (Point2D point : this.getVertices()) {
283             ok = false;
284 
285             // compare with all 4 corners of second rectangle
286             for (Point2D point2 : rect.getVertices())
287                 if (point.equals(point2))
288                     ok = true;
289 
290             // if the point does not belong to the corners of the other
291             // rectangle,
292             // then the two rectangles are different
293             if (!ok)
294                 return false;
295         }
296 
297         // test ok for 4 corners, then the two rectangles are the same.
298         return true;
299     }
300 
301     // ===================================================================
302     // general methods
303 
304     /**
305      * Return the new Polygon created by an affine transform of this polygon.
306      */
307     public SimplePolygon2D transform(AffineTransform2D trans) {
308         int nPoints = 4;
309         Point2D[] array = new Point2D[nPoints];
310         Point2D[] res = new Point2D[nPoints];
311         Iterator<Point2D> iter = this.getVertices().iterator();
312         for (int i = 0; i<nPoints; i++) {
313             array[i] = iter.next();
314             res[i] = new Point2D();
315         }
316 
317         trans.transform(array, res);
318         return new SimplePolygon2D(res);
319     }
320 
321 }