KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > geom > Arc2D


1 /*
2  * @(#)Arc2D.java 1.27 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.geom;
9
10 /**
11  * <CODE>Arc2D</CODE> is the abstract superclass for all objects that
12  * store a 2D arc defined by a bounding rectangle,
13  * start angle, angular extent (length of the arc), and a closure type
14  * (<CODE>OPEN</CODE>, <CODE>CHORD</CODE>, or <CODE>PIE</CODE>).
15  * <p>
16  * The bounding rectangle defines the outer boundary of the full ellipse
17  * of which this arc is a partial section.
18  * The angles are specified relative to the non-square extents of the
19  * bounding rectangle such that 45 degrees always falls on the line from
20  * the center of the ellipse to the upper right corner of the bounding
21  * rectangle.
22  * As a result, if the bounding rectangle is noticeably longer along one
23  * axis than the other, the angles to the start and end of the arc segment
24  * will be skewed farther along the longer axis of the bounds.
25  * <p>
26  * The actual storage representation of the coordinates is left to
27  * the subclass.
28  *
29  * @version 10 Feb 1997
30  * @author Jim Graham
31  */

32 public abstract class Arc2D extends RectangularShape JavaDoc {
33     /**
34      * The closure type for an open arc with no path segments
35      * connecting the two ends of the arc segment.
36      */

37     public final static int OPEN = 0;
38
39     /**
40      * The closure type for an arc closed by drawing a straight
41      * line segment from the start of the arc segment to the end of the
42      * arc segment.
43      */

44     public final static int CHORD = 1;
45
46     /**
47      * The closure type for an arc closed by drawing straight line
48      * segments from the start of the arc segment to the center
49      * of the full ellipse and from that point to the end of the arc segment.
50      */

51     public final static int PIE = 2;
52
53     /**
54      * This class defines an arc specified in float precision.
55      */

56     public static class Float extends Arc2D JavaDoc {
57  
58         /**
59          * The x coordinate of the upper left corner of the arc.
60          */

61     public float x;
62
63         /**
64          * The y coordinate of the upper left corner of the arc.
65          */

66     public float y;
67
68         /**
69          * The overall width of the full ellipse of which this arc is
70          * a partial section (not considering the
71          * angular extents).
72          */

73     public float width;
74
75         /**
76          * The overall height of the full ellipse of which this arc is
77          * a partial section (not considering the
78          * angular extents).
79          */

80     public float height;
81
82         /**
83          * The starting angle of the arc in degrees.
84          */

85     public float start;
86
87         /**
88          * The angular extent of the arc in degrees.
89          */

90     public float extent;
91
92         /**
93          * Constructs a new OPEN arc, initialized to location (0, 0),
94          * size (0, 0), angular extents (start = 0, extent = 0).
95          */

96     public Float() {
97         super(OPEN);
98     }
99
100         /**
101          * Constructs a new arc, initialized to location (0, 0),
102          * size (0, 0), angular extents (start = 0, extent = 0), and
103          * the specified closure type.
104          *
105          * @param type The closure type for the arc:
106          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
107          */

108     public Float(int type) {
109         super(type);
110     }
111
112         /**
113          * Constructs a new arc, initialized to the specified location,
114          * size, angular extents, and closure type.
115          *
116          * @param x,&nbsp;y The coordinates of the upper left corner of
117          * the arc. (Specified in float precision.)
118          * @param w The overall width of the full ellipse of which
119          * this arc is a partial section. (Specified in float precision.)
120          * @param h The overall height of the full ellipse of which this
121          * arc is a partial section. (Specified in float precision.)
122          * @param start The starting angle of the arc in degrees.
123          * (Specified in float precision.)
124          * @param extent The angular extent of the arc in degrees.
125          * (Specified in float precision.)
126          * @param type The closure type for the arc:
127          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
128          */

129     public Float(float x, float y, float w, float h,
130              float start, float extent, int type) {
131         super(type);
132         this.x = x;
133         this.y = y;
134         this.width = w;
135         this.height = h;
136         this.start = start;
137         this.extent = extent;
138     }
139
140         /**
141          * Constructs a new arc, initialized to the specified location,
142          * size, angular extents, and closure type.
143          *
144          * @param ellipseBounds The bounding rectangle that defines the
145          * outer boundary of the full ellipse of which this arc is a
146          * partial section.
147          * @param start The starting angle of the arc in degrees.
148          * (Specified in float precision.)
149          * @param extent The angular extent of the arc in degrees.
150          * (Specified in float precision.)
151          * @param type The closure type for the arc:
152          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
153          */

154     public Float(Rectangle2D JavaDoc ellipseBounds,
155              float start, float extent, int type) {
156         super(type);
157         this.x = (float) ellipseBounds.getX();
158         this.y = (float) ellipseBounds.getY();
159         this.width = (float) ellipseBounds.getWidth();
160         this.height = (float) ellipseBounds.getHeight();
161         this.start = start;
162         this.extent = extent;
163     }
164
165         /**
166          * Returns the x coordinate of the upper left corner of the arc.
167          *
168          * @return The x coordinate of arc's upper left coordinate in
169          * double precision.
170          */

171     public double getX() {
172         return (double) x;
173     }
174
175         /**
176          * Returns the y coordinate of the upper left corner of the arc.
177          *
178          * @return The y coordinate of arc's upper left coordinate in
179          * double precision.
180          */

181     public double getY() {
182         return (double) y;
183     }
184
185         /**
186          * Returns the width of the ellipse of which this arc is
187          * a partial section.
188          *
189          * @return A double value that represents the width of the full
190          * ellipse of which this arc is a partial section.
191          */

192     public double getWidth() {
193         return (double) width;
194     }
195
196         /**
197          * Returns the height of the ellipse of which this arc is
198          * a partial section.
199          *
200          * @return A double value that represents the height of the full
201          * ellipse of which this arc is a partial section.
202          */

203     public double getHeight() {
204         return (double) height;
205     }
206
207         /**
208          * Returns the starting angle of the arc.
209          *
210          * @return A double value that represents the starting angle of
211          * the arc in degrees.
212      * @see #setAngleStart
213          */

214     public double getAngleStart() {
215         return (double) start;
216     }
217
218         /**
219          * Returns the angular extent of the arc.
220          *
221          * @return A double value that represents the angular extent of
222          * the arc in degrees.
223      * @see #setAngleExtent
224          */

225     public double getAngleExtent() {
226         return (double) extent;
227     }
228
229         /**
230          * Determines whether the arc is empty.
231          *
232          * @return <CODE>true</CODE> if the arc is empty, <CODE>false</CODE>
233          * if it is not.
234          */

235     public boolean isEmpty() {
236         return (width <= 0.0 || height <= 0.0);
237     }
238
239         /**
240          * Sets the location, size, angular extents, and closure type of
241          * this arc to the specified double values.
242          *
243          * @param x,&nbsp;y The coordinates of the upper left corner of
244          * the arc.
245          * @param w The overall width of the full ellipse of which this
246          * arc is a partial section.
247          * @param h The overall height of the full ellipse of which this
248          * arc is a partial section.
249          * @param angSt The starting angle of the arc in degrees.
250          * @param angExt The angular extent of the arc in degrees.
251          * @param closure The closure type for the arc:
252          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
253          */

254     public void setArc(double x, double y, double w, double h,
255                double angSt, double angExt, int closure) {
256         this.setArcType(closure);
257         this.x = (float) x;
258         this.y = (float) y;
259         this.width = (float) w;
260         this.height = (float) h;
261         this.start = (float) angSt;
262         this.extent = (float) angExt;
263     }
264
265         /**
266          * Sets the starting angle of this arc to the specified double
267          * value.
268          *
269          * @param angSt The starting angle of the arc in degrees.
270      * @see #getAngleStart
271          */

272     public void setAngleStart(double angSt) {
273         this.start = (float) angSt;
274     }
275
276         /**
277          * Sets the angular extent of this arc to the specified double
278          * value.
279          *
280          * @param angExt The angular extent of the arc in degrees.
281      * @see #getAngleExtent
282          */

283     public void setAngleExtent(double angExt) {
284         this.extent = (float) angExt;
285     }
286
287         /**
288          * Return the high-precision bounding box of the arc.
289          *
290          * @param x,&nbsp;y The coordinates of the upper left corner
291          * of the arc.
292          * @param w The overall width of the full ellipse of which
293          * this arc is a partial section.
294          * @param h The overall height of the full ellipse of which
295          * this arc is a partial section.
296          *
297          * @return The bounding box as a <CODE>Rectangle2D</CODE> object.
298          */

299     protected Rectangle2D JavaDoc makeBounds(double x, double y,
300                      double w, double h) {
301         return new Rectangle2D.Float JavaDoc((float) x, (float) y,
302                      (float) w, (float) h);
303     }
304     }
305
306     /**
307      * This class defines an arc specified in double precision.
308      */

309     public static class Double extends Arc2D JavaDoc {
310         /**
311          * The x coordinate of the upper left corner of the arc.
312          */

313     public double x;
314
315         /**
316          * The y coordinate of the upper left corner of the arc.
317          */

318     public double y;
319
320         /**
321          * The overall width of the full ellipse (not considering the
322          * angular extents).
323          */

324     public double width;
325
326         /**
327          * The overall height of the full ellipse (not considering the
328          * angular extents).
329          */

330     public double height;
331
332         /**
333          * The starting angle of the arc in degrees.
334          */

335     public double start;
336
337         /**
338          * The angular extent of the arc in degrees.
339          */

340     public double extent;
341
342         /**
343          * Constructs a new OPEN arc, initialized to location (0, 0),
344          * size (0, 0), angular extents (start = 0, extent = 0).
345          */

346     public Double() {
347         super(OPEN);
348     }
349
350         /**
351          * Constructs a new arc, initialized to location (0, 0),
352          * size (0, 0), angular extents (start = 0, extent = 0), and
353          * the specified closure type.
354          *
355          * @param type The closure type for the arc:
356          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
357          */

358     public Double(int type) {
359         super(type);
360     }
361
362         /**
363          * Constructs a new arc, initialized to the specified location,
364          * size, angular extents, and closure type.
365          *
366          * @param x,&nbsp;y The coordinates of the upper left corner
367          * of the arc. (Specified in double precision.)
368          * @param w The overall width of the full ellipse of which this
369          * arc is a partial section. (Specified in double precision.)
370          * @param h The overall height of the full ellipse of which this
371          * arc is a partial section. (Specified in double precision.)
372          * @param start The starting angle of the arc in degrees.
373          * (Specified in double precision.)
374          * @param extent The angular extent of the arc in degrees.
375          * (Specified in double precision.)
376          * @param type The closure type for the arc:
377          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
378          */

379     public Double(double x, double y, double w, double h,
380               double start, double extent, int type) {
381         super(type);
382         this.x = x;
383         this.y = y;
384         this.width = w;
385         this.height = h;
386         this.start = start;
387         this.extent = extent;
388     }
389
390         /**
391          * Constructs a new arc, initialized to the specified location,
392          * size, angular extents, and closure type.
393          *
394          * @param ellipseBounds The bounding rectangle that defines the
395          * outer boundary of the full ellipse of which this arc is a
396          * partial section.
397          * @param start The starting angle of the arc in degrees.
398          * (Specified in double precision.)
399          * @param extent The angular extent of the arc in degrees.
400          * (Specified in double precision.)
401          * @param type The closure type for the arc:
402          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
403          */

404     public Double(Rectangle2D JavaDoc ellipseBounds,
405               double start, double extent, int type) {
406         super(type);
407         this.x = ellipseBounds.getX();
408         this.y = ellipseBounds.getY();
409         this.width = ellipseBounds.getWidth();
410         this.height = ellipseBounds.getHeight();
411         this.start = start;
412         this.extent = extent;
413     }
414
415         /**
416          * Returns the x coordinate of the upper left corner of the arc.
417          *
418          * @return The x coordinate of arc's upper left coordinate in
419          * double precision.
420          */

421     public double getX() {
422         return x;
423     }
424
425         /**
426          * Returns the y coordinate of the upper left corner of the arc.
427          *
428          * @return The y coordinate of arc's upper left coordinate in
429          * double precision.
430          */

431     public double getY() {
432         return y;
433     }
434
435         /**
436          * Returns the width of the ellipse of which this arc is
437          * a partial section.
438          *
439          * @return A double value that represents the width of the full
440          * ellipse of which this arc is a partial section.
441          */

442     public double getWidth() {
443         return width;
444     }
445
446         /**
447          * Returns the height of the ellipse of which this arc is
448          * a partial section.
449          *
450          * @return A double value that represents the height of the full
451          * ellipse of which this arc is a partial section.
452          */

453     public double getHeight() {
454         return height;
455     }
456
457         /**
458          * Returns the starting angle of the arc.
459          *
460          * @return a double value that represents the starting angle
461          * of the arc in degrees.
462      * @see #setAngleStart
463          */

464     public double getAngleStart() {
465         return start;
466     }
467
468         /**
469          * Returns the angular extent of the arc.
470          *
471          * @return A double value that represents the angular extent of
472          * the arc in degrees.
473      * @see #setAngleExtent
474          */

475     public double getAngleExtent() {
476         return extent;
477     }
478
479         /**
480          * Determines whether the arc is empty.
481          *
482          * @return <CODE>true</CODE> if the arc is empty, <CODE>false</CODE>
483          * if it not.
484          */

485     public boolean isEmpty() {
486         return (width <= 0.0 || height <= 0.0);
487     }
488
489         /**
490          * Sets the location, size, angular extents, and closure type of
491          * this arc to the specified double values.
492          *
493          * @param x,&nbsp;y The coordinates of the upper left corner
494          * of the arc.
495          * @param w The overall width of the full ellipse of which
496          * this arc is a partial section.
497          * @param h The overall height of the full ellipse of which
498          * this arc is a partial section.
499          * @param angSt The starting angle of the arc in degrees.
500          * @param angExt The angular extent of the arc in degrees.
501          * @param closure The closure type for the arc:
502          * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
503          */

504     public void setArc(double x, double y, double w, double h,
505                double angSt, double angExt, int closure) {
506         this.setArcType(closure);
507         this.x = x;
508         this.y = y;
509         this.width = w;
510         this.height = h;
511         this.start = angSt;
512         this.extent = angExt;
513     }
514
515         /**
516          * Sets the starting angle of this arc to the specified double
517          * value.
518          *
519          * @param angSt The starting angle of the arc in degrees.
520      * @see #getAngleStart
521          */

522     public void setAngleStart(double angSt) {
523         this.start = angSt;
524     }
525
526         /**
527          * Sets the angular extent of this arc to the specified double
528          * value.
529          *
530          * @param angExt The angular extent of the arc in degrees.
531      * @see #getAngleExtent
532          */

533     public void setAngleExtent(double angExt) {
534         this.extent = angExt;
535     }
536
537         /**
538          * Returns the high-precision bounding box of the arc.
539          *
540          * @param x,&nbsp;y The coordinates of the upper left corner
541          * of the arc.
542          * @param w The overall width of the full ellipse of which
543          * this arc is a partial section.
544          * @param h The overall height of the full ellipse of which
545          * this arc is a partial section.
546          *
547          * @return The bounding box as a <CODE>Rectangle2D</CODE> object.
548          */

549     protected Rectangle2D JavaDoc makeBounds(double x, double y,
550                      double w, double h) {
551         return new Rectangle2D.Double JavaDoc(x, y, w, h);
552     }
553     }
554
555     private int type;
556
557     /**
558      * This is an abstract class that cannot be instantiated directly.
559      * Type-specific implementation subclasses are available for
560      * instantiation and provide a number of formats for storing
561      * the information necessary to satisfy the various accessor
562      * methods below.
563      *
564      * @param type The closure type of this arc:
565      * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
566      * @see java.awt.geom.Arc2D.Float
567      * @see java.awt.geom.Arc2D.Double
568      */

569     protected Arc2D(int type) {
570     setArcType(type);
571     }
572
573     /**
574      * Returns the starting angle of the arc.
575      *
576      * @return A double value that represents the starting angle
577      * of the arc in degrees.
578      * @see #setAngleStart
579      */

580     public abstract double getAngleStart();
581
582     /**
583      * Returns the angular extent of the arc.
584      *
585      * @return A double value that represents the angular extent
586      * of the arc in degrees.
587      * @see #setAngleExtent
588      */

589     public abstract double getAngleExtent();
590
591     /**
592      * Returns the arc closure type of the arc: {@link #OPEN OPEN},
593      * {@link #CHORD CHORD}, or {@link #PIE PIE}.
594      * @return One of the integer constant closure types defined
595      * in this class.
596      * @see #setArcType
597      */

598     public int getArcType() {
599     return type;
600     }
601
602     /**
603      * Returns the starting point of the arc. This point is the
604      * intersection of the ray from the center defined by the
605      * starting angle and the elliptical boundary of the arc.
606      *
607      * @return A <CODE>Point2D</CODE> object representing the
608      * x,y coordinates of the starting point of the arc.
609      */

610     public Point2D JavaDoc getStartPoint() {
611     double angle = Math.toRadians(-getAngleStart());
612     double x = getX() + (Math.cos(angle) * 0.5 + 0.5) * getWidth();
613     double y = getY() + (Math.sin(angle) * 0.5 + 0.5) * getHeight();
614     return new Point2D.Double JavaDoc(x, y);
615     }
616
617     /**
618      * Returns the ending point of the arc. This point is the
619      * intersection of the ray from the center defined by the
620      * starting angle plus the angular extent of the arc and the
621      * elliptical boundary of the arc.
622      *
623      * @return A <CODE>Point2D</CODE> object representing the
624      * x,y coordinates of the ending point of the arc.
625      */

626     public Point2D JavaDoc getEndPoint() {
627     double angle = Math.toRadians(-getAngleStart() - getAngleExtent());
628     double x = getX() + (Math.cos(angle) * 0.5 + 0.5) * getWidth();
629     double y = getY() + (Math.sin(angle) * 0.5 + 0.5) * getHeight();
630     return new Point2D.Double JavaDoc(x, y);
631     }
632
633     /**
634      * Sets the location, size, angular extents, and closure type of
635      * this arc to the specified double values.
636      *
637      * @param x,&nbsp;y The coordinates of the upper left corner of
638      * the arc.
639      * @param w The overall width of the full ellipse of which
640      * this arc is a partial section.
641      * @param h The overall height of the full ellipse of which
642      * this arc is a partial section.
643      * @param angSt The starting angle of the arc in degrees.
644      * @param angExt The angular extent of the arc in degrees.
645      * @param closure The closure type for the arc:
646      * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
647      */

648     public abstract void setArc(double x, double y, double w, double h,
649                 double angSt, double angExt, int closure);
650
651     /**
652      * Sets the location, size, angular extents, and closure type of
653      * this arc to the specified values.
654      *
655      * @param loc The <CODE>Point2D</CODE> representing the coordinates of
656      * the upper left corner of the arc.
657      * @param size The <CODE>Dimension2D</CODE> representing the width
658      * and height of the full ellipse of which this arc is
659      * a partial section.
660      * @param angSt The starting angle of the arc in degrees.
661      * (Specified in double precision.)
662      * @param angExt The angular extent of the arc in degrees.
663      * (Specified in double precision.)
664      * @param closure The closure type for the arc:
665      * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
666      */

667     public void setArc(Point2D JavaDoc loc, Dimension2D JavaDoc size,
668                double angSt, double angExt, int closure) {
669     setArc(loc.getX(), loc.getY(), size.getWidth(), size.getHeight(),
670            angSt, angExt, closure);
671     }
672
673     /**
674      * Sets the location, size, angular extents, and closure type of
675      * this arc to the specified values.
676      *
677      * @param rect The bounding rectangle that defines the
678      * outer boundary of the full ellipse of which this arc is a
679      * partial section.
680      * @param angSt The starting angle of the arc in degrees.
681      * (Specified in double precision.)
682      * @param angExt The angular extent of the arc in degrees.
683      * (Specified in double precision.)
684      * @param closure The closure type for the arc:
685      * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
686      */

687     public void setArc(Rectangle2D JavaDoc rect, double angSt, double angExt,
688                int closure) {
689     setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(),
690            angSt, angExt, closure);
691     }
692
693     /**
694      * Sets this arc to be the same as the specified arc.
695      *
696      * @param a The <CODE>Arc2D</CODE> to use to set the arc's values.
697      */

