1 /* RectangularShape.java -- a rectangular frame for several generic shapes
2    Copyright (C) 2000, 2002 Free Software Foundation
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.awt.geom;
40 
41 import java.awt.Rectangle;
42 import java.awt.Shape;
43 
44 /**
45  * This class provides a generic framework, and several helper methods, for
46  * subclasses which represent geometric objects inside a rectangular frame.
47  * This does not specify any geometry except for the bounding box.
48  *
49  * @author Tom Tromey (tromey@cygnus.com)
50  * @author Eric Blake (ebb9@email.byu.edu)
51  * @since 1.2
52  * @see Arc2D
53  * @see Ellipse2D
54  * @see Rectangle2D
55  * @see RoundRectangle2D
56  * @status updated to 1.4
57  */
58 public abstract class RectangularShape implements Shape, Cloneable
59 {
60   /**
61    * Default constructor.
62    */
RectangularShape()63   protected RectangularShape()
64   {
65   }
66 
67   /**
68    * Get the x coordinate of the upper-left corner of the framing rectangle.
69    *
70    * @return the x coordinate
71    */
getX()72   public abstract double getX();
73 
74   /**
75    * Get the y coordinate of the upper-left corner of the framing rectangle.
76    *
77    * @return the y coordinate
78    */
getY()79   public abstract double getY();
80 
81   /**
82    * Get the width of the framing rectangle.
83    *
84    * @return the width
85    */
getWidth()86   public abstract double getWidth();
87 
88   /**
89    * Get the height of the framing rectangle.
90    *
91    * @return the height
92    */
getHeight()93   public abstract double getHeight();
94 
95   /**
96    * Get the minimum x coordinate in the frame. This is misnamed, or else
97    * Sun has a bug, because the implementation returns getX() even when
98    * getWidth() is negative.
99    *
100    * @return the minimum x coordinate
101    */
getMinX()102   public double getMinX()
103   {
104     return getX();
105   }
106 
107   /**
108    * Get the minimum y coordinate in the frame. This is misnamed, or else
109    * Sun has a bug, because the implementation returns getY() even when
110    * getHeight() is negative.
111    *
112    * @return the minimum y coordinate
113    */
getMinY()114   public double getMinY()
115   {
116     return getY();
117   }
118 
119   /**
120    * Get the maximum x coordinate in the frame. This is misnamed, or else
121    * Sun has a bug, because the implementation returns getX()+getWidth() even
122    * when getWidth() is negative.
123    *
124    * @return the maximum x coordinate
125    */
getMaxX()126   public double getMaxX()
127   {
128     return getX() + getWidth();
129   }
130 
131   /**
132    * Get the maximum y coordinate in the frame. This is misnamed, or else
133    * Sun has a bug, because the implementation returns getY()+getHeight() even
134    * when getHeight() is negative.
135    *
136    * @return the maximum y coordinate
137    */
getMaxY()138   public double getMaxY()
139   {
140     return getY() + getHeight();
141   }
142 
143   /**
144    * Return the x coordinate of the center point of the framing rectangle.
145    *
146    * @return the central x coordinate
147    */
getCenterX()148   public double getCenterX()
149   {
150     return getX() + getWidth() / 2;
151   }
152 
153   /**
154    * Return the y coordinate of the center point of the framing rectangle.
155    *
156    * @return the central y coordinate
157    */
getCenterY()158   public double getCenterY()
159   {
160     return getY() + getHeight() / 2;
161   }
162 
163   /**
164    * Return the frame around this object. Note that this may be a looser
165    * bounding box than getBounds2D.
166    *
167    * @return the frame, in double precision
168    * @see #setFrame(double, double, double, double)
169    */
getFrame()170   public Rectangle2D getFrame()
171   {
172     return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
173   }
174 
175   /**
176    * Test if the shape is empty, meaning that no points are inside it.
177    *
178    * @return true if the shape is empty
179    */
isEmpty()180   public abstract boolean isEmpty();
181 
182   /**
183    * Set the framing rectangle of this shape to the given coordinate and size.
184    *
185    * @param x the new x coordinate
186    * @param y the new y coordinate
187    * @param w the new width
188    * @param h the new height
189    * @see #getFrame()
190    */
setFrame(double x, double y, double w, double h)191   public abstract void setFrame(double x, double y, double w, double h);
192 
193   /**
194    * Set the framing rectangle of this shape to the given coordinate and size.
195    *
196    * @param p the new point
197    * @param d the new dimension
198    * @throws NullPointerException if p or d is null
199    * @see #getFrame()
200    */
setFrame(Point2D p, Dimension2D d)201   public void setFrame(Point2D p, Dimension2D d)
202   {
203     setFrame(p.getX(), p.getY(), d.getWidth(), d.getHeight());
204   }
205 
206   /**
207    * Set the framing rectangle of this shape to the given rectangle.
208    *
209    * @param r the new framing rectangle
210    * @throws NullPointerException if r is null
211    * @see #getFrame()
212    */
setFrame(Rectangle2D r)213   public void setFrame(Rectangle2D r)
214   {
215     setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
216   }
217 
218   /**
219    * Set the framing rectangle of this shape using two points on a diagonal.
220    * The area will be positive.
221    *
222    * @param x1 the first x coordinate
223    * @param y1 the first y coordinate
224    * @param x2 the second x coordinate
225    * @param y2 the second y coordinate
226    */
setFrameFromDiagonal(double x1, double y1, double x2, double y2)227   public void setFrameFromDiagonal(double x1, double y1, double x2, double y2)
228   {
229     if (x1 > x2)
230       {
231         double t = x2;
232         x2 = x1;
233         x1 = t;
234       }
235     if (y1 > y2)
236       {
237         double t = y2;
238         y2 = y1;
239         y1 = t;
240       }
241     setFrame(x1, y1, x2 - x1, y2 - y1);
242   }
243 
244   /**
245    * Set the framing rectangle of this shape using two points on a diagonal.
246    * The area will be positive.
247    *
248    * @param p1 the first point
249    * @param p2 the second point
250    * @throws NullPointerException if either point is null
251    */
setFrameFromDiagonal(Point2D p1, Point2D p2)252   public void setFrameFromDiagonal(Point2D p1, Point2D p2)
253   {
254     setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
255   }
256 
257   /**
258    * Set the framing rectangle of this shape using the center of the frame,
259    * and one of the four corners. The area will be positive.
260    *
261    * @param centerX the x coordinate at the center
262    * @param centerY the y coordinate at the center
263    * @param cornerX the x coordinate at a corner
264    * @param cornerY the y coordinate at a corner
265    */
setFrameFromCenter(double centerX, double centerY, double cornerX, double cornerY)266   public void setFrameFromCenter(double centerX, double centerY,
267                                  double cornerX, double cornerY)
268   {
269     double halfw = Math.abs(cornerX - centerX);
270     double halfh = Math.abs(cornerY - centerY);
271     setFrame(centerX - halfw, centerY - halfh, halfw + halfw, halfh + halfh);
272   }
273 
274   /**
275    * Set the framing rectangle of this shape using the center of the frame,
276    * and one of the four corners. The area will be positive.
277    *
278    * @param center the center point
279    * @param corner a corner point
280    * @throws NullPointerException if either point is null
281    */
setFrameFromCenter(Point2D center, Point2D corner)282   public void setFrameFromCenter(Point2D center, Point2D corner)
283   {
284     setFrameFromCenter(center.getX(), center.getY(),
285                        corner.getX(), corner.getY());
286   }
287 
288   /**
289    * Tests if a point is inside the boundary of the shape.
290    *
291    * @param p the point to test
292    * @return true if the point is inside the shape
293    * @throws NullPointerException if p is null
294    * @see #contains(double, double)
295    */
contains(Point2D p)296   public boolean contains(Point2D p)
297   {
298     return contains(p.getX(), p.getY());
299   }
300 
301   /**
302    * Tests if a rectangle and this shape share common internal points.
303    *
304    * @param r the rectangle to test
305    * @return true if the rectangle intersects this shpae
306    * @throws NullPointerException if r is null
307    * @see #intersects(double, double, double, double)
308    */
intersects(Rectangle2D r)309   public boolean intersects(Rectangle2D r)
310   {
311     return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
312   }
313 
314   /**
315    * Tests if the shape completely contains the given rectangle.
316    *
317    * @param r the rectangle to test
318    * @return true if r is contained in this shape
319    * @throws NullPointerException if r is null
320    * @see #contains(double, double, double, double)
321    */
contains(Rectangle2D r)322   public boolean contains(Rectangle2D r)
323   {
324     return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
325   }
326 
327   /**
328    * Returns a bounding box for this shape, in integer format. Notice that you
329    * may get a tighter bound with getBounds2D.
330    *
331    * @return a bounding box
332    */
getBounds()333   public Rectangle getBounds()
334   {
335     double x = getX();
336     double y = getY();
337     double maxx = Math.ceil(x + getWidth());
338     double maxy = Math.ceil(y + getHeight());
339     x = Math.floor(x);
340     y = Math.floor(y);
341     return new Rectangle((int) x, (int) y, (int) (maxx - x), (int) (maxy - y));
342   }
343 
344   /**
345    * Return an iterator along the shape boundary. If the optional transform
346    * is provided, the iterator is transformed accordingly. The path is
347    * flattened until all segments differ from the curve by at most the value
348    * of the flatness parameter, within the limits of the default interpolation
349    * recursion limit of 1024 segments between actual points. Each call
350    * returns a new object, independent from others in use. The result is
351    * threadsafe if and only if the iterator returned by
352    * {@link #getPathIterator(AffineTransform)} is as well.
353    *
354    * @param at an optional transform to apply to the iterator
355    * @param flatness the desired flatness
356    * @return a new iterator over the boundary
357    * @throws IllegalArgumentException if flatness is invalid
358    * @since 1.2
359    */
getPathIterator(AffineTransform at, double flatness)360   public PathIterator getPathIterator(AffineTransform at, double flatness)
361   {
362     return new FlatteningPathIterator(getPathIterator(at), flatness);
363   }
364 
365   /**
366    * Create a new shape of the same run-time type with the same contents as
367    * this one.
368    *
369    * @return the clone
370    */
clone()371   public Object clone()
372   {
373     try
374       {
375         return super.clone();
376       }
377     catch (CloneNotSupportedException e)
378       {
379         throw (Error) new InternalError().initCause(e); // Impossible
380       }
381   }
382 } // class RectangularShape
383