jdk/src/share/classes/java/awt/geom/Arc2D.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-2006 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.io.Serializable;
       
    29 
       
    30 /**
       
    31  * <CODE>Arc2D</CODE> is the abstract superclass for all objects that
       
    32  * store a 2D arc defined by a framing rectangle,
       
    33  * start angle, angular extent (length of the arc), and a closure type
       
    34  * (<CODE>OPEN</CODE>, <CODE>CHORD</CODE>, or <CODE>PIE</CODE>).
       
    35  * <p>
       
    36  * <a name="inscribes">
       
    37  * The arc is a partial section of a full ellipse which
       
    38  * inscribes the framing rectangle of its parent {@link RectangularShape}.
       
    39  * </a>
       
    40  * <a name="angles">
       
    41  * The angles are specified relative to the non-square
       
    42  * framing rectangle such that 45 degrees always falls on the line from
       
    43  * the center of the ellipse to the upper right corner of the framing
       
    44  * rectangle.
       
    45  * As a result, if the framing rectangle is noticeably longer along one
       
    46  * axis than the other, the angles to the start and end of the arc segment
       
    47  * will be skewed farther along the longer axis of the frame.
       
    48  * </a>
       
    49  * <p>
       
    50  * The actual storage representation of the coordinates is left to
       
    51  * the subclass.
       
    52  *
       
    53  * @author      Jim Graham
       
    54  * @since 1.2
       
    55  */
       
    56 public abstract class Arc2D extends RectangularShape {
       
    57 
       
    58     /**
       
    59      * The closure type for an open arc with no path segments
       
    60      * connecting the two ends of the arc segment.
       
    61      * @since 1.2
       
    62      */
       
    63     public final static int OPEN = 0;
       
    64 
       
    65     /**
       
    66      * The closure type for an arc closed by drawing a straight
       
    67      * line segment from the start of the arc segment to the end of the
       
    68      * arc segment.
       
    69      * @since 1.2
       
    70      */
       
    71     public final static int CHORD = 1;
       
    72 
       
    73     /**
       
    74      * The closure type for an arc closed by drawing straight line
       
    75      * segments from the start of the arc segment to the center
       
    76      * of the full ellipse and from that point to the end of the arc segment.
       
    77      * @since 1.2
       
    78      */
       
    79     public final static int PIE = 2;
       
    80 
       
    81     /**
       
    82      * This class defines an arc specified in {@code float} precision.
       
    83      * @since 1.2
       
    84      */
       
    85     public static class Float extends Arc2D implements Serializable {
       
    86         /**
       
    87          * The X coordinate of the upper-left corner of the framing
       
    88          * rectangle of the arc.
       
    89          * @since 1.2
       
    90          * @serial
       
    91          */
       
    92         public float x;
       
    93 
       
    94         /**
       
    95          * The Y coordinate of the upper-left corner of the framing
       
    96          * rectangle of the arc.
       
    97          * @since 1.2
       
    98          * @serial
       
    99          */
       
   100         public float y;
       
   101 
       
   102         /**
       
   103          * The overall width of the full ellipse of which this arc is
       
   104          * a partial section (not considering the
       
   105          * angular extents).
       
   106          * @since 1.2
       
   107          * @serial
       
   108          */
       
   109         public float width;
       
   110 
       
   111         /**
       
   112          * The overall height of the full ellipse of which this arc is
       
   113          * a partial section (not considering the
       
   114          * angular extents).
       
   115          * @since 1.2
       
   116          * @serial
       
   117          */
       
   118         public float height;
       
   119 
       
   120         /**
       
   121          * The starting angle of the arc in degrees.
       
   122          * @since 1.2
       
   123          * @serial
       
   124          */
       
   125         public float start;
       
   126 
       
   127         /**
       
   128          * The angular extent of the arc in degrees.
       
   129          * @since 1.2
       
   130          * @serial
       
   131          */
       
   132         public float extent;
       
   133 
       
   134         /**
       
   135          * Constructs a new OPEN arc, initialized to location (0, 0),
       
   136          * size (0, 0), angular extents (start = 0, extent = 0).
       
   137          * @since 1.2
       
   138          */
       
   139         public Float() {
       
   140             super(OPEN);
       
   141         }
       
   142 
       
   143         /**
       
   144          * Constructs a new arc, initialized to location (0, 0),
       
   145          * size (0, 0), angular extents (start = 0, extent = 0), and
       
   146          * the specified closure type.
       
   147          *
       
   148          * @param type The closure type for the arc:
       
   149          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   150          * @since 1.2
       
   151          */
       
   152         public Float(int type) {
       
   153             super(type);
       
   154         }
       
   155 
       
   156         /**
       
   157          * Constructs a new arc, initialized to the specified location,
       
   158          * size, angular extents, and closure type.
       
   159          *
       
   160          * @param x The X coordinate of the upper-left corner of
       
   161          *          the arc's framing rectangle.
       
   162          * @param y The Y coordinate of the upper-left corner of
       
   163          *          the arc's framing rectangle.
       
   164          * @param w The overall width of the full ellipse of which
       
   165          *          this arc is a partial section.
       
   166          * @param h The overall height of the full ellipse of which this
       
   167          *          arc is a partial section.
       
   168          * @param start The starting angle of the arc in degrees.
       
   169          * @param extent The angular extent of the arc in degrees.
       
   170          * @param type The closure type for the arc:
       
   171          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   172          * @since 1.2
       
   173          */
       
   174         public Float(float x, float y, float w, float h,
       
   175                      float start, float extent, int type) {
       
   176             super(type);
       
   177             this.x = x;
       
   178             this.y = y;
       
   179             this.width = w;
       
   180             this.height = h;
       
   181             this.start = start;
       
   182             this.extent = extent;
       
   183         }
       
   184 
       
   185         /**
       
   186          * Constructs a new arc, initialized to the specified location,
       
   187          * size, angular extents, and closure type.
       
   188          *
       
   189          * @param ellipseBounds The framing rectangle that defines the
       
   190          * outer boundary of the full ellipse of which this arc is a
       
   191          * partial section.
       
   192          * @param start The starting angle of the arc in degrees.
       
   193          * @param extent The angular extent of the arc in degrees.
       
   194          * @param type The closure type for the arc:
       
   195          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   196          * @since 1.2
       
   197          */
       
   198         public Float(Rectangle2D ellipseBounds,
       
   199                      float start, float extent, int type) {
       
   200             super(type);
       
   201             this.x = (float) ellipseBounds.getX();
       
   202             this.y = (float) ellipseBounds.getY();
       
   203             this.width = (float) ellipseBounds.getWidth();
       
   204             this.height = (float) ellipseBounds.getHeight();
       
   205             this.start = start;
       
   206             this.extent = extent;
       
   207         }
       
   208 
       
   209         /**
       
   210          * {@inheritDoc}
       
   211          * Note that the arc
       
   212          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   213          * the framing rectangle of this {@code RectangularShape}.
       
   214          *
       
   215          * @since 1.2
       
   216          */
       
   217         public double getX() {
       
   218             return (double) x;
       
   219         }
       
   220 
       
   221         /**
       
   222          * {@inheritDoc}
       
   223          * Note that the arc
       
   224          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   225          * the framing rectangle of this {@code RectangularShape}.
       
   226          *
       
   227          * @since 1.2
       
   228          */
       
   229         public double getY() {
       
   230             return (double) y;
       
   231         }
       
   232 
       
   233         /**
       
   234          * {@inheritDoc}
       
   235          * Note that the arc
       
   236          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   237          * the framing rectangle of this {@code RectangularShape}.
       
   238          *
       
   239          * @since 1.2
       
   240          */
       
   241         public double getWidth() {
       
   242             return (double) width;
       
   243         }
       
   244 
       
   245         /**
       
   246          * {@inheritDoc}
       
   247          * Note that the arc
       
   248          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   249          * the framing rectangle of this {@code RectangularShape}.
       
   250          *
       
   251          * @since 1.2
       
   252          */
       
   253         public double getHeight() {
       
   254             return (double) height;
       
   255         }
       
   256 
       
   257         /**
       
   258          * {@inheritDoc}
       
   259          * @since 1.2
       
   260          */
       
   261         public double getAngleStart() {
       
   262             return (double) start;
       
   263         }
       
   264 
       
   265         /**
       
   266          * {@inheritDoc}
       
   267          * @since 1.2
       
   268          */
       
   269         public double getAngleExtent() {
       
   270             return (double) extent;
       
   271         }
       
   272 
       
   273         /**
       
   274          * {@inheritDoc}
       
   275          * @since 1.2
       
   276          */
       
   277         public boolean isEmpty() {
       
   278             return (width <= 0.0 || height <= 0.0);
       
   279         }
       
   280 
       
   281         /**
       
   282          * {@inheritDoc}
       
   283          * @since 1.2
       
   284          */
       
   285         public void setArc(double x, double y, double w, double h,
       
   286                            double angSt, double angExt, int closure) {
       
   287             this.setArcType(closure);
       
   288             this.x = (float) x;
       
   289             this.y = (float) y;
       
   290             this.width = (float) w;
       
   291             this.height = (float) h;
       
   292             this.start = (float) angSt;
       
   293             this.extent = (float) angExt;
       
   294         }
       
   295 
       
   296         /**
       
   297          * {@inheritDoc}
       
   298          * @since 1.2
       
   299          */
       
   300         public void setAngleStart(double angSt) {
       
   301             this.start = (float) angSt;
       
   302         }
       
   303 
       
   304         /**
       
   305          * {@inheritDoc}
       
   306          * @since 1.2
       
   307          */
       
   308         public void setAngleExtent(double angExt) {
       
   309             this.extent = (float) angExt;
       
   310         }
       
   311 
       
   312         /**
       
   313          * {@inheritDoc}
       
   314          * @since 1.2
       
   315          */
       
   316         protected Rectangle2D makeBounds(double x, double y,
       
   317                                          double w, double h) {
       
   318             return new Rectangle2D.Float((float) x, (float) y,
       
   319                                          (float) w, (float) h);
       
   320         }
       
   321 
       
   322         /*
       
   323          * JDK 1.6 serialVersionUID
       
   324          */
       
   325         private static final long serialVersionUID = 9130893014586380278L;
       
   326 
       
   327         /**
       
   328          * Writes the default serializable fields to the
       
   329          * <code>ObjectOutputStream</code> followed by a byte
       
   330          * indicating the arc type of this <code>Arc2D</code>
       
   331          * instance.
       
   332          *
       
   333          * @serialData
       
   334          * <ol>
       
   335          * <li>The default serializable fields.
       
   336          * <li>
       
   337          * followed by a <code>byte</code> indicating the arc type
       
   338          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   339          * </ol>
       
   340          */
       
   341         private void writeObject(java.io.ObjectOutputStream s)
       
   342             throws java.io.IOException
       
   343         {
       
   344             s.defaultWriteObject();
       
   345 
       
   346             s.writeByte(getArcType());
       
   347         }
       
   348 
       
   349         /**
       
   350          * Reads the default serializable fields from the
       
   351          * <code>ObjectInputStream</code> followed by a byte
       
   352          * indicating the arc type of this <code>Arc2D</code>
       
   353          * instance.
       
   354          *
       
   355          * @serialData
       
   356          * <ol>
       
   357          * <li>The default serializable fields.
       
   358          * <li>
       
   359          * followed by a <code>byte</code> indicating the arc type
       
   360          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   361          * </ol>
       
   362          */
       
   363         private void readObject(java.io.ObjectInputStream s)
       
   364             throws java.lang.ClassNotFoundException, java.io.IOException
       
   365         {
       
   366             s.defaultReadObject();
       
   367 
       
   368             try {
       
   369                 setArcType(s.readByte());
       
   370             } catch (IllegalArgumentException iae) {
       
   371                 throw new java.io.InvalidObjectException(iae.getMessage());
       
   372             }
       
   373         }
       
   374     }
       
   375 
       
   376     /**
       
   377      * This class defines an arc specified in {@code double} precision.
       
   378      * @since 1.2
       
   379      */
       
   380     public static class Double extends Arc2D implements Serializable {
       
   381         /**
       
   382          * The X coordinate of the upper-left corner of the framing
       
   383          * rectangle of the arc.
       
   384          * @since 1.2
       
   385          * @serial
       
   386          */
       
   387         public double x;
       
   388 
       
   389         /**
       
   390          * The Y coordinate of the upper-left corner of the framing
       
   391          * rectangle of the arc.
       
   392          * @since 1.2
       
   393          * @serial
       
   394          */
       
   395         public double y;
       
   396 
       
   397         /**
       
   398          * The overall width of the full ellipse of which this arc is
       
   399          * a partial section (not considering the angular extents).
       
   400          * @since 1.2
       
   401          * @serial
       
   402          */
       
   403         public double width;
       
   404 
       
   405         /**
       
   406          * The overall height of the full ellipse of which this arc is
       
   407          * a partial section (not considering the angular extents).
       
   408          * @since 1.2
       
   409          * @serial
       
   410          */
       
   411         public double height;
       
   412 
       
   413         /**
       
   414          * The starting angle of the arc in degrees.
       
   415          * @since 1.2
       
   416          * @serial
       
   417          */
       
   418         public double start;
       
   419 
       
   420         /**
       
   421          * The angular extent of the arc in degrees.
       
   422          * @since 1.2
       
   423          * @serial
       
   424          */
       
   425         public double extent;
       
   426 
       
   427         /**
       
   428          * Constructs a new OPEN arc, initialized to location (0, 0),
       
   429          * size (0, 0), angular extents (start = 0, extent = 0).
       
   430          * @since 1.2
       
   431          */
       
   432         public Double() {
       
   433             super(OPEN);
       
   434         }
       
   435 
       
   436         /**
       
   437          * Constructs a new arc, initialized to location (0, 0),
       
   438          * size (0, 0), angular extents (start = 0, extent = 0), and
       
   439          * the specified closure type.
       
   440          *
       
   441          * @param type The closure type for the arc:
       
   442          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   443          * @since 1.2
       
   444          */
       
   445         public Double(int type) {
       
   446             super(type);
       
   447         }
       
   448 
       
   449         /**
       
   450          * Constructs a new arc, initialized to the specified location,
       
   451          * size, angular extents, and closure type.
       
   452          *
       
   453          * @param x The X coordinate of the upper-left corner
       
   454          *          of the arc's framing rectangle.
       
   455          * @param y The Y coordinate of the upper-left corner
       
   456          *          of the arc's framing rectangle.
       
   457          * @param w The overall width of the full ellipse of which this
       
   458          *          arc is a partial section.
       
   459          * @param h The overall height of the full ellipse of which this
       
   460          *          arc is a partial section.
       
   461          * @param start The starting angle of the arc in degrees.
       
   462          * @param extent The angular extent of the arc in degrees.
       
   463          * @param type The closure type for the arc:
       
   464          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   465          * @since 1.2
       
   466          */
       
   467         public Double(double x, double y, double w, double h,
       
   468                       double start, double extent, int type) {
       
   469             super(type);
       
   470             this.x = x;
       
   471             this.y = y;
       
   472             this.width = w;
       
   473             this.height = h;
       
   474             this.start = start;
       
   475             this.extent = extent;
       
   476         }
       
   477 
       
   478         /**
       
   479          * Constructs a new arc, initialized to the specified location,
       
   480          * size, angular extents, and closure type.
       
   481          *
       
   482          * @param ellipseBounds The framing rectangle that defines the
       
   483          * outer boundary of the full ellipse of which this arc is a
       
   484          * partial section.
       
   485          * @param start The starting angle of the arc in degrees.
       
   486          * @param extent The angular extent of the arc in degrees.
       
   487          * @param type The closure type for the arc:
       
   488          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   489          * @since 1.2
       
   490          */
       
   491         public Double(Rectangle2D ellipseBounds,
       
   492                       double start, double extent, int type) {
       
   493             super(type);
       
   494             this.x = ellipseBounds.getX();
       
   495             this.y = ellipseBounds.getY();
       
   496             this.width = ellipseBounds.getWidth();
       
   497             this.height = ellipseBounds.getHeight();
       
   498             this.start = start;
       
   499             this.extent = extent;
       
   500         }
       
   501 
       
   502         /**
       
   503          * {@inheritDoc}
       
   504          * Note that the arc
       
   505          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   506          * the framing rectangle of this {@code RectangularShape}.
       
   507          *
       
   508          * @since 1.2
       
   509          */
       
   510         public double getX() {
       
   511             return x;
       
   512         }
       
   513 
       
   514         /**
       
   515          * {@inheritDoc}
       
   516          * Note that the arc
       
   517          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   518          * the framing rectangle of this {@code RectangularShape}.
       
   519          *
       
   520          * @since 1.2
       
   521          */
       
   522         public double getY() {
       
   523             return y;
       
   524         }
       
   525 
       
   526         /**
       
   527          * {@inheritDoc}
       
   528          * Note that the arc
       
   529          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   530          * the framing rectangle of this {@code RectangularShape}.
       
   531          *
       
   532          * @since 1.2
       
   533          */
       
   534         public double getWidth() {
       
   535             return width;
       
   536         }
       
   537 
       
   538         /**
       
   539          * {@inheritDoc}
       
   540          * Note that the arc
       
   541          * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
   542          * the framing rectangle of this {@code RectangularShape}.
       
   543          *
       
   544          * @since 1.2
       
   545          */
       
   546         public double getHeight() {
       
   547             return height;
       
   548         }
       
   549 
       
   550         /**
       
   551          * {@inheritDoc}
       
   552          * @since 1.2
       
   553          */
       
   554         public double getAngleStart() {
       
   555             return start;
       
   556         }
       
   557 
       
   558         /**
       
   559          * {@inheritDoc}
       
   560          * @since 1.2
       
   561          */
       
   562         public double getAngleExtent() {
       
   563             return extent;
       
   564         }
       
   565 
       
   566         /**
       
   567          * {@inheritDoc}
       
   568          * @since 1.2
       
   569          */
       
   570         public boolean isEmpty() {
       
   571             return (width <= 0.0 || height <= 0.0);
       
   572         }
       
   573 
       
   574         /**
       
   575          * {@inheritDoc}
       
   576          * @since 1.2
       
   577          */
       
   578         public void setArc(double x, double y, double w, double h,
       
   579                            double angSt, double angExt, int closure) {
       
   580             this.setArcType(closure);
       
   581             this.x = x;
       
   582             this.y = y;
       
   583             this.width = w;
       
   584             this.height = h;
       
   585             this.start = angSt;
       
   586             this.extent = angExt;
       
   587         }
       
   588 
       
   589         /**
       
   590          * {@inheritDoc}
       
   591          * @since 1.2
       
   592          */
       
   593         public void setAngleStart(double angSt) {
       
   594             this.start = angSt;
       
   595         }
       
   596 
       
   597         /**
       
   598          * {@inheritDoc}
       
   599          * @since 1.2
       
   600          */
       
   601         public void setAngleExtent(double angExt) {
       
   602             this.extent = angExt;
       
   603         }
       
   604 
       
   605         /**
       
   606          * {@inheritDoc}
       
   607          * @since 1.2
       
   608          */
       
   609         protected Rectangle2D makeBounds(double x, double y,
       
   610                                          double w, double h) {
       
   611             return new Rectangle2D.Double(x, y, w, h);
       
   612         }
       
   613 
       
   614         /*
       
   615          * JDK 1.6 serialVersionUID
       
   616          */
       
   617         private static final long serialVersionUID = 728264085846882001L;
       
   618 
       
   619         /**
       
   620          * Writes the default serializable fields to the
       
   621          * <code>ObjectOutputStream</code> followed by a byte
       
   622          * indicating the arc type of this <code>Arc2D</code>
       
   623          * instance.
       
   624          *
       
   625          * @serialData
       
   626          * <ol>
       
   627          * <li>The default serializable fields.
       
   628          * <li>
       
   629          * followed by a <code>byte</code> indicating the arc type
       
   630          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   631          * </ol>
       
   632          */
       
   633         private void writeObject(java.io.ObjectOutputStream s)
       
   634             throws java.io.IOException
       
   635         {
       
   636             s.defaultWriteObject();
       
   637 
       
   638             s.writeByte(getArcType());
       
   639         }
       
   640 
       
   641         /**
       
   642          * Reads the default serializable fields from the
       
   643          * <code>ObjectInputStream</code> followed by a byte
       
   644          * indicating the arc type of this <code>Arc2D</code>
       
   645          * instance.
       
   646          *
       
   647          * @serialData
       
   648          * <ol>
       
   649          * <li>The default serializable fields.
       
   650          * <li>
       
   651          * followed by a <code>byte</code> indicating the arc type
       
   652          * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   653          * </ol>
       
   654          */
       
   655         private void readObject(java.io.ObjectInputStream s)
       
   656             throws java.lang.ClassNotFoundException, java.io.IOException
       
   657         {
       
   658             s.defaultReadObject();
       
   659 
       
   660             try {
       
   661                 setArcType(s.readByte());
       
   662             } catch (IllegalArgumentException iae) {
       
   663                 throw new java.io.InvalidObjectException(iae.getMessage());
       
   664             }
       
   665         }
       
   666     }
       
   667 
       
   668     private int type;
       
   669 
       
   670     /**
       
   671      * This is an abstract class that cannot be instantiated directly.
       
   672      * Type-specific implementation subclasses are available for
       
   673      * instantiation and provide a number of formats for storing
       
   674      * the information necessary to satisfy the various accessor
       
   675      * methods below.
       
   676      * <p>
       
   677      * This constructor creates an object with a default closure
       
   678      * type of {@link #OPEN}.  It is provided only to enable
       
   679      * serialization of subclasses.
       
   680      *
       
   681      * @see java.awt.geom.Arc2D.Float
       
   682      * @see java.awt.geom.Arc2D.Double
       
   683      */
       
   684     Arc2D() {
       
   685         this(OPEN);
       
   686     }
       
   687 
       
   688     /**
       
   689      * This is an abstract class that cannot be instantiated directly.
       
   690      * Type-specific implementation subclasses are available for
       
   691      * instantiation and provide a number of formats for storing
       
   692      * the information necessary to satisfy the various accessor
       
   693      * methods below.
       
   694      *
       
   695      * @param type The closure type of this arc:
       
   696      * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   697      * @see java.awt.geom.Arc2D.Float
       
   698      * @see java.awt.geom.Arc2D.Double
       
   699      * @since 1.2
       
   700      */
       
   701     protected Arc2D(int type) {
       
   702         setArcType(type);
       
   703     }
       
   704 
       
   705     /**
       
   706      * Returns the starting angle of the arc.
       
   707      *
       
   708      * @return A double value that represents the starting angle
       
   709      * of the arc in degrees.
       
   710      * @see #setAngleStart
       
   711      * @since 1.2
       
   712      */
       
   713     public abstract double getAngleStart();
       
   714 
       
   715     /**
       
   716      * Returns the angular extent of the arc.
       
   717      *
       
   718      * @return A double value that represents the angular extent
       
   719      * of the arc in degrees.
       
   720      * @see #setAngleExtent
       
   721      * @since 1.2
       
   722      */
       
   723     public abstract double getAngleExtent();
       
   724 
       
   725     /**
       
   726      * Returns the arc closure type of the arc: {@link #OPEN},
       
   727      * {@link #CHORD}, or {@link #PIE}.
       
   728      * @return One of the integer constant closure types defined
       
   729      * in this class.
       
   730      * @see #setArcType
       
   731      * @since 1.2
       
   732      */
       
   733     public int getArcType() {
       
   734         return type;
       
   735     }
       
   736 
       
   737     /**
       
   738      * Returns the starting point of the arc.  This point is the
       
   739      * intersection of the ray from the center defined by the
       
   740      * starting angle and the elliptical boundary of the arc.
       
   741      *
       
   742      * @return A <CODE>Point2D</CODE> object representing the
       
   743      * x,y coordinates of the starting point of the arc.
       
   744      * @since 1.2
       
   745      */
       
   746     public Point2D getStartPoint() {
       
   747         double angle = Math.toRadians(-getAngleStart());
       
   748         double x = getX() + (Math.cos(angle) * 0.5 + 0.5) * getWidth();
       
   749         double y = getY() + (Math.sin(angle) * 0.5 + 0.5) * getHeight();
       
   750         return new Point2D.Double(x, y);
       
   751     }
       
   752 
       
   753     /**
       
   754      * Returns the ending point of the arc.  This point is the
       
   755      * intersection of the ray from the center defined by the
       
   756      * starting angle plus the angular extent of the arc and the
       
   757      * elliptical boundary of the arc.
       
   758      *
       
   759      * @return A <CODE>Point2D</CODE> object representing the
       
   760      * x,y coordinates  of the ending point of the arc.
       
   761      * @since 1.2
       
   762      */
       
   763     public Point2D getEndPoint() {
       
   764         double angle = Math.toRadians(-getAngleStart() - getAngleExtent());
       
   765         double x = getX() + (Math.cos(angle) * 0.5 + 0.5) * getWidth();
       
   766         double y = getY() + (Math.sin(angle) * 0.5 + 0.5) * getHeight();
       
   767         return new Point2D.Double(x, y);
       
   768     }
       
   769 
       
   770     /**
       
   771      * Sets the location, size, angular extents, and closure type of
       
   772      * this arc to the specified double values.
       
   773      *
       
   774      * @param x The X coordinate of the upper-left corner of the arc.
       
   775      * @param y The Y coordinate of the upper-left corner of the arc.
       
   776      * @param w The overall width of the full ellipse of which
       
   777      *          this arc is a partial section.
       
   778      * @param h The overall height of the full ellipse of which
       
   779      *          this arc is a partial section.
       
   780      * @param angSt The starting angle of the arc in degrees.
       
   781      * @param angExt The angular extent of the arc in degrees.
       
   782      * @param closure The closure type for the arc:
       
   783      * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   784      * @since 1.2
       
   785      */
       
   786     public abstract void setArc(double x, double y, double w, double h,
       
   787                                 double angSt, double angExt, int closure);
       
   788 
       
   789     /**
       
   790      * Sets the location, size, angular extents, and closure type of
       
   791      * this arc to the specified values.
       
   792      *
       
   793      * @param loc The <CODE>Point2D</CODE> representing the coordinates of
       
   794      * the upper-left corner of the arc.
       
   795      * @param size The <CODE>Dimension2D</CODE> representing the width
       
   796      * and height of the full ellipse of which this arc is
       
   797      * a partial section.
       
   798      * @param angSt The starting angle of the arc in degrees.
       
   799      * @param angExt The angular extent of the arc in degrees.
       
   800      * @param closure The closure type for the arc:
       
   801      * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   802      * @since 1.2
       
   803      */
       
   804     public void setArc(Point2D loc, Dimension2D size,
       
   805                        double angSt, double angExt, int closure) {
       
   806         setArc(loc.getX(), loc.getY(), size.getWidth(), size.getHeight(),
       
   807                angSt, angExt, closure);
       
   808     }
       
   809 
       
   810     /**
       
   811      * Sets the location, size, angular extents, and closure type of
       
   812      * this arc to the specified values.
       
   813      *
       
   814      * @param rect The framing rectangle that defines the
       
   815      * outer boundary of the full ellipse of which this arc is a
       
   816      * partial section.
       
   817      * @param angSt The starting angle of the arc in degrees.
       
   818      * @param angExt The angular extent of the arc in degrees.
       
   819      * @param closure The closure type for the arc:
       
   820      * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   821      * @since 1.2
       
   822      */
       
   823     public void setArc(Rectangle2D rect, double angSt, double angExt,
       
   824                        int closure) {
       
   825         setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(),
       
   826                angSt, angExt, closure);
       
   827     }
       
   828 
       
   829     /**
       
   830      * Sets this arc to be the same as the specified arc.
       
   831      *
       
   832      * @param a The <CODE>Arc2D</CODE> to use to set the arc's values.
       
   833      * @since 1.2
       
   834      */
       
   835     public void setArc(Arc2D a) {
       
   836         setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(),
       
   837                a.getAngleStart(), a.getAngleExtent(), a.type);
       
   838     }
       
   839 
       
   840     /**
       
   841      * Sets the position, bounds, angular extents, and closure type of
       
   842      * this arc to the specified values. The arc is defined by a center
       
   843      * point and a radius rather than a framing rectangle for the full ellipse.
       
   844      *
       
   845      * @param x The X coordinate of the center of the arc.
       
   846      * @param y The Y coordinate of the center of the arc.
       
   847      * @param radius The radius of the arc.
       
   848      * @param angSt The starting angle of the arc in degrees.
       
   849      * @param angExt The angular extent of the arc in degrees.
       
   850      * @param closure The closure type for the arc:
       
   851      * {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
       
   852      * @since 1.2
       
   853      */
       
   854     public void setArcByCenter(double x, double y, double radius,
       
   855                                double angSt, double angExt, int closure) {
       
   856         setArc(x - radius, y - radius, radius * 2.0, radius * 2.0,
       
   857                angSt, angExt, closure);
       
   858     }
       
   859 
       
   860     /**
       
   861      * Sets the position, bounds, and angular extents of this arc to the
       
   862      * specified value. The starting angle of the arc is tangent to the
       
   863      * line specified by points (p1, p2), the ending angle is tangent to
       
   864      * the line specified by points (p2, p3), and the arc has the
       
   865      * specified radius.
       
   866      *
       
   867      * @param p1 The first point that defines the arc. The starting
       
   868      * angle of the arc is tangent to the line specified by points (p1, p2).
       
   869      * @param p2 The second point that defines the arc. The starting
       
   870      * angle of the arc is tangent to the line specified by points (p1, p2).
       
   871      * The ending angle of the arc is tangent to the line specified by
       
   872      * points (p2, p3).
       
   873      * @param p3 The third point that defines the arc. The ending angle
       
   874      * of the arc is tangent to the line specified by points (p2, p3).
       
   875      * @param radius The radius of the arc.
       
   876      * @since 1.2
       
   877      */
       
   878     public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3,
       
   879                                 double radius) {
       
   880         double ang1 = Math.atan2(p1.getY() - p2.getY(),
       
   881                                  p1.getX() - p2.getX());
       
   882         double ang2 = Math.atan2(p3.getY() - p2.getY(),
       
   883                                  p3.getX() - p2.getX());
       
   884         double diff = ang2 - ang1;
       
   885         if (diff > Math.PI) {
       
   886             ang2 -= Math.PI * 2.0;
       
   887         } else if (diff < -Math.PI) {
       
   888             ang2 += Math.PI * 2.0;
       
   889         }
       
   890         double bisect = (ang1 + ang2) / 2.0;
       
   891         double theta = Math.abs(ang2 - bisect);
       
   892         double dist = radius / Math.sin(theta);
       
   893         double x = p2.getX() + dist * Math.cos(bisect);
       
   894         double y = p2.getY() + dist * Math.sin(bisect);
       
   895         // REMIND: This needs some work...
       
   896         if (ang1 < ang2) {
       
   897             ang1 -= Math.PI / 2.0;
       
   898             ang2 += Math.PI / 2.0;
       
   899         } else {
       
   900             ang1 += Math.PI / 2.0;
       
   901             ang2 -= Math.PI / 2.0;
       
   902         }
       
   903         ang1 = Math.toDegrees(-ang1);
       
   904         ang2 = Math.toDegrees(-ang2);
       
   905         diff = ang2 - ang1;
       
   906         if (diff < 0) {
       
   907             diff += 360;
       
   908         } else {
       
   909             diff -= 360;
       
   910         }
       
   911         setArcByCenter(x, y, radius, ang1, diff, type);
       
   912     }
       
   913 
       
   914     /**
       
   915      * Sets the starting angle of this arc to the specified double
       
   916      * value.
       
   917      *
       
   918      * @param angSt The starting angle of the arc in degrees.
       
   919      * @see #getAngleStart
       
   920      * @since 1.2
       
   921      */
       
   922     public abstract void setAngleStart(double angSt);
       
   923 
       
   924     /**
       
   925      * Sets the angular extent of this arc to the specified double
       
   926      * value.
       
   927      *
       
   928      * @param angExt The angular extent of the arc in degrees.
       
   929      * @see #getAngleExtent
       
   930      * @since 1.2
       
   931      */
       
   932     public abstract void setAngleExtent(double angExt);
       
   933 
       
   934     /**
       
   935      * Sets the starting angle of this arc to the angle that the
       
   936      * specified point defines relative to the center of this arc.
       
   937      * The angular extent of the arc will remain the same.
       
   938      *
       
   939      * @param p The <CODE>Point2D</CODE> that defines the starting angle.
       
   940      * @see #getAngleStart
       
   941      * @since 1.2
       
   942      */
       
   943     public void setAngleStart(Point2D p) {
       
   944         // Bias the dx and dy by the height and width of the oval.
       
   945         double dx = getHeight() * (p.getX() - getCenterX());
       
   946         double dy = getWidth() * (p.getY() - getCenterY());
       
   947         setAngleStart(-Math.toDegrees(Math.atan2(dy, dx)));
       
   948     }
       
   949 
       
   950     /**
       
   951      * Sets the starting angle and angular extent of this arc using two
       
   952      * sets of coordinates. The first set of coordinates is used to
       
   953      * determine the angle of the starting point relative to the arc's
       
   954      * center. The second set of coordinates is used to determine the
       
   955      * angle of the end point relative to the arc's center.
       
   956      * The arc will always be non-empty and extend counterclockwise
       
   957      * from the first point around to the second point.
       
   958      *
       
   959      * @param x1 The X coordinate of the arc's starting point.
       
   960      * @param y1 The Y coordinate of the arc's starting point.
       
   961      * @param x2 The X coordinate of the arc's ending point.
       
   962      * @param y2 The Y coordinate of the arc's ending point.
       
   963      * @since 1.2
       
   964      */
       
   965     public void setAngles(double x1, double y1, double x2, double y2) {
       
   966         double x = getCenterX();
       
   967         double y = getCenterY();
       
   968         double w = getWidth();
       
   969         double h = getHeight();
       
   970         // Note: reversing the Y equations negates the angle to adjust
       
   971         // for the upside down coordinate system.
       
   972         // Also we should bias atans by the height and width of the oval.
       
   973         double ang1 = Math.atan2(w * (y - y1), h * (x1 - x));
       
   974         double ang2 = Math.atan2(w * (y - y2), h * (x2 - x));
       
   975         ang2 -= ang1;
       
   976         if (ang2 <= 0.0) {
       
   977             ang2 += Math.PI * 2.0;
       
   978         }
       
   979         setAngleStart(Math.toDegrees(ang1));
       
   980         setAngleExtent(Math.toDegrees(ang2));
       
   981     }
       
   982 
       
   983     /**
       
   984      * Sets the starting angle and angular extent of this arc using
       
   985      * two points. The first point is used to determine the angle of
       
   986      * the starting point relative to the arc's center.
       
   987      * The second point is used to determine the angle of the end point
       
   988      * relative to the arc's center.
       
   989      * The arc will always be non-empty and extend counterclockwise
       
   990      * from the first point around to the second point.
       
   991      *
       
   992      * @param p1 The <CODE>Point2D</CODE> that defines the arc's
       
   993      * starting point.
       
   994      * @param p2 The <CODE>Point2D</CODE> that defines the arc's
       
   995      * ending point.
       
   996      * @since 1.2
       
   997      */
       
   998     public void setAngles(Point2D p1, Point2D p2) {
       
   999         setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY());
       
  1000     }
       
  1001 
       
  1002     /**
       
  1003      * Sets the closure type of this arc to the specified value:
       
  1004      * <CODE>OPEN</CODE>, <CODE>CHORD</CODE>, or <CODE>PIE</CODE>.
       
  1005      *
       
  1006      * @param type The integer constant that represents the closure
       
  1007      * type of this arc: {@link #OPEN}, {@link #CHORD}, or
       
  1008      * {@link #PIE}.
       
  1009      *
       
  1010      * @throws IllegalArgumentException if <code>type</code> is not
       
  1011      * 0, 1, or 2.+
       
  1012      * @see #getArcType
       
  1013      * @since 1.2
       
  1014      */
       
  1015     public void setArcType(int type) {
       
  1016         if (type < OPEN || type > PIE) {
       
  1017             throw new IllegalArgumentException("invalid type for Arc: "+type);
       
  1018         }
       
  1019         this.type = type;
       
  1020     }
       
  1021 
       
  1022     /**
       
  1023      * {@inheritDoc}
       
  1024      * Note that the arc
       
  1025      * <a href="Arc2D.html#inscribes">partially inscribes</a>
       
  1026      * the framing rectangle of this {@code RectangularShape}.
       
  1027      *
       
  1028      * @since 1.2
       
  1029      */
       
  1030     public void setFrame(double x, double y, double w, double h) {
       
  1031         setArc(x, y, w, h, getAngleStart(), getAngleExtent(), type);
       
  1032     }
       
  1033 
       
  1034     /**
       
  1035      * Returns the high-precision framing rectangle of the arc.  The framing
       
  1036      * rectangle contains only the part of this <code>Arc2D</code> that is
       
  1037      * in between the starting and ending angles and contains the pie
       
  1038      * wedge, if this <code>Arc2D</code> has a <code>PIE</code> closure type.
       
  1039      * <p>
       
  1040      * This method differs from the
       
  1041      * {@link RectangularShape#getBounds() getBounds} in that the
       
  1042      * <code>getBounds</code> method only returns the bounds of the
       
  1043      * enclosing ellipse of this <code>Arc2D</code> without considering
       
  1044      * the starting and ending angles of this <code>Arc2D</code>.
       
  1045      *
       
  1046      * @return the <CODE>Rectangle2D</CODE> that represents the arc's
       
  1047      * framing rectangle.
       
  1048      * @since 1.2
       
  1049      */
       
  1050     public Rectangle2D getBounds2D() {
       
  1051         if (isEmpty()) {
       
  1052             return makeBounds(getX(), getY(), getWidth(), getHeight());
       
  1053         }
       
  1054         double x1, y1, x2, y2;
       
  1055         if (getArcType() == PIE) {
       
  1056             x1 = y1 = x2 = y2 = 0.0;
       
  1057         } else {
       
  1058             x1 = y1 = 1.0;
       
  1059             x2 = y2 = -1.0;
       
  1060         }
       
  1061         double angle = 0.0;
       
  1062         for (int i = 0; i < 6; i++) {
       
  1063             if (i < 4) {
       
  1064                 // 0-3 are the four quadrants
       
  1065                 angle += 90.0;
       
  1066                 if (!containsAngle(angle)) {
       
  1067                     continue;
       
  1068                 }
       
  1069             } else if (i == 4) {
       
  1070                 // 4 is start angle
       
  1071                 angle = getAngleStart();
       
  1072             } else {
       
  1073                 // 5 is end angle
       
  1074                 angle += getAngleExtent();
       
  1075             }
       
  1076             double rads = Math.toRadians(-angle);
       
  1077             double xe = Math.cos(rads);
       
  1078             double ye = Math.sin(rads);
       
  1079             x1 = Math.min(x1, xe);
       
  1080             y1 = Math.min(y1, ye);
       
  1081             x2 = Math.max(x2, xe);
       
  1082             y2 = Math.max(y2, ye);
       
  1083         }
       
  1084         double w = getWidth();
       
  1085         double h = getHeight();
       
  1086         x2 = (x2 - x1) * 0.5 * w;
       
  1087         y2 = (y2 - y1) * 0.5 * h;
       
  1088         x1 = getX() + (x1 * 0.5 + 0.5) * w;
       
  1089         y1 = getY() + (y1 * 0.5 + 0.5) * h;
       
  1090         return makeBounds(x1, y1, x2, y2);
       
  1091     }
       
  1092 
       
  1093     /**
       
  1094      * Constructs a <code>Rectangle2D</code> of the appropriate precision
       
  1095      * to hold the parameters calculated to be the framing rectangle
       
  1096      * of this arc.
       
  1097      *
       
  1098      * @param x The X coordinate of the upper-left corner of the
       
  1099      * framing rectangle.
       
  1100      * @param y The Y coordinate of the upper-left corner of the
       
  1101      * framing rectangle.
       
  1102      * @param w The width of the framing rectangle.
       
  1103      * @param h The height of the framing rectangle.
       
  1104      * @return a <code>Rectangle2D</code> that is the framing rectangle
       
  1105      *     of this arc.
       
  1106      * @since 1.2
       
  1107      */
       
  1108     protected abstract Rectangle2D makeBounds(double x, double y,
       
  1109                                               double w, double h);
       
  1110 
       
  1111     /*
       
  1112      * Normalizes the specified angle into the range -180 to 180.
       
  1113      */
       
  1114     static double normalizeDegrees(double angle) {
       
  1115         if (angle > 180.0) {
       
  1116             if (angle <= (180.0 + 360.0)) {
       
  1117                 angle = angle - 360.0;
       
  1118             } else {
       
  1119                 angle = Math.IEEEremainder(angle, 360.0);
       
  1120                 // IEEEremainder can return -180 here for some input values...
       
  1121                 if (angle == -180.0) {
       
  1122                     angle = 180.0;
       
  1123                 }
       
  1124             }
       
  1125         } else if (angle <= -180.0) {
       
  1126             if (angle > (-180.0 - 360.0)) {
       
  1127                 angle = angle + 360.0;
       
  1128             } else {
       
  1129                 angle = Math.IEEEremainder(angle, 360.0);
       
  1130                 // IEEEremainder can return -180 here for some input values...
       
  1131                 if (angle == -180.0) {
       
  1132                     angle = 180.0;
       
  1133                 }
       
  1134             }
       
  1135         }
       
  1136         return angle;
       
  1137     }
       
  1138 
       
  1139     /**
       
  1140      * Determines whether or not the specified angle is within the
       
  1141      * angular extents of the arc.
       
  1142      *
       
  1143      * @param angle The angle to test.
       
  1144      *
       
  1145      * @return <CODE>true</CODE> if the arc contains the angle,
       
  1146      * <CODE>false</CODE> if the arc doesn't contain the angle.
       
  1147      * @since 1.2
       
  1148      */
       
  1149     public boolean containsAngle(double angle) {
       
  1150         double angExt = getAngleExtent();
       
  1151         boolean backwards = (angExt < 0.0);
       
  1152         if (backwards) {
       
  1153             angExt = -angExt;
       
  1154         }
       
  1155         if (angExt >= 360.0) {
       
  1156             return true;
       
  1157         }
       
  1158         angle = normalizeDegrees(angle) - normalizeDegrees(getAngleStart());
       
  1159         if (backwards) {
       
  1160             angle = -angle;
       
  1161         }
       
  1162         if (angle < 0.0) {
       
  1163             angle += 360.0;
       
  1164         }
       
  1165 
       
  1166 
       
  1167         return (angle >= 0.0) && (angle < angExt);
       
  1168     }
       
  1169 
       
  1170     /**
       
  1171      * Determines whether or not the specified point is inside the boundary
       
  1172      * of the arc.
       
  1173      *
       
  1174      * @param x The X coordinate of the point to test.
       
  1175      * @param y The Y coordinate of the point to test.
       
  1176      *
       
  1177      * @return <CODE>true</CODE> if the point lies within the bound of
       
  1178      * the arc, <CODE>false</CODE> if the point lies outside of the
       
  1179      * arc's bounds.
       
  1180      * @since 1.2
       
  1181      */
       
  1182     public boolean contains(double x, double y) {
       
  1183         // Normalize the coordinates compared to the ellipse
       
  1184         // having a center at 0,0 and a radius of 0.5.
       
  1185         double ellw = getWidth();
       
  1186         if (ellw <= 0.0) {
       
  1187             return false;
       
  1188         }
       
  1189         double normx = (x - getX()) / ellw - 0.5;
       
  1190         double ellh = getHeight();
       
  1191         if (ellh <= 0.0) {
       
  1192             return false;
       
  1193         }
       
  1194         double normy = (y - getY()) / ellh - 0.5;
       
  1195         double distSq = (normx * normx + normy * normy);
       
  1196         if (distSq >= 0.25) {
       
  1197             return false;
       
  1198         }
       
  1199         double angExt = Math.abs(getAngleExtent());
       
  1200         if (angExt >= 360.0) {
       
  1201             return true;
       
  1202         }
       
  1203         boolean inarc = containsAngle(-Math.toDegrees(Math.atan2(normy,
       
  1204                                                                  normx)));
       
  1205         if (type == PIE) {
       
  1206             return inarc;
       
  1207         }
       
  1208         // CHORD and OPEN behave the same way
       
  1209         if (inarc) {
       
  1210             if (angExt >= 180.0) {
       
  1211                 return true;
       
  1212             }
       
  1213             // point must be outside the "pie triangle"
       
  1214         } else {
       
  1215             if (angExt <= 180.0) {
       
  1216                 return false;
       
  1217             }
       
  1218             // point must be inside the "pie triangle"
       
  1219         }
       
  1220         // The point is inside the pie triangle iff it is on the same
       
  1221         // side of the line connecting the ends of the arc as the center.
       
  1222         double angle = Math.toRadians(-getAngleStart());
       
  1223         double x1 = Math.cos(angle);
       
  1224         double y1 = Math.sin(angle);
       
  1225         angle += Math.toRadians(-getAngleExtent());
       
  1226         double x2 = Math.cos(angle);
       
  1227         double y2 = Math.sin(angle);
       
  1228         boolean inside = (Line2D.relativeCCW(x1, y1, x2, y2, 2*normx, 2*normy) *
       
  1229                           Line2D.relativeCCW(x1, y1, x2, y2, 0, 0) >= 0);
       
  1230         return inarc ? !inside : inside;
       
  1231     }
       
  1232 
       
  1233     /**
       
  1234      * Determines whether or not the interior of the arc intersects
       
  1235      * the interior of the specified rectangle.
       
  1236      *
       
  1237      * @param x The X coordinate of the rectangle's upper-left corner.
       
  1238      * @param y The Y coordinate of the rectangle's upper-left corner.
       
  1239      * @param w The width of the rectangle.
       
  1240      * @param h The height of the rectangle.
       
  1241      *
       
  1242      * @return <CODE>true</CODE> if the arc intersects the rectangle,
       
  1243      * <CODE>false</CODE> if the arc doesn't intersect the rectangle.
       
  1244      * @since 1.2
       
  1245      */
       
  1246     public boolean intersects(double x, double y, double w, double h) {
       
  1247 
       
  1248         double aw = getWidth();
       
  1249         double ah = getHeight();
       
  1250 
       
  1251         if ( w <= 0 || h <= 0 || aw <= 0 || ah <= 0 ) {
       
  1252             return false;
       
  1253         }
       
  1254         double ext = getAngleExtent();
       
  1255         if (ext == 0) {
       
  1256             return false;
       
  1257         }
       
  1258 
       
  1259         double ax  = getX();
       
  1260         double ay  = getY();
       
  1261         double axw = ax + aw;
       
  1262         double ayh = ay + ah;
       
  1263         double xw  = x + w;
       
  1264         double yh  = y + h;
       
  1265 
       
  1266         // check bbox
       
  1267         if (x >= axw || y >= ayh || xw <= ax || yh <= ay) {
       
  1268             return false;
       
  1269         }
       
  1270 
       
  1271         // extract necessary data
       
  1272         double axc = getCenterX();
       
  1273         double ayc = getCenterY();
       
  1274         Point2D sp = getStartPoint();
       
  1275         Point2D ep = getEndPoint();
       
  1276         double sx = sp.getX();
       
  1277         double sy = sp.getY();
       
  1278         double ex = ep.getX();
       
  1279         double ey = ep.getY();
       
  1280 
       
  1281         /*
       
  1282          * Try to catch rectangles that intersect arc in areas
       
  1283          * outside of rectagle with left top corner coordinates
       
  1284          * (min(center x, start point x, end point x),
       
  1285          *  min(center y, start point y, end point y))
       
  1286          * and rigth bottom corner coordinates
       
  1287          * (max(center x, start point x, end point x),
       
  1288          *  max(center y, start point y, end point y)).
       
  1289          * So we'll check axis segments outside of rectangle above.
       
  1290          */
       
  1291         if (ayc >= y && ayc <= yh) { // 0 and 180
       
  1292             if ((sx < xw && ex < xw && axc < xw &&
       
  1293                  axw > x && containsAngle(0)) ||
       
  1294                 (sx > x && ex > x && axc > x &&
       
  1295                  ax < xw && containsAngle(180))) {
       
  1296                 return true;
       
  1297             }
       
  1298         }
       
  1299         if (axc >= x && axc <= xw) { // 90 and 270
       
  1300             if ((sy > y && ey > y && ayc > y &&
       
  1301                  ay < yh && containsAngle(90)) ||
       
  1302                 (sy < yh && ey < yh && ayc < yh &&
       
  1303                  ayh > y && containsAngle(270))) {
       
  1304                 return true;
       
  1305             }
       
  1306         }
       
  1307 
       
  1308         /*
       
  1309          * For PIE we should check intersection with pie slices;
       
  1310          * also we should do the same for arcs with extent is greater
       
  1311          * than 180, because we should cover case of rectangle, which
       
  1312          * situated between center of arc and chord, but does not
       
  1313          * intersect the chord.
       
  1314          */
       
  1315         Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
       
  1316         if (type == PIE || Math.abs(ext) > 180) {
       
  1317             // for PIE: try to find intersections with pie slices
       
  1318             if (rect.intersectsLine(axc, ayc, sx, sy) ||
       
  1319                 rect.intersectsLine(axc, ayc, ex, ey)) {
       
  1320                 return true;
       
  1321             }
       
  1322         } else {
       
  1323             // for CHORD and OPEN: try to find intersections with chord
       
  1324             if (rect.intersectsLine(sx, sy, ex, ey)) {
       
  1325                 return true;
       
  1326             }
       
  1327         }
       
  1328 
       
  1329         // finally check the rectangle corners inside the arc
       
  1330         if (contains(x, y) || contains(x + w, y) ||
       
  1331             contains(x, y + h) || contains(x + w, y + h)) {
       
  1332             return true;
       
  1333         }
       
  1334 
       
  1335         return false;
       
  1336     }
       
  1337 
       
  1338     /**
       
  1339      * Determines whether or not the interior of the arc entirely contains
       
  1340      * the specified rectangle.
       
  1341      *
       
  1342      * @param x The X coordinate of the rectangle's upper-left corner.
       
  1343      * @param y The Y coordinate of the rectangle's upper-left corner.
       
  1344      * @param w The width of the rectangle.
       
  1345      * @param h The height of the rectangle.
       
  1346      *
       
  1347      * @return <CODE>true</CODE> if the arc contains the rectangle,
       
  1348      * <CODE>false</CODE> if the arc doesn't contain the rectangle.
       
  1349      * @since 1.2
       
  1350      */
       
  1351     public boolean contains(double x, double y, double w, double h) {
       
  1352         return contains(x, y, w, h, null);
       
  1353     }
       
  1354 
       
  1355     /**
       
  1356      * Determines whether or not the interior of the arc entirely contains
       
  1357      * the specified rectangle.
       
  1358      *
       
  1359      * @param r The <CODE>Rectangle2D</CODE> to test.
       
  1360      *
       
  1361      * @return <CODE>true</CODE> if the arc contains the rectangle,
       
  1362      * <CODE>false</CODE> if the arc doesn't contain the rectangle.
       
  1363      * @since 1.2
       
  1364      */
       
  1365     public boolean contains(Rectangle2D r) {
       
  1366         return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight(), r);
       
  1367     }
       
  1368 
       
  1369     private boolean contains(double x, double y, double w, double h,
       
  1370                              Rectangle2D origrect) {
       
  1371         if (!(contains(x, y) &&
       
  1372               contains(x + w, y) &&
       
  1373               contains(x, y + h) &&
       
  1374               contains(x + w, y + h))) {
       
  1375             return false;
       
  1376         }
       
  1377         // If the shape is convex then we have done all the testing
       
  1378         // we need.  Only PIE arcs can be concave and then only if
       
  1379         // the angular extents are greater than 180 degrees.
       
  1380         if (type != PIE || Math.abs(getAngleExtent()) <= 180.0) {
       
  1381             return true;
       
  1382         }
       
  1383         // For a PIE shape we have an additional test for the case where
       
  1384         // the angular extents are greater than 180 degrees and all four
       
  1385         // rectangular corners are inside the shape but one of the
       
  1386         // rectangle edges spans across the "missing wedge" of the arc.
       
  1387         // We can test for this case by checking if the rectangle intersects
       
  1388         // either of the pie angle segments.
       
  1389         if (origrect == null) {
       
  1390             origrect = new Rectangle2D.Double(x, y, w, h);
       
  1391         }
       
  1392         double halfW = getWidth() / 2.0;
       
  1393         double halfH = getHeight() / 2.0;
       
  1394         double xc = getX() + halfW;
       
  1395         double yc = getY() + halfH;
       
  1396         double angle = Math.toRadians(-getAngleStart());
       
  1397         double xe = xc + halfW * Math.cos(angle);
       
  1398         double ye = yc + halfH * Math.sin(angle);
       
  1399         if (origrect.intersectsLine(xc, yc, xe, ye)) {
       
  1400             return false;
       
  1401         }
       
  1402         angle += Math.toRadians(-getAngleExtent());
       
  1403         xe = xc + halfW * Math.cos(angle);
       
  1404         ye = yc + halfH * Math.sin(angle);
       
  1405         return !origrect.intersectsLine(xc, yc, xe, ye);
       
  1406     }
       
  1407 
       
  1408     /**
       
  1409      * Returns an iteration object that defines the boundary of the
       
  1410      * arc.
       
  1411      * This iterator is multithread safe.
       
  1412      * <code>Arc2D</code> guarantees that
       
  1413      * modifications to the geometry of the arc
       
  1414      * do not affect any iterations of that geometry that
       
  1415      * are already in process.
       
  1416      *
       
  1417      * @param at an optional <CODE>AffineTransform</CODE> to be applied
       
  1418      * to the coordinates as they are returned in the iteration, or null
       
  1419      * if the untransformed coordinates are desired.
       
  1420      *
       
  1421      * @return A <CODE>PathIterator</CODE> that defines the arc's boundary.
       
  1422      * @since 1.2
       
  1423      */
       
  1424     public PathIterator getPathIterator(AffineTransform at) {
       
  1425         return new ArcIterator(this, at);
       
  1426     }
       
  1427 
       
  1428     /**
       
  1429      * Returns the hashcode for this <code>Arc2D</code>.
       
  1430      * @return the hashcode for this <code>Arc2D</code>.
       
  1431      * @since 1.6
       
  1432      */
       
  1433     public int hashCode() {
       
  1434         long bits = java.lang.Double.doubleToLongBits(getX());
       
  1435         bits += java.lang.Double.doubleToLongBits(getY()) * 37;
       
  1436         bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
       
  1437         bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
       
  1438         bits += java.lang.Double.doubleToLongBits(getAngleStart()) * 53;
       
  1439         bits += java.lang.Double.doubleToLongBits(getAngleExtent()) * 59;
       
  1440         bits += getArcType() * 61;
       
  1441         return (((int) bits) ^ ((int) (bits >> 32)));
       
  1442     }
       
  1443 
       
  1444     /**
       
  1445      * Determines whether or not the specified <code>Object</code> is
       
  1446      * equal to this <code>Arc2D</code>.  The specified
       
  1447      * <code>Object</code> is equal to this <code>Arc2D</code>
       
  1448      * if it is an instance of <code>Arc2D</code> and if its
       
  1449      * location, size, arc extents and type are the same as this
       
  1450      * <code>Arc2D</code>.
       
  1451      * @param obj  an <code>Object</code> to be compared with this
       
  1452      *             <code>Arc2D</code>.
       
  1453      * @return  <code>true</code> if <code>obj</code> is an instance
       
  1454      *          of <code>Arc2D</code> and has the same values;
       
  1455      *          <code>false</code> otherwise.
       
  1456      * @since 1.6
       
  1457      */
       
  1458     public boolean equals(Object obj) {
       
  1459         if (obj == this) {
       
  1460             return true;
       
  1461         }
       
  1462         if (obj instanceof Arc2D) {
       
  1463             Arc2D a2d = (Arc2D) obj;
       
  1464             return ((getX() == a2d.getX()) &&
       
  1465                     (getY() == a2d.getY()) &&
       
  1466                     (getWidth() == a2d.getWidth()) &&
       
  1467                     (getHeight() == a2d.getHeight()) &&
       
  1468                     (getAngleStart() == a2d.getAngleStart()) &&
       
  1469                     (getAngleExtent() == a2d.getAngleExtent()) &&
       
  1470                     (getArcType() == a2d.getArcType()));
       
  1471         }
       
  1472         return false;
       
  1473     }
       
  1474 }