698     public void setArc(Arc2D JavaDoc a) {
699     setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(),
700            a.getAngleStart(), a.getAngleExtent(), a.type);
701     }
702
703     /**
704      * Sets the position, bounds, angular extents, and closure type of
705      * this arc to the specified values. The arc is defined by a center
706      * point and a radius rather than a bounding box for the full ellipse.
707      *
708      * @param x,&nbsp;y The coordinates of the center of the arc.
709      * (Specified in double precision.)
710      * @param radius The radius of the arc. (Specified in double precision.)
711      * @param angSt The starting angle of the arc in degrees.
712      * (Specified in double precision.)
713      * @param angExt The angular extent of the arc in degrees.
714      * (Specified in double precision.)
715      * @param closure The closure type for the arc:
716      * {@link #OPEN OPEN}, {@link #CHORD CHORD}, or {@link #PIE PIE}.
717      */

718     public void setArcByCenter(double x, double y, double radius,
719                    double angSt, double angExt, int closure) {
720     setArc(x - radius, y - radius, radius * 2.0, radius * 2.0,
721            angSt, angExt, closure);
722     }
723
724     /**
725      * Sets the position, bounds, and angular extents of this arc to the
726      * specified value. The starting angle of the arc is tangent to the
727      * line specified by points (p1, p2), the ending angle is tangent to
728      * the line specified by points (p2, p3), and the arc has the
729      * specified radius.
730      *
731      * @param p1 The first point that defines the arc. The starting
732      * angle of the arc is tangent to the line specified by points (p1, p2).
733      * @param p2 The second point that defines the arc. The starting
734      * angle of the arc is tangent to the line specified by points (p1, p2).
735      * The ending angle of the arc is tangent to the line specified by
736      * points (p2, p3).
737      * @param p3 The third point that defines the arc. The ending angle
738      * of the arc is tangent to the line specified by points (p2, p3).
739      * @param radius The radius of the arc. (Specified in double precision.)
740      */

