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., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 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. If the frame is empty, the 330 * box is the default empty box at the origin. 331 * 332 * @return a bounding box 333 */ getBounds()334 public Rectangle getBounds() 335 { 336 if (isEmpty()) 337 return new Rectangle(); 338 double x = getX(); 339 double y = getY(); 340 double maxx = Math.ceil(x + getWidth()); 341 double maxy = Math.ceil(y + getHeight()); 342 x = Math.floor(x); 343 y = Math.floor(y); 344 return new Rectangle((int) x, (int) y, (int) (maxx - x), (int) (maxy - y)); 345 } 346 347 /** 348 * Return an iterator along the shape boundary. If the optional transform 349 * is provided, the iterator is transformed accordingly. The path is 350 * flattened until all segments differ from the curve by at most the value 351 * of the flatness parameter, within the limits of the default interpolation 352 * recursion limit of 1024 segments between actual points. Each call 353 * returns a new object, independent from others in use. The result is 354 * threadsafe if and only if the iterator returned by 355 * {@link #getPathIterator(AffineTransform)} is as well. 356 * 357 * @param transform an optional transform to apply to the iterator 358 * @param flatness the desired flatness 359 * @return a new iterator over the boundary 360 * @throws IllegalArgumentException if flatness is invalid 361 * @since 1.2 362 */ getPathIterator(AffineTransform at, double flatness)363 public PathIterator getPathIterator(AffineTransform at, double flatness) 364 { 365 return new FlatteningPathIterator(getPathIterator(at), flatness); 366 } 367 368 /** 369 * Create a new shape of the same run-time type with the same contents as 370 * this one. 371 * 372 * @return the clone 373 */ clone()374 public Object clone() 375 { 376 try 377 { 378 return super.clone(); 379 } 380 catch (CloneNotSupportedException e) 381 { 382 throw (Error) new InternalError().initCause(e); // Impossible 383 } 384 } 385 } // class RectangularShape 386