| GNU Classpath (0.95) | |
| Frames | No Frames |
1: /* Arc2D.java -- represents an arc in 2-D space 2: Copyright (C) 2002, 2003, 2004 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: package java.awt.geom; 39: 40: import java.util.NoSuchElementException; 41: 42: 43: /** 44: * This class represents all arcs (segments of an ellipse in 2-D space). The 45: * arcs are defined by starting angle and extent (arc length) in degrees, as 46: * opposed to radians (like the rest of Java), and can be open, chorded, or 47: * wedge shaped. The angles are skewed according to the ellipse, so that 45 48: * degrees always points to the upper right corner (positive x, negative y) 49: * of the bounding rectangle. A positive extent draws a counterclockwise arc, 50: * and while the angle can be any value, the path iterator only traverses the 51: * first 360 degrees. Storage is up to the subclasses. 52: * 53: * @author Eric Blake (ebb9@email.byu.edu) 54: * @author Sven de Marothy (sven@physto.se) 55: * @since 1.2 56: */ 57: public abstract class Arc2D extends RectangularShape 58: { 59: /** 60: * An open arc, with no segment connecting the endpoints. This type of 61: * arc still contains the same points as a chorded version. 62: */ 63: public static final int OPEN = 0; 64: 65: /** 66: * A closed arc with a single segment connecting the endpoints (a chord). 67: */ 68: public static final int CHORD = 1; 69: 70: /** 71: * A closed arc with two segments, one from each endpoint, meeting at the 72: * center of the ellipse. 73: */ 74: public static final int PIE = 2; 75: 76: /** The closure type of this arc. This is package-private to avoid an 77: * accessor method. */ 78: int type; 79: 80: /** 81: * Create a new arc, with the specified closure type. 82: * 83: * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}. 84: * @throws IllegalArgumentException if type is invalid 85: */ 86: protected Arc2D(int type) 87: { 88: if (type < OPEN || type > PIE) 89: throw new IllegalArgumentException(); 90: this.type = type; 91: } 92: 93: /** 94: * Get the starting angle of the arc in degrees. 95: * 96: * @return the starting angle 97: * @see #setAngleStart(double) 98: */ 99: public abstract double getAngleStart(); 100: 101: /** 102: * Get the extent angle of the arc in degrees. 103: * 104: * @return the extent angle 105: * @see #setAngleExtent(double) 106: */ 107: public abstract double getAngleExtent(); 108: 109: /** 110: * Return the closure type of the arc. 111: * 112: * @return the closure type 113: * @see #OPEN 114: * @see #CHORD 115: * @see #PIE 116: * @see #setArcType(int) 117: */ 118: public int getArcType() 119: { 120: return type; 121: } 122: 123: /** 124: * Returns the starting point of the arc. 125: * 126: * @return the start point 127: */ 128: public Point2D getStartPoint() 129: { 130: double angle = Math.toRadians(getAngleStart()); 131: double rx = getWidth() / 2; 132: double ry = getHeight() / 2; 133: double x = getX() + rx + rx * Math.cos(angle); 134: double y = getY() + ry - ry * Math.sin(angle); 135: return new Point2D.Double(x, y); 136: } 137: 138: /** 139: * Returns the ending point of the arc. 140: * 141: * @return the end point 142: */ 143: public Point2D getEndPoint() 144: { 145: double angle = Math.toRadians(getAngleStart() + getAngleExtent()); 146: double rx = getWidth() / 2; 147: double ry = getHeight() / 2; 148: double x = getX() + rx + rx * Math.cos(angle); 149: double y = getY() + ry - ry * Math.sin(angle); 150: return new Point2D.Double(x, y); 151: } 152: 153: /** 154: * Set the parameters of the arc. The angles are in degrees, and a positive 155: * extent sweeps counterclockwise (from the positive x-axis to the negative 156: * y-axis). 157: * 158: * @param x the new x coordinate of the upper left of the bounding box 159: * @param y the new y coordinate of the upper left of the bounding box 160: * @param w the new width of the bounding box 161: * @param h the new height of the bounding box 162: * @param start the start angle, in degrees 163: * @param extent the arc extent, in degrees 164: * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} 165: * @throws IllegalArgumentException if type is invalid 166: */ 167: public abstract void setArc(double x, double y, double w, double h, 168: double start, double extent, int type); 169: 170: /** 171: * Set the parameters of the arc. The angles are in degrees, and a positive 172: * extent sweeps counterclockwise (from the positive x-axis to the negative 173: * y-axis). 174: * 175: * @param p the upper left point of the bounding box 176: * @param d the dimensions of the bounding box 177: * @param start the start angle, in degrees 178: * @param extent the arc extent, in degrees 179: * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} 180: * @throws IllegalArgumentException if type is invalid 181: * @throws NullPointerException if p or d is null 182: */ 183: public void setArc(Point2D p, Dimension2D d, double start, double extent, 184: int type) 185: { 186: setArc(p.getX(), p.getY(), d.getWidth(), d.getHeight(), start, extent, type); 187: } 188: 189: /** 190: * Set the parameters of the arc. The angles are in degrees, and a positive 191: * extent sweeps counterclockwise (from the positive x-axis to the negative 192: * y-axis). 193: * 194: * @param r the new bounding box 195: * @param start the start angle, in degrees 196: * @param extent the arc extent, in degrees 197: * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} 198: * @throws IllegalArgumentException if type is invalid 199: * @throws NullPointerException if r is null 200: */ 201: public void setArc(Rectangle2D r, double start, double extent, int type) 202: { 203: setArc(r.getX(), r.getY(), r.getWidth(), r.getHeight(), start, extent, type); 204: } 205: 206: /** 207: * Set the parameters of the arc from the given one. 208: * 209: * @param a the arc to copy 210: * @throws NullPointerException if a is null 211: */ 212: public void setArc(Arc2D a) 213: { 214: setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(), a.getAngleStart(), 215: a.getAngleExtent(), a.getArcType()); 216: } 217: 218: /** 219: * Set the parameters of the arc. The angles are in degrees, and a positive 220: * extent sweeps counterclockwise (from the positive x-axis to the negative 221: * y-axis). This controls the center point and radius, so the arc will be 222: * circular. 223: * 224: * @param x the x coordinate of the center of the circle 225: * @param y the y coordinate of the center of the circle 226: * @param r the radius of the circle 227: * @param start the start angle, in degrees 228: * @param extent the arc extent, in degrees 229: * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} 230: * @throws IllegalArgumentException if type is invalid 231: */ 232: public void setArcByCenter(double x, double y, double r, double start, 233: double extent, int type) 234: { 235: setArc(x - r, y - r, r + r, r + r, start, extent, type); 236: } 237: 238: /** 239: * Sets the parameters of the arc by finding the tangents of two lines, and 240: * using the specified radius. The arc will be circular, will begin on the 241: * tangent point of the line extending from p1 to p2, and will end on the 242: * tangent point of the line extending from p2 to p3. 243: * 244: * XXX What happens if the points are colinear, or the radius negative? 245: * 246: * @param p1 the first point 247: * @param p2 the tangent line intersection point 248: * @param p3 the third point 249: * @param r the radius of the arc 250: * @throws NullPointerException if any point is null 251: */ 252: public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double r) 253: { 254: if ((p2.getX() - p1.getX()) * (p3.getY() - p1.getY()) 255: - (p3.getX() - p1.getX()) * (p2.getY() - p1.getY()) > 0) 256: { 257: Point2D p = p3; 258: p3 = p1; 259: p1 = p; 260: } 261: 262: // normalized tangent vectors 263: double dx1 = (p1.getX() - p2.getX()) / p1.distance(p2); 264: double dy1 = (p1.getY() - p2.getY()) / p1.distance(p2); 265: double dx2 = (p2.getX() - p3.getX()) / p3.distance(p2); 266: double dy2 = (p2.getY() - p3.getY()) / p3.distance(p2); 267: double theta1 = Math.atan2(dx1, dy1); 268: double theta2 = Math.atan2(dx2, dy2); 269: 270: double dx = r * Math.cos(theta2) - r * Math.cos(theta1); 271: double dy = -r * Math.sin(theta2) + r * Math.sin(theta1); 272: 273: if (theta1 < 0) 274: theta1 += 2 * Math.PI; 275: if (theta2 < 0) 276: theta2 += 2 * Math.PI; 277: if (theta2 < theta1) 278: theta2 += 2 * Math.PI; 279: 280: // Vectors of the lines, not normalized, note we change 281: // the direction of line 2. 282: dx1 = p1.getX() - p2.getX(); 283: dy1 = p1.getY() - p2.getY(); 284: dx2 = p3.getX() - p2.getX(); 285: dy2 = p3.getY() - p2.getY(); 286: 287: // Calculate the tangent point to the second line 288: double t2 = -(dx1 * dy - dy1 * dx) / (dx2 * dy1 - dx1 * dy2); 289: double x2 = t2 * (p3.getX() - p2.getX()) + p2.getX(); 290: double y2 = t2 * (p3.getY() - p2.getY()) + p2.getY(); 291: 292: // calculate the center point 293: double x = x2 - r * Math.cos(theta2); 294: double y = y2 + r * Math.sin(theta2); 295: 296: setArc(x - r, y - r, 2 * r, 2 * r, Math.toDegrees(theta1), 297: Math.toDegrees(theta2 - theta1), getArcType()); 298: } 299: 300: /** 301: * Set the start, in degrees. 302: * 303: * @param start the new start angle 304: * @see #getAngleStart() 305: */ 306: public abstract void setAngleStart(double start); 307: 308: /** 309: * Set the extent, in degrees. 310: * 311: * @param extent the new extent angle 312: * @see #getAngleExtent() 313: */ 314: public abstract void setAngleExtent(double extent); 315: 316: /** 317: * Sets the starting angle to the angle of the given point relative to 318: * the center of the arc. The extent remains constant; in other words, 319: * this rotates the arc. 320: * 321: * @param p the new start point 322: * @throws NullPointerException if p is null 323: * @see #getStartPoint() 324: * @see #getAngleStart() 325: */ 326: public void setAngleStart(Point2D p) 327: { 328: // Normalize. 329: double x = p.getX() - (getX() + getWidth() / 2); 330: double y = p.getY() - (getY() + getHeight() / 2); 331: setAngleStart(Math.toDegrees(Math.atan2(-y, x))); 332: } 333: 334: /** 335: * Sets the starting and extent angles to those of the given points 336: * relative to the center of the arc. The arc will be non-empty, and will 337: * extend counterclockwise. 338: * 339: * @param x1 the first x coordinate 340: * @param y1 the first y coordinate 341: * @param x2 the second x coordinate 342: * @param y2 the second y coordinate 343: * @see #setAngleStart(Point2D) 344: */ 345: public void setAngles(double x1, double y1, double x2, double y2) 346: { 347: // Normalize the points. 348: double mx = getX(); 349: double my = getY(); 350: double mw = getWidth(); 351: double mh = getHeight(); 352: x1 = x1 - (mx + mw / 2); 353: y1 = y1 - (my + mh / 2); 354: x2 = x2 - (mx + mw / 2); 355: y2 = y2 - (my + mh / 2); 356: double start = Math.toDegrees(Math.atan2(-y1, x1)); 357: double extent = Math.toDegrees(Math.atan2(-y2, x2)) - start; 358: if (extent < 0) 359: extent += 360; 360: setAngleStart(start); 361: setAngleExtent(extent); 362: } 363: 364: /** 365: * Sets the starting and extent angles to those of the given points 366: * relative to the center of the arc. The arc will be non-empty, and will 367: * extend counterclockwise. 368: * 369: * @param p1 the first point 370: * @param p2 the second point 371: * @throws NullPointerException if either point is null 372: * @see #setAngleStart(Point2D) 373: */ 374: public void setAngles(Point2D p1, Point2D p2) 375: { 376: setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY()); 377: } 378: 379: /** 380: * Set the closure type of this arc. 381: * 382: * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} 383: * @throws IllegalArgumentException if type is invalid 384: * @see #getArcType() 385: */ 386: public void setArcType(int type) 387: { 388: if (type < OPEN || type > PIE) 389: throw new IllegalArgumentException(); 390: this.type = type; 391: } 392: 393: /** 394: * Sets the location and bounds of the ellipse of which this arc is a part. 395: * 396: * @param x the new x coordinate 397: * @param y the new y coordinate 398: * @param w the new width 399: * @param h the new height 400: * @see #getFrame() 401: */ 402: public void setFrame(double x, double y, double w, double h) 403: { 404: setArc(x, y, w, h, getAngleStart(), getAngleExtent(), type); 405: } 406: 407: /** 408: * Gets the bounds of the arc. This is much tighter than 409: * <code>getBounds</code>, as it takes into consideration the start and 410: * end angles, and the center point of a pie wedge, rather than just the 411: * overall ellipse. 412: * 413: * @return the bounds of the arc 414: * @see #getBounds() 415: */ 416: public Rectangle2D getBounds2D() 417: { 418: double extent = getAngleExtent(); 419: if (Math.abs(extent) >= 360) 420: return makeBounds(getX(), getY(), getWidth(), getHeight()); 421: 422: // Find the minimal bounding box. This determined by its extrema, 423: // which are the center, the endpoints of the arc, and any local 424: // maximum contained by the arc. 425: double rX = getWidth() / 2; 426: double rY = getHeight() / 2; 427: double centerX = getX() + rX; 428: double centerY = getY() + rY; 429: 430: Point2D p1 = getStartPoint(); 431: Rectangle2D result = makeBounds(p1.getX(), p1.getY(), 0, 0); 432: result.add(getEndPoint()); 433: 434: if (type == PIE) 435: result.add(centerX, centerY); 436: if (containsAngle(0)) 437: result.add(centerX + rX, centerY); 438: if (containsAngle(90)) 439: result.add(centerX, centerY - rY); 440: if (containsAngle(180)) 441: result.add(centerX - rX, centerY); 442: if (containsAngle(270)) 443: result.add(centerX, centerY + rY); 444: 445: return result; 446: } 447: 448: /** 449: * Construct a bounding box in a precision appropriate for the subclass. 450: * 451: * @param x the x coordinate 452: * @param y the y coordinate 453: * @param w the width 454: * @param h the height 455: * @return the rectangle for use in getBounds2D 456: */ 457: protected abstract Rectangle2D makeBounds(double x, double y, double w, 458: double h); 459: 460: /** 461: * Tests if the given angle, in degrees, is included in the arc. 462: * All angles are normalized to be between 0 and 360 degrees. 463: * 464: * @param a the angle to test 465: * @return true if it is contained 466: */ 467: public boolean containsAngle(double a) 468: { 469: double start = getAngleStart(); 470: double extent = getAngleExtent(); 471: double end = start + extent; 472: 473: if (extent == 0) 474: return false; 475: 476: if (extent >= 360 || extent <= -360) 477: return true; 478: 479: if (extent < 0) 480: { 481: end = start; 482: start += extent; 483: } 484: 485: start %= 360; 486: while (start < 0) 487: start += 360; 488: 489: end %= 360; 490: while (end < start) 491: end += 360; 492: 493: a %= 360; 494: while (a < start) 495: a += 360; 496: 497: return a >= start && a < end; // starting angle included, ending angle not 498: } 499: 500: /** 501: * Determines if the arc contains the given point. If the bounding box 502: * is empty, then this will return false. 503: * 504: * The area considered 'inside' an arc of type OPEN is the same as the 505: * area inside an equivalent filled CHORD-type arc. The area considered 506: * 'inside' a CHORD-type arc is the same as the filled area. 507: * 508: * @param x the x coordinate to test 509: * @param y the y coordinate to test 510: * @return true if the point is inside the arc 511: */ 512: public boolean contains(double x, double y) 513: { 514: double w = getWidth(); 515: double h = getHeight(); 516: double extent = getAngleExtent(); 517: if (w <= 0 || h <= 0 || extent == 0) 518: return false; 519: 520: double mx = getX() + w / 2; 521: double my = getY() + h / 2; 522: double dx = (x - mx) * 2 / w; 523: double dy = (y - my) * 2 / h; 524: if ((dx * dx + dy * dy) >= 1.0) 525: return false; 526: 527: double angle = Math.toDegrees(Math.atan2(-dy, dx)); 528: if (getArcType() == PIE) 529: return containsAngle(angle); 530: 531: double a1 = Math.toRadians(getAngleStart()); 532: double a2 = Math.toRadians(getAngleStart() + extent); 533: double x1 = mx + getWidth() * Math.cos(a1) / 2; 534: double y1 = my - getHeight() * Math.sin(a1) / 2; 535: double x2 = mx + getWidth() * Math.cos(a2) / 2; 536: double y2 = my - getHeight() * Math.sin(a2) / 2; 537: double sgn = ((x2 - x1) * (my - y1) - (mx - x1) * (y2 - y1)) * ((x2 - x1) * (y 538: - y1) - (x - x1) * (y2 - y1)); 539: 540: if (Math.abs(extent) > 180) 541: { 542: if (containsAngle(angle)) 543: return true; 544: return sgn > 0; 545: } 546: else 547: { 548: if (! containsAngle(angle)) 549: return false; 550: return sgn < 0; 551: } 552: } 553: 554: /** 555: * Tests if a given rectangle intersects the area of the arc. 556: * 557: * For a definition of the 'inside' area, see the contains() method. 558: * @see #contains(double, double) 559: * 560: * @param x the x coordinate of the rectangle 561: * @param y the y coordinate of the rectangle 562: * @param w the width of the rectangle 563: * @param h the height of the rectangle 564: * @return true if the two shapes share common points 565: */ 566: public boolean intersects(double x, double y, double w, double h) 567: { 568: double extent = getAngleExtent(); 569: if (extent == 0) 570: return false; 571: 572: if (contains(x, y) || contains(x, y + h) || contains(x + w, y) 573: || contains(x + w, y + h)) 574: return true; 575: 576: Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); 577: 578: double a = getWidth() / 2.0; 579: double b = getHeight() / 2.0; 580: 581: double mx = getX() + a; 582: double my = getY() + b; 583: double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); 584: double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); 585: double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); 586: double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); 587: 588: if (getArcType() != CHORD) 589: { 590: // check intersections against the pie radii 591: if (rect.intersectsLine(mx, my, x1, y1)) 592: return true; 593: if (rect.intersectsLine(mx, my, x2, y2)) 594: return true; 595: } 596: else// check the chord 597: if (rect.intersectsLine(x1, y1, x2, y2)) 598: return true; 599: 600: // Check the Arc segment against the four edges 601: double dx; 602: 603: // Check the Arc segment against the four edges 604: double dy; 605: dy = y - my; 606: dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); 607: if (! java.lang.Double.isNaN(dx)) 608: { 609: if (mx + dx >= x && mx + dx <= x + w 610: && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) 611: return true; 612: if (mx - dx >= x && mx - dx <= x + w 613: && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) 614: return true; 615: } 616: dy = (y + h) - my; 617: dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); 618: if (! java.lang.Double.isNaN(dx)) 619: { 620: if (mx + dx >= x && mx + dx <= x + w 621: && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) 622: return true; 623: if (mx - dx >= x && mx - dx <= x + w 624: && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) 625: return true; 626: } 627: dx = x - mx; 628: dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); 629: if (! java.lang.Double.isNaN(dy)) 630: { 631: if (my + dy >= y && my + dy <= y + h 632: && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) 633: return true; 634: if (my - dy >= y && my - dy <= y + h 635: && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) 636: return true; 637: } 638: 639: dx = (x + w) - mx; 640: dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); 641: if (! java.lang.Double.isNaN(dy)) 642: { 643: if (my + dy >= y && my + dy <= y + h 644: && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) 645: return true; 646: if (my - dy >= y && my - dy <= y + h 647: && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) 648: return true; 649: } 650: 651: // Check whether the arc is contained within the box 652: if (rect.contains(mx, my)) 653: return true; 654: 655: return false; 656: } 657: 658: /** 659: * Tests if a given rectangle is contained in the area of the arc. 660: * 661: * @param x the x coordinate of the rectangle 662: * @param y the y coordinate of the rectangle 663: * @param w the width of the rectangle 664: * @param h the height of the rectangle 665: * @return true if the arc contains the rectangle 666: */ 667: public boolean contains(double x, double y, double w, double h) 668: { 669: double extent = getAngleExtent(); 670: if (extent == 0) 671: return false; 672: 673: if (! (contains(x, y) && contains(x, y + h) && contains(x + w, y) 674: && contains(x + w, y + h))) 675: return false; 676: 677: Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); 678: 679: double a = getWidth() / 2.0; 680: double b = getHeight() / 2.0; 681: 682: double mx = getX() + a; 683: double my = getY() + b; 684: double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); 685: double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); 686: double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); 687: double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); 688: if (getArcType() != CHORD) 689: { 690: // check intersections against the pie radii 691: if (rect.intersectsLine(mx, my, x1, y1)) 692: return false; 693: 694: if (rect.intersectsLine(mx, my, x2, y2)) 695: return false; 696: } 697: else if (rect.intersectsLine(x1, y1, x2, y2)) 698: return false; 699: return true; 700: } 701: 702: /** 703: * Tests if a given rectangle is contained in the area of the arc. 704: * 705: * @param r the rectangle 706: * @return true if the arc contains the rectangle 707: */ 708: public boolean contains(Rectangle2D r) 709: { 710: return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 711: } 712: 713: /** 714: * Returns an iterator over this arc, with an optional transformation. 715: * This iterator is threadsafe, so future modifications to the arc do not 716: * affect the iteration. 717: * 718: * @param at the transformation, or null 719: * @return a path iterator 720: */ 721: public PathIterator getPathIterator(AffineTransform at) 722: { 723: return new ArcIterator(this, at); 724: } 725: 726: /** 727: * This class is used to iterate over an arc. Since ellipses are a subclass 728: * of arcs, this is used by Ellipse2D as well. 729: * 730: * @author Eric Blake (ebb9@email.byu.edu) 731: */ 732: static final class ArcIterator implements PathIterator 733: { 734: /** The current iteration. */ 735: private int current; 736: 737: /** The last iteration. */ 738: private final int limit; 739: 740: /** The optional transformation. */ 741: private final AffineTransform xform; 742: 743: /** The x coordinate of the bounding box. */ 744: private final double x; 745: 746: /** The y coordinate of the bounding box. */ 747: private