741     public void setArcByTangent(Point2D JavaDoc p1, Point2D JavaDoc p2, Point2D JavaDoc p3,
742                 double radius) {
743     double ang1 = Math.atan2(p1.getY() - p2.getY(),
744                  p1.getX() - p2.getX());
745     double ang2 = Math.atan2(p3.getY() - p2.getY(),
746                  p3.getX() - p2.getX());
747     double diff = ang2 - ang1;
748     if (diff > Math.PI) {
749         ang2 -= Math.PI * 2.0;
750     } else if (diff < -Math.PI) {
751         ang2 += Math.PI * 2.0;
752     }
753     double bisect = (ang1 + ang2) / 2.0;
754     double theta = Math.abs(ang2 - bisect);
755     double dist = radius / Math.sin(theta);
756     double x = p2.getX() + dist * Math.cos(bisect);
757     double y = p2.getY() + dist * Math.sin(bisect);
758     // REMIND: This needs some work...
759
if (ang1 < ang2) {
760         ang1 -= Math.PI / 2.0;
761         ang2 += Math.PI / 2.0;
762     } else {
763         ang1 += Math.PI / 2.0;
764         ang2 -= Math.PI / 2.0;
765     }
766     ang1 = Math.toDegrees(-ang1);
767     ang2 = Math.toDegrees(-ang2);
768     diff = ang2 - ang1;
769     if (diff < 0) {
770         diff += 360;
771     } else {
772         diff -= 360;
773     }
774     setArcByCenter(x, y, radius, ang1, diff, type);
775     }
776
777     /**
778      * Sets the starting angle of this arc to the specified double
779      * value.
780      *
781      * @param angSt The starting angle of the arc in degrees.
782      * @see #getAngleStart
783      */

