001 /* RectangularShape.java -- a rectangular frame for several generic shapes
002 Copyright (C) 2000, 2002 Free Software Foundation
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package java.awt.geom;
040
041 import java.awt.Rectangle;
042 import java.awt.Shape;
043
044 /**
045 * This class provides a generic framework, and several helper methods, for
046 * subclasses which represent geometric objects inside a rectangular frame.
047 * This does not specify any geometry except for the bounding box.
048 *
049 * @author Tom Tromey (tromey@cygnus.com)
050 * @author Eric Blake (ebb9@email.byu.edu)
051 * @since 1.2
052 * @see Arc2D
053 * @see Ellipse2D
054 * @see Rectangle2D
055 * @see RoundRectangle2D
056 * @status updated to 1.4
057 */
058 public abstract class RectangularShape implements Shape, Cloneable
059 {
060 /**
061 * Default constructor.
062 */
063 protected RectangularShape()
064 {
065 }
066
067 /**
068 * Get the x coordinate of the upper-left corner of the framing rectangle.
069 *
070 * @return the x coordinate
071 */
072 public abstract double getX();
073
074 /**
075 * Get the y coordinate of the upper-left corner of the framing rectangle.
076 *
077 * @return the y coordinate
078 */
079 public abstract double getY();
080
081 /**
082 * Get the width of the framing rectangle.
083 *
084 * @return the width
085 */
086 public abstract double getWidth();
087
088 /**
089 * Get the height of the framing rectangle.
090 *
091 * @return the height
092 */
093 public abstract double getHeight();
094
095 /**
096 * Get the minimum x coordinate in the frame. This is misnamed, or else
097 * Sun has a bug, because the implementation returns getX() even when
098 * getWidth() is negative.
099 *
100 * @return the minimum x coordinate
101 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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