OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / geom / RoundRectangle2D.java
1 /* RoundRectangle2D.java -- represents a rectangle with rounded corners
2    Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package java.awt.geom;
39
40 import java.util.NoSuchElementException;
41
42
43 /** This class implements a rectangle with rounded corners.
44  * @author Tom Tromey <tromey@cygnus.com>
45  * @date December 3, 2000
46  */
47 public abstract class RoundRectangle2D extends RectangularShape
48 {
49   /** Return the arc height of this round rectangle.  */
50   public abstract double getArcHeight();
51
52   /** Return the arc width of this round rectangle.  */
53   public abstract double getArcWidth();
54
55   /** Set the values of this round rectangle
56    * @param x The x coordinate
57    * @param y The y coordinate
58    * @param w The width
59    * @param h The height
60    * @param arcWidth The arc width
61    * @param arcHeight The arc height
62    */
63   public abstract void setRoundRect(double x, double y, double w, double h,
64                                     double arcWidth, double arcHeight);
65
66   /** Create a RoundRectangle2D.  This is protected because this class
67    * is abstract and cannot be instantiated.
68    */
69   protected RoundRectangle2D()
70   {
71   }
72
73   /** Return true if this object contains the specified point.
74    * @param x The x coordinate
75    * @param y The y coordinate
76    */
77   public boolean contains(double x, double y)
78   {
79     double mx = getX();
80     double mw = getWidth();
81     if (x < mx || x >= mx + mw)
82       return false;
83     double my = getY();
84     double mh = getHeight();
85     if (y < my || y >= my + mh)
86       return false;
87
88     // Now check to see if the point is in range of an arc.
89     double dy = Math.min(Math.abs(my - y), Math.abs(my + mh - y));
90     double dx = Math.min(Math.abs(mx - x), Math.abs(mx + mw - x));
91
92     // The arc dimensions are that of the corresponding ellipse
93     // thus a 90 degree segment is half of that.
94     double aw = getArcWidth() / 2.0;
95     double ah = getArcHeight() / 2.0;
96     if (dx > aw || dy > ah)
97       return true;
98
99     // At this point DX represents the distance from the nearest edge
100     // of the rectangle.  But we want to transform it to represent the
101     // scaled distance from the center of the ellipse that forms the
102     // arc.  Hence this code:
103     dy = (ah - dy) / ah;
104     dx = (aw - dx) / aw;
105
106     return dx * dx + dy * dy <= 1.0;
107   }
108
109   /** Return true if this object contains the specified rectangle
110    * @param x The x coordinate
111    * @param y The y coordinate
112    * @param w The width
113    * @param h The height
114    */
115   public boolean contains(double x, double y, double w, double h)
116   {
117     // We have to check all four points here (for ordinary rectangles
118     // we can just check opposing corners).
119     return (contains(x, y) && contains(x, y + h) && contains(x + w, y + h)
120            && contains(x + w, y));
121   }
122
123   /** Return a new path iterator which iterates over this rectangle.
124    * @param at An affine transform to apply to the object
125    */
126   public PathIterator getPathIterator(final AffineTransform at)
127   {
128     final double minx = getX();
129     final double miny = getY();
130     final double maxx = minx + getWidth();
131     final double maxy = miny + getHeight();
132     final double arcwidth = getArcWidth();
133     final double archeight = getArcHeight();
134     return new PathIterator()
135       {
136         /** We iterate counterclockwise around the rectangle, starting in the
137          * upper right.  This variable tracks our current point, which
138          * can be on either side of a given corner.  */
139         private int current = 0;
140
141         /** Child path iterator, used for corners.  */
142         private PathIterator corner;
143
144         /** This is used when rendering the corners.  We re-use the arc
145          * for each corner.  */
146         private Arc2D arc = new Arc2D.Double();
147
148         /** Temporary array used by getPoint.  */
149         private double[] temp = new double[2];
150
151         public int getWindingRule()
152         {
153           return WIND_NON_ZERO;
154         }
155
156         public boolean isDone()
157         {
158           return current > 9;
159         }
160
161         private void getPoint(int val)
162         {
163           switch (val)
164             {
165             case 0:
166             case 8:
167               temp[0] = maxx;
168               temp[1] = miny + archeight;
169               break;
170             case 7:
171               temp[0] = maxx;
172               temp[1] = maxy - archeight;
173               break;
174             case 6:
175               temp[0] = maxx - arcwidth;
176               temp[1] = maxy;
177               break;
178             case 5:
179               temp[0] = minx + arcwidth;
180               temp[1] = maxy;
181               break;
182             case 4:
183               temp[0] = minx;
184               temp[1] = maxy - archeight;
185               break;
186             case 3:
187               temp[0] = minx;
188               temp[1] = miny + archeight;
189               break;
190             case 2:
191               temp[0] = minx + arcwidth;
192               temp[1] = miny;
193               break;
194             case 1:
195               temp[0] = maxx - arcwidth;
196               temp[1] = miny;
197               break;
198             }
199         }
200
201         public void next()
202         {
203           if (current >= 8)
204             ++current;
205           else if (corner != null)
206             {
207               // We're iterating through the corner.  Work on the child
208               // iterator; if it finishes, reset and move to the next
209               // point along the rectangle.
210               corner.next();
211               if (corner.isDone())
212                 {
213                   corner = null;
214                   ++current;
215                 }
216             }
217           else
218             {
219               // Make an arc between this point on the rectangle and
220               // the next one, and then iterate over this arc.
221               getPoint(current);
222               double x1 = temp[0];
223               double y1 = temp[1];
224               getPoint(current + 1);
225               Rectangle2D.Double r = new Rectangle2D.Double(Math.min(x1,
226                                                                      temp[0]),
227                                                             Math.min(y1,
228                                                                      temp[1]),
229                                                             Math.abs(x1
230                                                                      - temp[0]),
231                                                             Math.abs(y1
232                                                                      - temp[1]));
233               arc.setArc(r, (current >> 1) * 90.0, 90.0, Arc2D.OPEN);
234               corner = arc.getPathIterator(at);
235             }
236         }
237
238         public int currentSegment(float[] coords)
239         {
240           if (corner != null)
241             {
242               int r = corner.currentSegment(coords);
243               if (r == SEG_MOVETO)
244                 r = SEG_LINETO;
245               return r;
246             }
247
248           if (current < 9)
249             {
250               getPoint(current);
251               coords[0] = (float) temp[0];
252               coords[1] = (float) temp[1];
253             }
254           else if (current == 9)
255             return SEG_CLOSE;
256           else
257             throw new NoSuchElementException("rect iterator out of bounds");
258
259           if (at != null)
260             at.transform(coords, 0, coords, 0, 1);
261           return current == 0 ? SEG_MOVETO : SEG_LINETO;
262         }
263
264         public int currentSegment(double[] coords)
265         {
266           if (corner != null)
267             {
268               int r = corner.currentSegment(coords);
269               if (r == SEG_MOVETO)
270                 r = SEG_LINETO;
271               return r;
272             }
273
274           if (current < 9)
275             {
276               getPoint(current);
277               coords[0] = temp[0];
278               coords[1] = temp[1];
279             }
280           else if (current == 9)
281             return SEG_CLOSE;
282           else
283             throw new NoSuchElementException("rect iterator out of bounds");
284
285           if (at != null)
286             at.transform(coords, 0, coords, 0, 1);
287           return current == 0 ? SEG_MOVETO : SEG_LINETO;
288         }
289       };
290   }
291
292   /** Return true if the given rectangle intersects this shape.
293    * @param x The x coordinate
294    * @param y The y coordinate
295    * @param w The width
296    * @param h The height
297    */
298   public boolean intersects(double x, double y, double w, double h)
299   {
300     // Check if any corner is within the rectangle
301     return (contains(x, y) || contains(x, y + h) || contains(x + w, y + h)
302            || contains(x + w, y));
303   }
304
305   /** Set the boundary of this round rectangle.
306    * @param x The x coordinate
307    * @param y The y coordinate
308    * @param w The width
309    * @param h The height
310    */
311   public void setFrame(double x, double y, double w, double h)
312   {
313     // This is a bit lame.
314     setRoundRect(x, y, w, h, getArcWidth(), getArcHeight());
315   }
316
317   /** Set the values of this round rectangle to be the same as those
318    * of the argument.
319    * @param rr The round rectangle to copy
320    */
321   public void setRoundRect(RoundRectangle2D rr)
322   {
323     setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(),
324                  rr.getArcWidth(), rr.getArcHeight());
325   }
326
327   /** A subclass of RoundRectangle which keeps its parameters as
328    * doubles.  */
329   public static class Double extends RoundRectangle2D
330   {
331     /** The height of the corner arc.  */
332     public double archeight;
333
334     /** The width of the corner arc.  */
335     public double arcwidth;
336
337     /** The x coordinate of this object.  */
338     public double x;
339
340     /** The y coordinate of this object.  */
341     public double y;
342
343     /** The width of this object.  */
344     public double width;
345
346     /** The height of this object.  */
347     public double height;
348
349     /** Construct a new instance, with all parameters set to 0.  */
350     public Double()
351     {
352     }
353
354     /** Construct a new instance with the given arguments.
355      * @param x The x coordinate
356      * @param y The y coordinate
357      * @param w The width
358      * @param h The height
359      * @param arcWidth The arc width
360      * @param arcHeight The arc height
361      */
362     public Double(double x, double y, double w, double h, double arcWidth,
363                   double arcHeight)
364     {
365       this.x = x;
366       this.y = y;
367       this.width = w;
368       this.height = h;
369       this.arcwidth = arcWidth;
370       this.archeight = arcHeight;
371     }
372
373     public double getArcHeight()
374     {
375       return archeight;
376     }
377
378     public double getArcWidth()
379     {
380       return arcwidth;
381     }
382
383     public Rectangle2D getBounds2D()
384     {
385       return new Rectangle2D.Double(x, y, width, height);
386     }
387
388     public double getX()
389     {
390       return x;
391     }
392
393     public double getY()
394     {
395       return y;
396     }
397
398     public double getWidth()
399     {
400       return width;
401     }
402
403     public double getHeight()
404     {
405       return height;
406     }
407
408     public boolean isEmpty()
409     {
410       return width <= 0 || height <= 0;
411     }
412
413     public void setRoundRect(double x, double y, double w, double h,
414                              double arcWidth, double arcHeight)
415     {
416       this.x = x;
417       this.y = y;
418       this.width = w;
419       this.height = h;
420       this.arcwidth = arcWidth;
421       this.archeight = arcHeight;
422     }
423   } // class Double
424
425   /** A subclass of RoundRectangle which keeps its parameters as
426    * floats.  */
427   public static class Float extends RoundRectangle2D
428   {
429     /** The height of the corner arc.  */
430     public float archeight;
431
432     /** The width of the corner arc.  */
433     public float arcwidth;
434
435     /** The x coordinate of this object.  */
436     public float x;
437
438     /** The y coordinate of this object.  */
439     public float y;
440
441     /** The width of this object.  */
442     public float width;
443
444     /** The height of this object.  */
445     public float height;
446
447     /** Construct a new instance, with all parameters set to 0.  */
448     public Float()
449     {
450     }
451
452     /** Construct a new instance with the given arguments.
453      * @param x The x coordinate
454      * @param y The y coordinate
455      * @param w The width
456      * @param h The height
457      * @param arcWidth The arc width
458      * @param arcHeight The arc height
459      */
460     public Float(float x, float y, float w, float h, float arcWidth,
461                  float arcHeight)
462     {
463       this.x = x;
464       this.y = y;
465       this.width = w;
466       this.height = h;
467       this.arcwidth = arcWidth;
468       this.archeight = arcHeight;
469     }
470
471     public double getArcHeight()
472     {
473       return archeight;
474     }
475
476     public double getArcWidth()
477     {
478       return arcwidth;
479     }
480
481     public Rectangle2D getBounds2D()
482     {
483       return new Rectangle2D.Float(x, y, width, height);
484     }
485
486     public double getX()
487     {
488       return x;
489     }
490
491     public double getY()
492     {
493       return y;
494     }
495
496     public double getWidth()
497     {
498       return width;
499     }
500
501     public double getHeight()
502     {
503       return height;
504     }
505
506     public boolean isEmpty()
507     {
508       return width <= 0 || height <= 0;
509     }
510
511     public void setRoundRect(float x, float y, float w, float h,
512                              float arcWidth, float arcHeight)
513     {
514       this.x = x;
515       this.y = y;
516       this.width = w;
517       this.height = h;
518       this.arcwidth = arcWidth;
519       this.archeight = arcHeight;
520     }
521
522     public void setRoundRect(double x, double y, double w, double h,
523                              double arcWidth, double arcHeight)
524     {
525       this.x = (float) x;
526       this.y = (float) y;
527       this.width = (float) w;
528       this.height = (float) h;
529       this.arcwidth = (float) arcWidth;
530       this.archeight = (float) arcHeight;
531     }
532   } // class Float
533 } // class RoundRectangle2D