784     public abstract void setAngleStart(double angSt);
785
786     /**
787      * Sets the angular extent of this arc to the specified double
788      * value.
789      *
790      * @param angExt The angular extent of the arc in degrees.
791      * @see #getAngleExtent
792      */

793     public abstract void setAngleExtent(double angExt);
794
795     /**
796      * Sets the starting angle of this arc to the angle that the
797      * specified point defines relative to the center of this arc.
798      * The angular extent of the arc will remain the same.
799      *
800      * @param p The <CODE>Point2D</CODE> that defines the starting angle.
801      * @see #getAngleStart
802      */

803     public void setAngleStart(Point2D JavaDoc p) {
804     // Bias the dx and dy by the height and width of the oval.
805
double dx = getHeight() * (p.getX() - getCenterX());
806     double dy = getWidth() * (p.getY() - getCenterY());
807     setAngleStart(-Math.toDegrees(Math.atan2(dy, dx)));
808     }
809
810     /**
811      * Sets the starting angle and angular extent of this arc using two
812      * sets of coordinates. The first set of coordinates is used to
813      * determine the angle of the starting point relative to the arc's
814      * center. The second set of coordinates is used to determine the
815      * angle of the end point relative to the arc's center.
816      * The arc will always be non-empty and extend counterclockwise
817      * from the first point around to the second point.
818      *
819      * @param x1,&nbsp;y1 The coordinates of the arc's starting point.
820      * @param x2,&nbsp;y2 The coordinates of the arc's ending point.
821      */

