1 /*
2 * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.awt.geom;
27
28 import java.awt.Shape;
29 import java.awt.Rectangle;
30 import java.beans.Transient;
31
32 /**
33 * <code>RectangularShape</code> is the base class for a number of
34 * {@link Shape} objects whose geometry is defined by a rectangular frame.
35 * This class does not directly specify any specific geometry by
36 * itself, but merely provides manipulation methods inherited by
37 * a whole category of <code>Shape</code> objects.
38 * The manipulation methods provided by this class can be used to
39 * query and modify the rectangular frame, which provides a reference
40 * for the subclasses to define their geometry.
41 *
42 * @author Jim Graham
43 * @since 1.2
44 */
45 public abstract class RectangularShape implements Shape, Cloneable {
46
47 /**
48 * This is an abstract class that cannot be instantiated directly.
49 *
50 * @see Arc2D
51 * @see Ellipse2D
52 * @see Rectangle2D
53 * @see RoundRectangle2D
54 * @since 1.2
55 */
56 protected RectangularShape() {
57 }
58
59 /**
60 * Returns the X coordinate of the upper-left corner of
61 * the framing rectangle in <code>double</code> precision.
62 * @return the X coordinate of the upper-left corner of
63 * the framing rectangle.
64 * @since 1.2
65 */
66 public abstract double getX();
67
68 /**
69 * Returns the Y coordinate of the upper-left corner of
70 * the framing rectangle in <code>double</code> precision.
71 * @return the Y coordinate of the upper-left corner of
72 * the framing rectangle.
73 * @since 1.2
74 */
75 public abstract double getY();
76
77 /**
78 * Returns the width of the framing rectangle in
79 * <code>double</code> precision.
80 * @return the width of the framing rectangle.
81 * @since 1.2
82 */
83 public abstract double getWidth();
84
85 /**
86 * Returns the height of the framing rectangle
87 * in <code>double</code> precision.
88 * @return the height of the framing rectangle.
89 * @since 1.2
90 */
91 public abstract double getHeight();
92
93 /**
94 * Returns the smallest X coordinate of the framing
95 * rectangle of the <code>Shape</code> in <code>double</code>
96 * precision.
97 * @return the smallest X coordinate of the framing
98 * rectangle of the <code>Shape</code>.
99 * @since 1.2
100 */
101 public double getMinX() {
102 return getX();
103 }
104
105 /**
106 * Returns the smallest Y coordinate of the framing
107 * rectangle of the <code>Shape</code> in <code>double</code>
108 * precision.
109 * @return the smallest Y coordinate of the framing
110 * rectangle of the <code>Shape</code>.
111 * @since 1.2
112 */
113 public double getMinY() {
114 return getY();
115 }
116
117 /**
118 * Returns the largest X coordinate of the framing
119 * rectangle of the <code>Shape</code> in <code>double</code>
120 * precision.
121 * @return the largest X coordinate of the framing
122 * rectangle of the <code>Shape</code>.
123 * @since 1.2
124 */
125 public double getMaxX() {
126 return getX() + getWidth();
127 }
128
129 /**
130 * Returns the largest Y coordinate of the framing
131 * rectangle of the <code>Shape</code> in <code>double</code>
132 * precision.
133 * @return the largest Y coordinate of the framing
134 * rectangle of the <code>Shape</code>.
135 * @since 1.2
136 */
137 public double getMaxY() {
138 return getY() + getHeight();
139 }
140
141 /**
142 * Returns the X coordinate of the center of the framing
143 * rectangle of the <code>Shape</code> in <code>double</code>
144 * precision.
145 * @return the X coordinate of the center of the framing rectangle
146 * of the <code>Shape</code>.
147 * @since 1.2
148 */
149 public double getCenterX() {
150 return getX() + getWidth() / 2.0;
151 }
152
153 /**
154 * Returns the Y coordinate of the center of the framing
155 * rectangle of the <code>Shape</code> in <code>double</code>
156 * precision.
157 * @return the Y coordinate of the center of the framing rectangle
158 * of the <code>Shape</code>.
159 * @since 1.2
160 */
161 public double getCenterY() {
162 return getY() + getHeight() / 2.0;
163 }
164
165 /**
166 * Returns the framing {@link Rectangle2D}
167 * that defines the overall shape of this object.
168 * @return a <code>Rectangle2D</code>, specified in
169 * <code>double</code> coordinates.
170 * @see #setFrame(double, double, double, double)
171 * @see #setFrame(Point2D, Dimension2D)
172 * @see #setFrame(Rectangle2D)
173 * @since 1.2
174 */
175 @Transient
176 public Rectangle2D getFrame() {
177 return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
178 }
179
180 /**
181 * Determines whether the <code>RectangularShape</code> is empty.
182 * When the <code>RectangularShape</code> is empty, it encloses no
183 * area.
184 * @return <code>true</code> if the <code>RectangularShape</code> is empty;
185 * <code>false</code> otherwise.
186 * @since 1.2
187 */
188 public abstract boolean isEmpty();
189
190 /**
191 * Sets the location and size of the framing rectangle of this
192 * <code>Shape</code> to the specified rectangular values.
193 *
194 * @param x the X coordinate of the upper-left corner of the
195 * specified rectangular shape
196 * @param y the Y coordinate of the upper-left corner of the
197 * specified rectangular shape
198 * @param w the width of the specified rectangular shape
199 * @param h the height of the specified rectangular shape
200 * @see #getFrame
201 * @since 1.2
202 */
203 public abstract void setFrame(double x, double y, double w, double h);
204
205 /**
206 * Sets the location and size of the framing rectangle of this
207 * <code>Shape</code> to the specified {@link Point2D} and
208 * {@link Dimension2D}, respectively. The framing rectangle is used
209 * by the subclasses of <code>RectangularShape</code> to define
210 * their geometry.
211 * @param loc the specified <code>Point2D</code>
212 * @param size the specified <code>Dimension2D</code>
213 * @see #getFrame
214 * @since 1.2
215 */
216 public void setFrame(Point2D loc, Dimension2D size) {
217 setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
218 }
219
220 /**
221 * Sets the framing rectangle of this <code>Shape</code> to
222 * be the specified <code>Rectangle2D</code>. The framing rectangle is
223 * used by the subclasses of <code>RectangularShape</code> to define
224 * their geometry.
225 * @param r the specified <code>Rectangle2D</code>
226 * @see #getFrame
227 * @since 1.2
228 */
229 public void setFrame(Rectangle2D r) {
230 setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
231 }
232
233 /**
234 * Sets the diagonal of the framing rectangle of this <code>Shape</code>
235 * based on the two specified coordinates. The framing rectangle is
236 * used by the subclasses of <code>RectangularShape</code> to define
237 * their geometry.
238 *
239 * @param x1 the X coordinate of the start point of the specified diagonal
240 * @param y1 the Y coordinate of the start point of the specified diagonal
241 * @param x2 the X coordinate of the end point of the specified diagonal
242 * @param y2 the Y coordinate of the end point of the specified diagonal
243 * @since 1.2
244 */
245 public void setFrameFromDiagonal(double x1, double y1,
246 double x2, double y2) {
247 if (x2 < x1) {
248 double t = x1;
249 x1 = x2;
250 x2 = t;
251 }
252 if (y2 < y1) {
253 double t = y1;
254 y1 = y2;
255 y2 = t;
256 }
257 setFrame(x1, y1, x2 - x1, y2 - y1);
258 }
259
260 /**
261 * Sets the diagonal of the framing rectangle of this <code>Shape</code>
262 * based on two specified <code>Point2D</code> objects. The framing
263 * rectangle is used by the subclasses of <code>RectangularShape</code>
264 * to define their geometry.
265 *
266 * @param p1 the start <code>Point2D</code> of the specified diagonal
267 * @param p2 the end <code>Point2D</code> of the specified diagonal
268 * @since 1.2
269 */
270 public void setFrameFromDiagonal(Point2D p1, Point2D p2) {
271 setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
272 }
273
274 /**
275 * Sets the framing rectangle of this <code>Shape</code>
276 * based on the specified center point coordinates and corner point
277 * coordinates. The framing rectangle is used by the subclasses of
278 * <code>RectangularShape</code> to define their geometry.
279 *
280 * @param centerX the X coordinate of the specified center point
281 * @param centerY the Y coordinate of the specified center point
282 * @param cornerX the X coordinate of the specified corner point
283 * @param cornerY the Y coordinate of the specified corner point
284 * @since 1.2
285 */
286 public void setFrameFromCenter(double centerX, double centerY,
287 double cornerX, double cornerY) {
288 double halfW = Math.abs(cornerX - centerX);
289 double halfH = Math.abs(cornerY - centerY);
290 setFrame(centerX - halfW, centerY - halfH, halfW * 2.0, halfH * 2.0);
291 }
292
293 /**
294 * Sets the framing rectangle of this <code>Shape</code> based on a
295 * specified center <code>Point2D</code> and corner
296 * <code>Point2D</code>. The framing rectangle is used by the subclasses
297 * of <code>RectangularShape</code> to define their geometry.
298 * @param center the specified center <code>Point2D</code>
299 * @param corner the specified corner <code>Point2D</code>
300 * @since 1.2
301 */
302 public void setFrameFromCenter(Point2D center, Point2D corner) {
303 setFrameFromCenter(center.getX(), center.getY(),
304 corner.getX(), corner.getY());
305 }
306
307 /**
308 * {@inheritDoc}
309 * @since 1.2
310 */
311 public boolean contains(Point2D p) {
312 return contains(p.getX(), p.getY());
313 }
314
315 /**
316 * {@inheritDoc}
317 * @since 1.2
318 */
319 public boolean intersects(Rectangle2D r) {
320 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
321 }
322
323 /**
324 * {@inheritDoc}
325 * @since 1.2
326 */
327 public boolean contains(Rectangle2D r) {
328 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
329 }
330
331 /**
332 * {@inheritDoc}
333 * @since 1.2
334 */
335 public Rectangle getBounds() {
336 double width = getWidth();
337 double height = getHeight();
338 if (width < 0 || height < 0) {
339 return new Rectangle();
340 }
341 double x = getX();
342 double y = getY();
343 double x1 = Math.floor(x);
344 double y1 = Math.floor(y);
345 double x2 = Math.ceil(x + width);
346 double y2 = Math.ceil(y + height);
347 return new Rectangle((int) x1, (int) y1,
348 (int) (x2 - x1), (int) (y2 - y1));
349 }
350
351 /**
352 * Returns an iterator object that iterates along the
353 * <code>Shape</code> object's boundary and provides access to a
354 * flattened view of the outline of the <code>Shape</code>
355 * object's geometry.
356 * <p>
357 * Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point types will
358 * be returned by the iterator.
359 * <p>
360 * The amount of subdivision of the curved segments is controlled
361 * by the <code>flatness</code> parameter, which specifies the
362 * maximum distance that any point on the unflattened transformed
363 * curve can deviate from the returned flattened path segments.
364 * An optional {@link AffineTransform} can
365 * be specified so that the coordinates returned in the iteration are
366 * transformed accordingly.
367 * @param at an optional <code>AffineTransform</code> to be applied to the
368 * coordinates as they are returned in the iteration,
369 * or <code>null</code> if untransformed coordinates are desired.
370 * @param flatness the maximum distance that the line segments used to
371 * approximate the curved segments are allowed to deviate
372 * from any point on the original curve
373 * @return a <code>PathIterator</code> object that provides access to
374 * the <code>Shape</code> object's flattened geometry.
375 * @since 1.2
376 */
377 public PathIterator getPathIterator(AffineTransform at, double flatness) {
378 return new FlatteningPathIterator(getPathIterator(at), flatness);
379 }
380
381 /**
382 * Creates a new object of the same class and with the same
383 * contents as this object.
384 * @return a clone of this instance.
385 * @exception OutOfMemoryError if there is not enough memory.
386 * @see java.lang.Cloneable
387 * @since 1.2
388 */
389 public Object clone() {
390 try {
391 return super.clone();
392 } catch (CloneNotSupportedException e) {
393 // this shouldn't happen, since we are Cloneable
394 throw new InternalError();
395 }
396 }
397 }