822     public void setAngles(double x1, double y1, double x2, double y2) {
823     double x = getCenterX();
824     double y = getCenterY();
825     double w = getWidth();
826     double h = getHeight();
827     // Note: reversing the Y equations negates the angle to adjust
828
// for the upside down coordinate system.
829
// Also we should bias atans by the height and width of the oval.
830
double ang1 = Math.atan2(w * (y - y1), h * (x1 - x));
831     double ang2 = Math.atan2(w * (y - y2), h * (x2 - x));
832     ang2 -= ang1;
833     if (ang2 <= 0.0) {
834         ang2 += Math.PI * 2.0;
835     }
836     setAngleStart(Math.toDegrees(ang1));
837     setAngleExtent(Math.toDegrees(ang2));
838     }
839
840     /**
841      * Sets the starting angle and angular extent of this arc using
842      * two points. The first point is used to determine the angle of
843      * the starting point relative to the arc's center.
844      * The second point is used to determine the angle of the end point
845      * relative to the arc's center.
846      * The arc will always be non-empty and extend counterclockwise
847      * from the first point around to the second point.
848      *
849      * @param p1 The <CODE>Point2D</CODE> that defines the arc's
850      * starting point.
851      * @param p2 The <CODE>Point2D</CODE> that defines the arc's
852      * ending point.
853      */

854     public void setAngles(Point2D JavaDoc p1, Point2D JavaDoc p2) {
855     setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY());
856     }
857
858     /**
859      * Sets the closure type of this arc to the specified value:
860      * <CODE>OPEN</CODE>, <CODE>CHORD</CODE>, or <CODE>PIE</CODE>.
861      *
862      * @param type The integer constant that represents the closure
863      * type of this arc: {@link #OPEN}, {@link #CHORD}, or
864      * {@link #PIE}.
865      *
866      * @throws IllegalArgumentException if <code>type</code> is not
867      * 0, 1, or 2.+
868      * @see #getArcType
869      */

870     public void setArcType(int type) {
871     if (type < OPEN || type > PIE) {
872         throw new IllegalArgumentException JavaDoc("invalid type for Arc: "+type);
873     }
874     this.type = type;
875     }
876
877     /**
878      * Sets the location and size of the outer bounds of this arc
879      * to the specified values.
880      *
881      * @param x,&nbsp;y The coordinates of the upper left corner of the
882      * arc's bounding box. (Specified in double precision.)
883      * @param w The width of the arc's bounding box. (Specified in
884      * double precision.)
885      * @param h The height of the arc's bounding box. (Specified in
886      * double precision.)
887      */

888     public void setFrame(double x, double y, double w, double h) {
889     setArc(x, y, w, h, getAngleStart(), getAngleExtent(), type);
890     }
891
892     /**
893      * Returns the high-precision bounding box of the arc. The bounding
894      * box contains only the part of this <code>Arc2D</code> that is
895      * in between the starting and ending angles and contains the pie
896      * wedge, if this <code>Arc2D</code> has a <code>PIE</code> closure type.
897      * <p>
898      * This method differs from the
899      * {@link RectangularShape#getBounds() getBounds} in that the
900      * <code>getBounds</code> method only returns the bounds of the
901      * enclosing ellipse of this <code>Arc2D</code> without considering
902      * the starting and ending angles of this <code>Arc2D</code>.
903      *
904      * @return the <CODE>Rectangle2D</CODE> that represents the arc's
905      * bounding box.
906      */

907     public Rectangle2D JavaDoc getBounds2D() {
908     if (isEmpty()) {
909         return makeBounds(getX(), getY(), getWidth(), getHeight());
910     }
911     double x1, y1, x2, y2;
912     if (getArcType() == PIE) {
913         x1 = y1 = x2 = y2 = 0.0;
914     } else {
915         x1 = y1 = 1.0;
916         x2 = y2 = -1.0;
917     }
918     double angle = 0.0;
919     for (int i = 0; i < 6; i++) {
920         if (i < 4) {
921         // 0-3 are the four quadrants
922
angle += 90.0;
923         if (!containsAngle(angle)) {
924             continue;
925         }
926         } else if (i == 4) {
927         // 4 is start angle
928
angle = getAngleStart();
929         } else {
930         // 5 is end angle
931
angle += getAngleExtent();
932         }
933         double rads = Math.toRadians(-angle);
934         double xe = Math.cos(rads);
935         double ye = Math.sin(rads);
936         x1 = Math.min(x1, xe);
937         y1 = Math.min(y1, ye);
938         x2 = Math.max(x2, xe);
939         y2 = Math.max(y2, ye);
940     }
941     double w = getWidth();
942     double h = getHeight();
943     x2 = (x2 - x1) * 0.5 * w;
944     y2 = (y2 - y1) * 0.5 * h;
945     x1 = getX() + (x1 * 0.5 + 0.5) * w;
946     y1 = getY() + (y1 * 0.5 + 0.5) * h;
947     return makeBounds(x1, y1, x2, y2);
948     }
949
950     /**
951      * Constructs a <code>Rectangle2D</code> of the appropriate precision
952      * to hold the parameters calculated to be the bounding box
953      * of this arc.
954      *
955      * @param x,&nbsp;y The coordinates of the upper left corner of the
956      * bounding box. (Specified in double precision.)
957      * @param w The width of the bounding box. (Specified in
958      * double precision.)
959      * @param h The height of the bounding box. (Specified in
960      * double precision.)
961      * @return a <code>Rectangle2D</code> that is the bounding box
962      * of this arc.
963      */

964     protected abstract Rectangle2D JavaDoc makeBounds(double x, double y,
965                           double w, double h);
966
967     /*
968      * Normalizes the specified angle into the range -180 to 180.
969      */

970     static double normalizeDegrees(double angle) {
971     if (angle > 180.0) {
972         if (angle <= (180.0 + 360.0)) {
973         angle = angle - 360.0;
974         } else {
975         angle = Math.IEEEremainder(angle, 360.0);
976         // IEEEremainder can return -180 here for some input values...
977
if (angle == -180.0) {
978             angle = 180.0;
979         }
980         }
981     } else if (angle <= -180.0) {
982         if (angle > (-180.0 - 360.0)) {
983         angle = angle + 360.0;
984         } else {
985         angle = Math.IEEEremainder(angle, 360.0);
986         // IEEEremainder can return -180 here for some input values...
987
if (angle == -180.0) {
988             angle = 180.0;
989         }
990         }
991     }
992     return angle;
993     }
994
995     /**
996      * Determines whether or not the specified angle is within the
997      * angular extents of the arc.
998      *
999      * @param angle The angle to test. (Specified in double precision.)
1000     *
1001     * @return <CODE>true</CODE> if the arc contains the angle,
1002     * <CODE>false</CODE> if the arc doesn't contain the angle.
1003     */

1004    public boolean containsAngle(double angle) {
1005    double angExt = getAngleExtent();
1006    boolean backwards = (angExt < 0.0);
1007    if (backwards) {
1008        angExt = -angExt;
1009    }
1010    if (angExt >= 360.0) {
1011        return true;
1012    }
1013    angle = normalizeDegrees(angle) - normalizeDegrees(getAngleStart());
1014    if (backwards) {
1015        angle = -angle;
1016    }
1017    if (angle < 0.0) {
1018        angle += 360.0;
1019    }
1020
1021      
1022    return (angle >= 0.0) && (angle < angExt);
1023    }
1024
1025    /**
1026     * Determines whether or not the specified point is inside the boundary
1027     * of the arc.
1028     *
1029     * @param x,&nbsp;y The coordinates of the point to test. (Specified in
1030     * double precision.)
1031     *
1032     * @return <CODE>true</CODE> if the point lies within the bound of
1033     * the arc, <CODE>false</CODE> if the point lies outside of the
1034     * arc's bounds.
1035     */

1036    public boolean contains(double x, double y) {
1037    // Normalize the coordinates compared to the ellipse
1038
// having a center at 0,0 and a radius of 0.5.
1039
double ellw = getWidth();
1040    if (ellw <= 0.0) {
1041        return false;
1042    }
1043    double normx = (x - getX()) / ellw - 0.5;
1044    double ellh = getHeight();
1045    if (ellh <= 0.0) {
1046        return false;
1047    }
1048    double normy = (y - getY()) / ellh - 0.5;
1049    double distSq = (normx * normx + normy * normy);
1050    if (distSq >= 0.25) {
1051        return false;
1052    }
1053    double angExt = Math.abs(getAngleExtent());
1054    if (angExt >= 360.0) {
1055        return true;
1056    }
1057    boolean inarc = containsAngle(-Math.toDegrees(Math.atan2(normy,
1058                                 normx)));
1059    if (type == PIE) {
1060        return inarc;
1061    }
1062    // CHORD and OPEN behave the same way
1063
if (inarc) {
1064        if (angExt >= 180.0) {
1065        return true;
1066        }
1067        // point must be outside the "pie triangle"
1068
} else {
1069        if (angExt <= 180.0) {
1070        return false;
1071        }
1072        // point must be inside the "pie triangle"
1073
}
1074    // The point is inside the pie triangle iff it is on the same
1075
// side of the line connecting the ends of the arc as the center.
1076
double angle = Math.toRadians(-getAngleStart());
1077    double x1 = Math.cos(angle);
1078    double y1 = Math.sin(angle);
1079    angle += Math.toRadians(-getAngleExtent());
1080    double x2 = Math.cos(angle);
1081    double y2 = Math.sin(angle);
1082    boolean inside = (Line2D.relativeCCW(x1, y1, x2, y2, 2*normx, 2*normy) *
1083              Line2D.relativeCCW(x1, y1, x2, y2, 0, 0) >= 0);
1084    return inarc ? !inside : inside;
1085    }
1086
1087    /**
1088     * Determines whether or not the interior of the arc intersects
1089     * the interior of the specified rectangle.
1090     *
1091     * @param x,&nbsp;y The coordinates of the rectangle's upper left corner.
1092     * (Specified in double precision.)
1093     * @param w The width of the rectangle. (Specified in double precision.)
1094     * @param h The height of the rectangle. (Specified in double precision.)
1095     *
1096     * @return <CODE>true</CODE> if the arc intersects the rectangle,
1097     * <CODE>false</CODE> if the arc doesn't intersect the rectangle.
1098     */

1099
1100    public boolean intersects(double x, double y, double w, double h) {
1101
1102    double aw = getWidth();
1103    double ah = getHeight();
1104
1105    if ( w <= 0 || h <= 0 || aw <= 0 || ah <= 0 ) {
1106        return false;
1107    }
1108    double ext = getAngleExtent();
1109    if (ext == 0) {
1110        return false;
1111    }
1112
1113    double ax = getX();
1114    double ay = getY();
1115    double axw = ax + aw;
1116    double ayh = ay + ah;
1117    double xw = x + w;
1118    double yh = y + h;
1119
1120    // check bbox
1121
if (x >= axw || y >= ayh || xw <= ax || yh <= ay) {
1122        return false;
1123    }
1124
1125    // extract necessary data
1126
double axc = getCenterX();
1127    double ayc = getCenterY();
1128    Point2D JavaDoc sp = getStartPoint();
1129    Point2D JavaDoc ep = getEndPoint();
1130    double sx = sp.getX();
1131    double sy = sp.getY();
1132    double ex = ep.getX();
1133    double ey = ep.getY();
1134
1135    /*
1136     * Try to catch rectangles that intersect arc in areas
1137     * outside of rectagle with left top corner coordinates
1138     * (min(center x, start point x, end point x),
1139     * min(center y, start point y, end point y))
1140     * and rigth bottom corner coordinates
1141     * (max(center x, start point x, end point x),
1142     * max(center y, start point y, end point y)).
1143     * So we'll check axis segments outside of rectangle above.
1144     */

1145    if (ayc >= y && ayc <= yh) { // 0 and 180
1146
if ((sx < xw && ex < xw && axc < xw &&
1147             axw > x && containsAngle(0)) ||
1148            (sx > x && ex > x && axc > x &&
1149             ax < xw && containsAngle(180))) {
1150        return true;
1151        }
1152    }
1153    if (axc >= x && axc <= xw) { // 90 and 270
1154
if ((sy > y && ey > y && ayc > y &&
1155             ay < yh && containsAngle(90)) ||
1156            (sy < yh && ey < yh && ayc < yh &&
1157             ayh > y && containsAngle(270))) {
1158        return true;
1159        }
1160    }
1161
1162    /*
1163     * For PIE we should check intersection with pie slices;
1164     * also we should do the same for arcs with extent is greater
1165     * than 180, because we should cover case of rectangle, which
1166     * situated between center of arc and chord, but does not
1167     * intersect the chord.
1168     */

1169    Rectangle2D JavaDoc rect = new Rectangle2D.Double JavaDoc(x, y, w, h);
1170    if (type == PIE || Math.abs(ext) > 180) {
1171        // for PIE: try to find intersections with pie slices
1172
if (rect.intersectsLine(axc, ayc, sx, sy) ||
1173        rect.intersectsLine(axc, ayc, ex, ey)) {
1174        return true;
1175        }
1176    } else {
1177        // for CHORD and OPEN: try to find intersections with chord
1178
if (rect.intersectsLine(sx, sy, ex, ey)) {
1179        return true;
1180        }
1181    }
1182
1183    // finally check the rectangle corners inside the arc
1184
if (contains(x, y) || contains(x + w, y) ||
1185        contains(x, y + h) || contains(x + w, y + h)) {
1186        return true;
1187    }
1188
1189    return false;
1190    }
1191
1192    /**
1193     * Determine whether or not the interior of the arc entirely contains
1194     * the specified rectangle.
1195     *
1196     * @param x,&nbsp;y The coordinates of the rectangle's upper left corner.
1197     * (Specified in double precision.)
1198     * @param w The width of the rectangle. (Specified in double precision.)
1199     * @param h The height of the rectangle. (Specified in double precision.)
1200     *
1201     * @return <CODE>true</CODE> if the arc contains the rectangle,
1202     * <CODE>false</CODE> if the arc doesn't contain the rectangle.
1203     */

1204    public boolean contains(double x, double y, double w, double h) {
1205    return contains(x, y, w, h, null);
1206    }
1207
1208    /**
1209     * Determine whether or not the interior of the arc entirely contains
1210     * the specified rectangle.
1211     *
1212     * @param r The <CODE>Rectangle2D</CODE> to test.
1213     *
1214     * @return <CODE>true</CODE> if the arc contains the rectangle,
1215     * <CODE>false</CODE> if the arc doesn't contain the rectangle.
1216     */

1217    public boolean contains(Rectangle2D JavaDoc r) {
1218    return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight(), r);
1219    }
1220
1221    private boolean contains(double x, double y, double w, double h,
1222                 Rectangle2D JavaDoc origrect) {
1223    if (!(contains(x, y) &&
1224          contains(x + w, y) &&
1225          contains(x, y + h) &&
1226          contains(x + w, y + h))) {
1227        return false;
1228    }
1229    // If the shape is convex then we have done all the testing
1230
// we need. Only PIE arcs can be concave and then only if
1231
// the angular extents are greater than 180 degrees.
1232
if (type != PIE || Math.abs(getAngleExtent()) <= 180.0) {
1233        return true;
1234    }
1235    // For a PIE shape we have an additional test for the case where
1236
// the angular extents are greater than 180 degrees and all four
1237
// rectangular corners are inside the shape but one of the
1238
// rectangle edges spans across the "missing wedge" of the arc.
1239
// We can test for this case by checking if the rectangle intersects
1240
// either of the pie angle segments.
1241
if (origrect == null) {
1242        origrect = new Rectangle2D.Double JavaDoc(x, y, w, h);
1243    }
1244    double halfW = getWidth() / 2.0;
1245    double halfH = getHeight() / 2.0;
1246    double xc = getX() + halfW;
1247    double yc = getY() + halfH;
1248    double angle = Math.toRadians(-getAngleStart());
1249    double xe = xc + halfW * Math.cos(angle);
1250    double ye = yc + halfH * Math.sin(angle);
1251    if (origrect.intersectsLine(xc, yc, xe, ye)) {
1252        return false;
1253    }
1254    angle += Math.toRadians(-getAngleExtent());
1255    xe = xc + halfW * Math.cos(angle);
1256    ye = yc + halfH * Math.sin(angle);
1257    return !origrect.intersectsLine(xc, yc, xe, ye);
1258    }
1259
1260    /**
1261     * Returns an iteration object that defines the boundary of the
1262     * arc.
1263     * This iterator is multithread safe.
1264     * <code>Arc2D</code> guarantees that
1265     * modifications to the geometry of the arc
1266     * do not affect any iterations of that geometry that
1267     * are already in process.
1268     *
1269     * @param at an optional <CODE>AffineTransform</CODE> to be applied
1270     * to the coordinates as they are returned in the iteration, or null
1271     * if the untransformed coordinates are desired.
1272     *
1273     * @return A <CODE>PathIterator</CODE> that defines the arc's boundary.
1274     */

1275    public PathIterator JavaDoc getPathIterator(AffineTransform JavaDoc at) {
1276    return new ArcIterator JavaDoc(this, at);
1277    }
1278}
1279
Popular Tags