History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/geom (76 of 18352 files). Show all

Unified · Split

76 files
  1. java/pkg/java/awt/geom/AffineTransform.class +0 −0
  2. java/pkg/java/awt/geom/AffineTransform.java +3923 −0
  3. java/pkg/java/awt/geom/Arc2D$Double.class +0 −0
  4. java/pkg/java/awt/geom/Arc2D$Float.class +0 −0
  5. java/pkg/java/awt/geom/Arc2D.class +0 −0
  6. java/pkg/java/awt/geom/Arc2D.java +1474 −0
  7. java/pkg/java/awt/geom/ArcIterator.class +0 −0
  8. java/pkg/java/awt/geom/ArcIterator.java +312 −0
  9. java/pkg/java/awt/geom/Area.class +0 −0
  10. java/pkg/java/awt/geom/Area.java +744 −0
  11. java/pkg/java/awt/geom/AreaIterator.class +0 −0
  12. java/pkg/java/awt/geom/CubicCurve2D$Double.class +0 −0
  13. java/pkg/java/awt/geom/CubicCurve2D$Float.class +0 −0
  14. java/pkg/java/awt/geom/CubicCurve2D.class +0 −0
  15. java/pkg/java/awt/geom/CubicCurve2D.java +1575 −0
  16. java/pkg/java/awt/geom/CubicIterator.class +0 −0
  17. java/pkg/java/awt/geom/CubicIterator.java +156 −0
  18. java/pkg/java/awt/geom/Dimension2D.class +0 −0
  19. java/pkg/java/awt/geom/Dimension2D.java +114 −0
  20. java/pkg/java/awt/geom/Ellipse2D$Double.class +0 −0
  21. java/pkg/java/awt/geom/Ellipse2D$Float.class +0 −0
  22. java/pkg/java/awt/geom/Ellipse2D.class +0 −0
  23. java/pkg/java/awt/geom/Ellipse2D.java +464 −0
  24. java/pkg/java/awt/geom/EllipseIterator.class +0 −0
  25. java/pkg/java/awt/geom/EllipseIterator.java +189 −0
  26. java/pkg/java/awt/geom/FlatteningPathIterator.class +0 −0
  27. java/pkg/java/awt/geom/FlatteningPathIterator.java +395 −0
  28. java/pkg/java/awt/geom/GeneralPath.class +0 −0
  29. java/pkg/java/awt/geom/GeneralPath.java +127 −0
  30. java/pkg/java/awt/geom/IllegalPathStateException.class +0 −0
  31. java/pkg/java/awt/geom/IllegalPathStateException.java +56 −0
  32. java/pkg/java/awt/geom/Line2D$Double.class +0 −0
  33. java/pkg/java/awt/geom/Line2D$Float.class +0 −0
  34. java/pkg/java/awt/geom/Line2D.class +0 −0
  35. java/pkg/java/awt/geom/Line2D.java +1128 −0
  36. java/pkg/java/awt/geom/LineIterator.class +0 −0
  37. java/pkg/java/awt/geom/LineIterator.java +148 −0
  38. java/pkg/java/awt/geom/NoninvertibleTransformException.class +0 −0
  39. java/pkg/java/awt/geom/NoninvertibleTransformException.java +46 −0
  40. java/pkg/java/awt/geom/Path2D$Double$CopyIterator.class +0 −0
  41. java/pkg/java/awt/geom/Path2D$Double$TxIterator.class +0 −0
  42. java/pkg/java/awt/geom/Path2D$Double.class +0 −0
  43. java/pkg/java/awt/geom/Path2D$Float$CopyIterator.class +0 −0
  44. java/pkg/java/awt/geom/Path2D$Float$TxIterator.class +0 −0
  45. java/pkg/java/awt/geom/Path2D$Float.class +0 −0
  46. java/pkg/java/awt/geom/Path2D$Iterator.class +0 −0
  47. java/pkg/java/awt/geom/Path2D.class +0 −0
  48. java/pkg/java/awt/geom/Path2D.java +2595 −0
  49. java/pkg/java/awt/geom/PathIterator.class +0 −0
  50. java/pkg/java/awt/geom/PathIterator.java +215 −0
  51. java/pkg/java/awt/geom/Point2D$Double.class +0 −0
  52. java/pkg/java/awt/geom/Point2D$Float.class +0 −0
  53. java/pkg/java/awt/geom/Point2D.class +0 −0
  54. java/pkg/java/awt/geom/Point2D.java +428 −0
  55. java/pkg/java/awt/geom/QuadCurve2D$Double.class +0 −0
  56. java/pkg/java/awt/geom/QuadCurve2D$Float.class +0 −0
  57. java/pkg/java/awt/geom/QuadCurve2D.class +0 −0
  58. java/pkg/java/awt/geom/QuadCurve2D.java +1401 −0
  59. java/pkg/java/awt/geom/QuadIterator.class +0 −0
  60. java/pkg/java/awt/geom/QuadIterator.java +152 −0
  61. java/pkg/java/awt/geom/RectIterator.class +0 −0
  62. java/pkg/java/awt/geom/RectIterator.java +156 −0
  63. java/pkg/java/awt/geom/Rectangle2D$Double.class +0 −0
  64. java/pkg/java/awt/geom/Rectangle2D$Float.class +0 −0
  65. java/pkg/java/awt/geom/Rectangle2D.class +0 −0
  66. java/pkg/java/awt/geom/Rectangle2D.java +930 −0
  67. java/pkg/java/awt/geom/RectangularShape.class +0 −0
  68. java/pkg/java/awt/geom/RectangularShape.java +397 −0
  69. java/pkg/java/awt/geom/RoundRectIterator.class +0 −0
  70. java/pkg/java/awt/geom/RoundRectIterator.java +189 −0
  71. java/pkg/java/awt/geom/RoundRectangle2D$Double.class +0 −0
  72. java/pkg/java/awt/geom/RoundRectangle2D$Float.class +0 −0
  73. java/pkg/java/awt/geom/RoundRectangle2D.class +0 −0
  74. java/pkg/java/awt/geom/RoundRectangle2D.java +681 −0
  75. java/pkg/java/awt/geom/mkfile +32 −0
  76. java/pkg/java/awt/geom/package.html +62 −0
java/pkg/java/awt/geom/AffineTransform.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/AffineTransform.java+3923−0
@@ -0,0 +1,3923 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.beans.ConstructorProperties;
30+
31+/**
32+ * The <code>AffineTransform</code> class represents a 2D affine transform
33+ * that performs a linear mapping from 2D coordinates to other 2D
34+ * coordinates that preserves the "straightness" and
35+ * "parallelness" of lines. Affine transformations can be constructed
36+ * using sequences of translations, scales, flips, rotations, and shears.
37+ * <p>
38+ * Such a coordinate transformation can be represented by a 3 row by
39+ * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
40+ * transforms source coordinates {@code (x,y)} into
41+ * destination coordinates {@code (x',y')} by considering
42+ * them to be a column vector and multiplying the coordinate vector
43+ * by the matrix according to the following process:
44+ * <pre>
45+ * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
46+ * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
47+ * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
48+ * </pre>
49+ * <p>
50+ * <a name="quadrantapproximation"><h4>Handling 90-Degree Rotations</h4></a>
51+ * <p>
52+ * In some variations of the <code>rotate</code> methods in the
53+ * <code>AffineTransform</code> class, a double-precision argument
54+ * specifies the angle of rotation in radians.
55+ * These methods have special handling for rotations of approximately
56+ * 90 degrees (including multiples such as 180, 270, and 360 degrees),
57+ * so that the common case of quadrant rotation is handled more
58+ * efficiently.
59+ * This special handling can cause angles very close to multiples of
60+ * 90 degrees to be treated as if they were exact multiples of
61+ * 90 degrees.
62+ * For small multiples of 90 degrees the range of angles treated
63+ * as a quadrant rotation is approximately 0.00000121 degrees wide.
64+ * This section explains why such special care is needed and how
65+ * it is implemented.
66+ * <p>
67+ * Since 90 degrees is represented as <code>PI/2</code> in radians,
68+ * and since PI is a transcendental (and therefore irrational) number,
69+ * it is not possible to exactly represent a multiple of 90 degrees as
70+ * an exact double precision value measured in radians.
71+ * As a result it is theoretically impossible to describe quadrant
72+ * rotations (90, 180, 270 or 360 degrees) using these values.
73+ * Double precision floating point values can get very close to
74+ * non-zero multiples of <code>PI/2</code> but never close enough
75+ * for the sine or cosine to be exactly 0.0, 1.0 or -1.0.
76+ * The implementations of <code>Math.sin()</code> and
77+ * <code>Math.cos()</code> correspondingly never return 0.0
78+ * for any case other than <code>Math.sin(0.0)</code>.
79+ * These same implementations do, however, return exactly 1.0 and
80+ * -1.0 for some range of numbers around each multiple of 90
81+ * degrees since the correct answer is so close to 1.0 or -1.0 that
82+ * the double precision significand cannot represent the difference
83+ * as accurately as it can for numbers that are near 0.0.
84+ * <p>
85+ * The net result of these issues is that if the
86+ * <code>Math.sin()</code> and <code>Math.cos()</code> methods
87+ * are used to directly generate the values for the matrix modifications
88+ * during these radian-based rotation operations then the resulting
89+ * transform is never strictly classifiable as a quadrant rotation
90+ * even for a simple case like <code>rotate(Math.PI/2.0)</code>,
91+ * due to minor variations in the matrix caused by the non-0.0 values
92+ * obtained for the sine and cosine.
93+ * If these transforms are not classified as quadrant rotations then
94+ * subsequent code which attempts to optimize further operations based
95+ * upon the type of the transform will be relegated to its most general
96+ * implementation.
97+ * <p>
98+ * Because quadrant rotations are fairly common,
99+ * this class should handle these cases reasonably quickly, both in
100+ * applying the rotations to the transform and in applying the resulting
101+ * transform to the coordinates.
102+ * To facilitate this optimal handling, the methods which take an angle
103+ * of rotation measured in radians attempt to detect angles that are
104+ * intended to be quadrant rotations and treat them as such.
105+ * These methods therefore treat an angle <em>theta</em> as a quadrant
106+ * rotation if either <code>Math.sin(<em>theta</em>)</code> or
107+ * <code>Math.cos(<em>theta</em>)</code> returns exactly 1.0 or -1.0.
108+ * As a rule of thumb, this property holds true for a range of
109+ * approximately 0.0000000211 radians (or 0.00000121 degrees) around
110+ * small multiples of <code>Math.PI/2.0</code>.
111+ *
112+ * @author Jim Graham
113+ * @since 1.2
114+ */
115+public class AffineTransform implements Cloneable, java.io.Serializable {
116+
117+ /*
118+ * This constant is only useful for the cached type field.
119+ * It indicates that the type has been decached and must be recalculated.
120+ */
121+ private static final int TYPE_UNKNOWN = -1;
122+
123+ /**
124+ * This constant indicates that the transform defined by this object
125+ * is an identity transform.
126+ * An identity transform is one in which the output coordinates are
127+ * always the same as the input coordinates.
128+ * If this transform is anything other than the identity transform,
129+ * the type will either be the constant GENERAL_TRANSFORM or a
130+ * combination of the appropriate flag bits for the various coordinate
131+ * conversions that this transform performs.
132+ * @see #TYPE_TRANSLATION
133+ * @see #TYPE_UNIFORM_SCALE
134+ * @see #TYPE_GENERAL_SCALE
135+ * @see #TYPE_FLIP
136+ * @see #TYPE_QUADRANT_ROTATION
137+ * @see #TYPE_GENERAL_ROTATION
138+ * @see #TYPE_GENERAL_TRANSFORM
139+ * @see #getType
140+ * @since 1.2
141+ */
142+ public static final int TYPE_IDENTITY = 0;
143+
144+ /**
145+ * This flag bit indicates that the transform defined by this object
146+ * performs a translation in addition to the conversions indicated
147+ * by other flag bits.
148+ * A translation moves the coordinates by a constant amount in x
149+ * and y without changing the length or angle of vectors.
150+ * @see #TYPE_IDENTITY
151+ * @see #TYPE_UNIFORM_SCALE
152+ * @see #TYPE_GENERAL_SCALE
153+ * @see #TYPE_FLIP
154+ * @see #TYPE_QUADRANT_ROTATION
155+ * @see #TYPE_GENERAL_ROTATION
156+ * @see #TYPE_GENERAL_TRANSFORM
157+ * @see #getType
158+ * @since 1.2
159+ */
160+ public static final int TYPE_TRANSLATION = 1;
161+
162+ /**
163+ * This flag bit indicates that the transform defined by this object
164+ * performs a uniform scale in addition to the conversions indicated
165+ * by other flag bits.
166+ * A uniform scale multiplies the length of vectors by the same amount
167+ * in both the x and y directions without changing the angle between
168+ * vectors.
169+ * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
170+ * @see #TYPE_IDENTITY
171+ * @see #TYPE_TRANSLATION
172+ * @see #TYPE_GENERAL_SCALE
173+ * @see #TYPE_FLIP
174+ * @see #TYPE_QUADRANT_ROTATION
175+ * @see #TYPE_GENERAL_ROTATION
176+ * @see #TYPE_GENERAL_TRANSFORM
177+ * @see #getType
178+ * @since 1.2
179+ */
180+ public static final int TYPE_UNIFORM_SCALE = 2;
181+
182+ /**
183+ * This flag bit indicates that the transform defined by this object
184+ * performs a general scale in addition to the conversions indicated
185+ * by other flag bits.
186+ * A general scale multiplies the length of vectors by different
187+ * amounts in the x and y directions without changing the angle
188+ * between perpendicular vectors.
189+ * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
190+ * @see #TYPE_IDENTITY
191+ * @see #TYPE_TRANSLATION
192+ * @see #TYPE_UNIFORM_SCALE
193+ * @see #TYPE_FLIP
194+ * @see #TYPE_QUADRANT_ROTATION
195+ * @see #TYPE_GENERAL_ROTATION
196+ * @see #TYPE_GENERAL_TRANSFORM
197+ * @see #getType
198+ * @since 1.2
199+ */
200+ public static final int TYPE_GENERAL_SCALE = 4;
201+
202+ /**
203+ * This constant is a bit mask for any of the scale flag bits.
204+ * @see #TYPE_UNIFORM_SCALE
205+ * @see #TYPE_GENERAL_SCALE
206+ * @since 1.2
207+ */
208+ public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE |
209+ TYPE_GENERAL_SCALE);
210+
211+ /**
212+ * This flag bit indicates that the transform defined by this object
213+ * performs a mirror image flip about some axis which changes the
214+ * normally right handed coordinate system into a left handed
215+ * system in addition to the conversions indicated by other flag bits.
216+ * A right handed coordinate system is one where the positive X
217+ * axis rotates counterclockwise to overlay the positive Y axis
218+ * similar to the direction that the fingers on your right hand
219+ * curl when you stare end on at your thumb.
220+ * A left handed coordinate system is one where the positive X
221+ * axis rotates clockwise to overlay the positive Y axis similar
222+ * to the direction that the fingers on your left hand curl.
223+ * There is no mathematical way to determine the angle of the
224+ * original flipping or mirroring transformation since all angles
225+ * of flip are identical given an appropriate adjusting rotation.
226+ * @see #TYPE_IDENTITY
227+ * @see #TYPE_TRANSLATION
228+ * @see #TYPE_UNIFORM_SCALE
229+ * @see #TYPE_GENERAL_SCALE
230+ * @see #TYPE_QUADRANT_ROTATION
231+ * @see #TYPE_GENERAL_ROTATION
232+ * @see #TYPE_GENERAL_TRANSFORM
233+ * @see #getType
234+ * @since 1.2
235+ */
236+ public static final int TYPE_FLIP = 64;
237+ /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
238+ * circulation and the flag bits could no longer be conveniently
239+ * renumbered without introducing binary incompatibility in outside
240+ * code.
241+ */
242+
243+ /**
244+ * This flag bit indicates that the transform defined by this object
245+ * performs a quadrant rotation by some multiple of 90 degrees in
246+ * addition to the conversions indicated by other flag bits.
247+ * A rotation changes the angles of vectors by the same amount
248+ * regardless of the original direction of the vector and without
249+ * changing the length of the vector.
250+ * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
251+ * @see #TYPE_IDENTITY
252+ * @see #TYPE_TRANSLATION
253+ * @see #TYPE_UNIFORM_SCALE
254+ * @see #TYPE_GENERAL_SCALE
255+ * @see #TYPE_FLIP
256+ * @see #TYPE_GENERAL_ROTATION
257+ * @see #TYPE_GENERAL_TRANSFORM
258+ * @see #getType
259+ * @since 1.2
260+ */
261+ public static final int TYPE_QUADRANT_ROTATION = 8;
262+
263+ /**
264+ * This flag bit indicates that the transform defined by this object
265+ * performs a rotation by an arbitrary angle in addition to the
266+ * conversions indicated by other flag bits.
267+ * A rotation changes the angles of vectors by the same amount
268+ * regardless of the original direction of the vector and without
269+ * changing the length of the vector.
270+ * This flag bit is mutually exclusive with the
271+ * TYPE_QUADRANT_ROTATION flag.
272+ * @see #TYPE_IDENTITY
273+ * @see #TYPE_TRANSLATION
274+ * @see #TYPE_UNIFORM_SCALE
275+ * @see #TYPE_GENERAL_SCALE
276+ * @see #TYPE_FLIP
277+ * @see #TYPE_QUADRANT_ROTATION
278+ * @see #TYPE_GENERAL_TRANSFORM
279+ * @see #getType
280+ * @since 1.2
281+ */
282+ public static final int TYPE_GENERAL_ROTATION = 16;
283+
284+ /**
285+ * This constant is a bit mask for any of the rotation flag bits.
286+ * @see #TYPE_QUADRANT_ROTATION
287+ * @see #TYPE_GENERAL_ROTATION
288+ * @since 1.2
289+ */
290+ public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION |
291+ TYPE_GENERAL_ROTATION);
292+
293+ /**
294+ * This constant indicates that the transform defined by this object
295+ * performs an arbitrary conversion of the input coordinates.
296+ * If this transform can be classified by any of the above constants,
297+ * the type will either be the constant TYPE_IDENTITY or a
298+ * combination of the appropriate flag bits for the various coordinate
299+ * conversions that this transform performs.
300+ * @see #TYPE_IDENTITY
301+ * @see #TYPE_TRANSLATION
302+ * @see #TYPE_UNIFORM_SCALE
303+ * @see #TYPE_GENERAL_SCALE
304+ * @see #TYPE_FLIP
305+ * @see #TYPE_QUADRANT_ROTATION
306+ * @see #TYPE_GENERAL_ROTATION
307+ * @see #getType
308+ * @since 1.2
309+ */
310+ public static final int TYPE_GENERAL_TRANSFORM = 32;
311+
312+ /**
313+ * This constant is used for the internal state variable to indicate
314+ * that no calculations need to be performed and that the source
315+ * coordinates only need to be copied to their destinations to
316+ * complete the transformation equation of this transform.
317+ * @see #APPLY_TRANSLATE
318+ * @see #APPLY_SCALE
319+ * @see #APPLY_SHEAR
320+ * @see #state
321+ */
322+ static final int APPLY_IDENTITY = 0;
323+
324+ /**
325+ * This constant is used for the internal state variable to indicate
326+ * that the translation components of the matrix (m02 and m12) need
327+ * to be added to complete the transformation equation of this transform.
328+ * @see #APPLY_IDENTITY
329+ * @see #APPLY_SCALE
330+ * @see #APPLY_SHEAR
331+ * @see #state
332+ */
333+ static final int APPLY_TRANSLATE = 1;
334+
335+ /**
336+ * This constant is used for the internal state variable to indicate
337+ * that the scaling components of the matrix (m00 and m11) need
338+ * to be factored in to complete the transformation equation of
339+ * this transform. If the APPLY_SHEAR bit is also set then it
340+ * indicates that the scaling components are not both 0.0. If the
341+ * APPLY_SHEAR bit is not also set then it indicates that the
342+ * scaling components are not both 1.0. If neither the APPLY_SHEAR
343+ * nor the APPLY_SCALE bits are set then the scaling components
344+ * are both 1.0, which means that the x and y components contribute
345+ * to the transformed coordinate, but they are not multiplied by
346+ * any scaling factor.
347+ * @see #APPLY_IDENTITY
348+ * @see #APPLY_TRANSLATE
349+ * @see #APPLY_SHEAR
350+ * @see #state
351+ */
352+ static final int APPLY_SCALE = 2;
353+
354+ /**
355+ * This constant is used for the internal state variable to indicate
356+ * that the shearing components of the matrix (m01 and m10) need
357+ * to be factored in to complete the transformation equation of this
358+ * transform. The presence of this bit in the state variable changes
359+ * the interpretation of the APPLY_SCALE bit as indicated in its
360+ * documentation.
361+ * @see #APPLY_IDENTITY
362+ * @see #APPLY_TRANSLATE
363+ * @see #APPLY_SCALE
364+ * @see #state
365+ */
366+ static final int APPLY_SHEAR = 4;
367+
368+ /*
369+ * For methods which combine together the state of two separate
370+ * transforms and dispatch based upon the combination, these constants
371+ * specify how far to shift one of the states so that the two states
372+ * are mutually non-interfering and provide constants for testing the
373+ * bits of the shifted (HI) state. The methods in this class use
374+ * the convention that the state of "this" transform is unshifted and
375+ * the state of the "other" or "argument" transform is shifted (HI).
376+ */
377+ private static final int HI_SHIFT = 3;
378+ private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
379+ private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
380+ private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
381+ private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
382+
383+ /**
384+ * The X coordinate scaling element of the 3x3
385+ * affine transformation matrix.
386+ *
387+ * @serial
388+ */
389+ double m00;
390+
391+ /**
392+ * The Y coordinate shearing element of the 3x3
393+ * affine transformation matrix.
394+ *
395+ * @serial
396+ */
397+ double m10;
398+
399+ /**
400+ * The X coordinate shearing element of the 3x3
401+ * affine transformation matrix.
402+ *
403+ * @serial
404+ */
405+ double m01;
406+
407+ /**
408+ * The Y coordinate scaling element of the 3x3
409+ * affine transformation matrix.
410+ *
411+ * @serial
412+ */
413+ double m11;
414+
415+ /**
416+ * The X coordinate of the translation element of the
417+ * 3x3 affine transformation matrix.
418+ *
419+ * @serial
420+ */
421+ double m02;
422+
423+ /**
424+ * The Y coordinate of the translation element of the
425+ * 3x3 affine transformation matrix.
426+ *
427+ * @serial
428+ */
429+ double m12;
430+
431+ /**
432+ * This field keeps track of which components of the matrix need to
433+ * be applied when performing a transformation.
434+ * @see #APPLY_IDENTITY
435+ * @see #APPLY_TRANSLATE
436+ * @see #APPLY_SCALE
437+ * @see #APPLY_SHEAR
438+ */
439+ transient int state;
440+
441+ /**
442+ * This field caches the current transformation type of the matrix.
443+ * @see #TYPE_IDENTITY
444+ * @see #TYPE_TRANSLATION
445+ * @see #TYPE_UNIFORM_SCALE
446+ * @see #TYPE_GENERAL_SCALE
447+ * @see #TYPE_FLIP
448+ * @see #TYPE_QUADRANT_ROTATION
449+ * @see #TYPE_GENERAL_ROTATION
450+ * @see #TYPE_GENERAL_TRANSFORM
451+ * @see #TYPE_UNKNOWN
452+ * @see #getType
453+ */
454+ private transient int type;
455+
456+ private AffineTransform(double m00, double m10,
457+ double m01, double m11,
458+ double m02, double m12,
459+ int state) {
460+ this.m00 = m00;
461+ this.m10 = m10;
462+ this.m01 = m01;
463+ this.m11 = m11;
464+ this.m02 = m02;
465+ this.m12 = m12;
466+ this.state = state;
467+ this.type = TYPE_UNKNOWN;
468+ }
469+
470+ /**
471+ * Constructs a new <code>AffineTransform</code> representing the
472+ * Identity transformation.
473+ * @since 1.2
474+ */
475+ public AffineTransform() {
476+ m00 = m11 = 1.0;
477+ // m01 = m10 = m02 = m12 = 0.0; /* Not needed. */
478+ // state = APPLY_IDENTITY; /* Not needed. */
479+ // type = TYPE_IDENTITY; /* Not needed. */
480+ }
481+
482+ /**
483+ * Constructs a new <code>AffineTransform</code> that is a copy of
484+ * the specified <code>AffineTransform</code> object.
485+ * @param Tx the <code>AffineTransform</code> object to copy
486+ * @since 1.2
487+ */
488+ public AffineTransform(AffineTransform Tx) {
489+ this.m00 = Tx.m00;
490+ this.m10 = Tx.m10;
491+ this.m01 = Tx.m01;
492+ this.m11 = Tx.m11;
493+ this.m02 = Tx.m02;
494+ this.m12 = Tx.m12;
495+ this.state = Tx.state;
496+ this.type = Tx.type;
497+ }
498+
499+ /**
500+ * Constructs a new <code>AffineTransform</code> from 6 floating point
501+ * values representing the 6 specifiable entries of the 3x3
502+ * transformation matrix.
503+ *
504+ * @param m00 the X coordinate scaling element of the 3x3 matrix
505+ * @param m10 the Y coordinate shearing element of the 3x3 matrix
506+ * @param m01 the X coordinate shearing element of the 3x3 matrix
507+ * @param m11 the Y coordinate scaling element of the 3x3 matrix
508+ * @param m02 the X coordinate translation element of the 3x3 matrix
509+ * @param m12 the Y coordinate translation element of the 3x3 matrix
510+ * @since 1.2
511+ */
512+ @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" })
513+ public AffineTransform(float m00, float m10,
514+ float m01, float m11,
515+ float m02, float m12) {
516+ this.m00 = m00;
517+ this.m10 = m10;
518+ this.m01 = m01;
519+ this.m11 = m11;
520+ this.m02 = m02;
521+ this.m12 = m12;
522+ updateState();
523+ }
524+
525+ /**
526+ * Constructs a new <code>AffineTransform</code> from an array of
527+ * floating point values representing either the 4 non-translation
528+ * enries or the 6 specifiable entries of the 3x3 transformation
529+ * matrix. The values are retrieved from the array as
530+ * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
531+ * @param flatmatrix the float array containing the values to be set
532+ * in the new <code>AffineTransform</code> object. The length of the
533+ * array is assumed to be at least 4. If the length of the array is
534+ * less than 6, only the first 4 values are taken. If the length of
535+ * the array is greater than 6, the first 6 values are taken.
536+ * @since 1.2
537+ */
538+ public AffineTransform(float[] flatmatrix) {
539+ m00 = flatmatrix[0];
540+ m10 = flatmatrix[1];
541+ m01 = flatmatrix[2];
542+ m11 = flatmatrix[3];
543+ if (flatmatrix.length > 5) {
544+ m02 = flatmatrix[4];
545+ m12 = flatmatrix[5];
546+ }
547+ updateState();
548+ }
549+
550+ /**
551+ * Constructs a new <code>AffineTransform</code> from 6 double
552+ * precision values representing the 6 specifiable entries of the 3x3
553+ * transformation matrix.
554+ *
555+ * @param m00 the X coordinate scaling element of the 3x3 matrix
556+ * @param m10 the Y coordinate shearing element of the 3x3 matrix
557+ * @param m01 the X coordinate shearing element of the 3x3 matrix
558+ * @param m11 the Y coordinate scaling element of the 3x3 matrix
559+ * @param m02 the X coordinate translation element of the 3x3 matrix
560+ * @param m12 the Y coordinate translation element of the 3x3 matrix
561+ * @since 1.2
562+ */
563+ public AffineTransform(double m00, double m10,
564+ double m01, double m11,
565+ double m02, double m12) {
566+ this.m00 = m00;
567+ this.m10 = m10;
568+ this.m01 = m01;
569+ this.m11 = m11;
570+ this.m02 = m02;
571+ this.m12 = m12;
572+ updateState();
573+ }
574+
575+ /**
576+ * Constructs a new <code>AffineTransform</code> from an array of
577+ * double precision values representing either the 4 non-translation
578+ * entries or the 6 specifiable entries of the 3x3 transformation
579+ * matrix. The values are retrieved from the array as
580+ * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
581+ * @param flatmatrix the double array containing the values to be set
582+ * in the new <code>AffineTransform</code> object. The length of the
583+ * array is assumed to be at least 4. If the length of the array is
584+ * less than 6, only the first 4 values are taken. If the length of
585+ * the array is greater than 6, the first 6 values are taken.
586+ * @since 1.2
587+ */
588+ public AffineTransform(double[] flatmatrix) {
589+ m00 = flatmatrix[0];
590+ m10 = flatmatrix[1];
591+ m01 = flatmatrix[2];
592+ m11 = flatmatrix[3];
593+ if (flatmatrix.length > 5) {
594+ m02 = flatmatrix[4];
595+ m12 = flatmatrix[5];
596+ }
597+ updateState();
598+ }
599+
600+ /**
601+ * Returns a transform representing a translation transformation.
602+ * The matrix representing the returned transform is:
603+ * <pre>
604+ * [ 1 0 tx ]
605+ * [ 0 1 ty ]
606+ * [ 0 0 1 ]
607+ * </pre>
608+ * @param tx the distance by which coordinates are translated in the
609+ * X axis direction
610+ * @param ty the distance by which coordinates are translated in the
611+ * Y axis direction
612+ * @return an <code>AffineTransform</code> object that represents a
613+ * translation transformation, created with the specified vector.
614+ * @since 1.2
615+ */
616+ public static AffineTransform getTranslateInstance(double tx, double ty) {
617+ AffineTransform Tx = new AffineTransform();
618+ Tx.setToTranslation(tx, ty);
619+ return Tx;
620+ }
621+
622+ /**
623+ * Returns a transform representing a rotation transformation.
624+ * The matrix representing the returned transform is:
625+ * <pre>
626+ * [ cos(theta) -sin(theta) 0 ]
627+ * [ sin(theta) cos(theta) 0 ]
628+ * [ 0 0 1 ]
629+ * </pre>
630+ * Rotating by a positive angle theta rotates points on the positive
631+ * X axis toward the positive Y axis.
632+ * Note also the discussion of
633+ * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
634+ * above.
635+ * @param theta the angle of rotation measured in radians
636+ * @return an <code>AffineTransform</code> object that is a rotation
637+ * transformation, created with the specified angle of rotation.
638+ * @since 1.2
639+ */
640+ public static AffineTransform getRotateInstance(double theta) {
641+ AffineTransform Tx = new AffineTransform();
642+ Tx.setToRotation(theta);
643+ return Tx;
644+ }
645+
646+ /**
647+ * Returns a transform that rotates coordinates around an anchor point.
648+ * This operation is equivalent to translating the coordinates so
649+ * that the anchor point is at the origin (S1), then rotating them
650+ * about the new origin (S2), and finally translating so that the
651+ * intermediate origin is restored to the coordinates of the original
652+ * anchor point (S3).
653+ * <p>
654+ * This operation is equivalent to the following sequence of calls:
655+ * <pre>
656+ * AffineTransform Tx = new AffineTransform();
657+ * Tx.translate(anchorx, anchory); // S3: final translation
658+ * Tx.rotate(theta); // S2: rotate around anchor
659+ * Tx.translate(-anchorx, -anchory); // S1: translate anchor to origin
660+ * </pre>
661+ * The matrix representing the returned transform is:
662+ * <pre>
663+ * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
664+ * [ sin(theta) cos(theta) y-x*sin-y*cos ]
665+ * [ 0 0 1 ]
666+ * </pre>
667+ * Rotating by a positive angle theta rotates points on the positive
668+ * X axis toward the positive Y axis.
669+ * Note also the discussion of
670+ * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
671+ * above.
672+ *
673+ * @param theta the angle of rotation measured in radians
674+ * @param anchorx the X coordinate of the rotation anchor point
675+ * @param anchory the Y coordinate of the rotation anchor point
676+ * @return an <code>AffineTransform</code> object that rotates
677+ * coordinates around the specified point by the specified angle of
678+ * rotation.
679+ * @since 1.2
680+ */
681+ public static AffineTransform getRotateInstance(double theta,
682+ double anchorx,
683+ double anchory)
684+ {
685+ AffineTransform Tx = new AffineTransform();
686+ Tx.setToRotation(theta, anchorx, anchory);
687+ return Tx;
688+ }
689+
690+ /**
691+ * Returns a transform that rotates coordinates according to
692+ * a rotation vector.
693+ * All coordinates rotate about the origin by the same amount.
694+ * The amount of rotation is such that coordinates along the former
695+ * positive X axis will subsequently align with the vector pointing
696+ * from the origin to the specified vector coordinates.
697+ * If both <code>vecx</code> and <code>vecy</code> are 0.0,
698+ * an identity transform is returned.
699+ * This operation is equivalent to calling:
700+ * <pre>
701+ * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
702+ * </pre>
703+ *
704+ * @param vecx the X coordinate of the rotation vector
705+ * @param vecy the Y coordinate of the rotation vector
706+ * @return an <code>AffineTransform</code> object that rotates
707+ * coordinates according to the specified rotation vector.
708+ * @since 1.6
709+ */
710+ public static AffineTransform getRotateInstance(double vecx, double vecy) {
711+ AffineTransform Tx = new AffineTransform();
712+ Tx.setToRotation(vecx, vecy);
713+ return Tx;
714+ }
715+
716+ /**
717+ * Returns a transform that rotates coordinates around an anchor
718+ * point accordinate to a rotation vector.
719+ * All coordinates rotate about the specified anchor coordinates
720+ * by the same amount.
721+ * The amount of rotation is such that coordinates along the former
722+ * positive X axis will subsequently align with the vector pointing
723+ * from the origin to the specified vector coordinates.
724+ * If both <code>vecx</code> and <code>vecy</code> are 0.0,
725+ * an identity transform is returned.
726+ * This operation is equivalent to calling:
727+ * <pre>
728+ * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
729+ * anchorx, anchory);
730+ * </pre>
731+ *
732+ * @param vecx the X coordinate of the rotation vector
733+ * @param vecy the Y coordinate of the rotation vector
734+ * @param anchorx the X coordinate of the rotation anchor point
735+ * @param anchory the Y coordinate of the rotation anchor point
736+ * @return an <code>AffineTransform</code> object that rotates
737+ * coordinates around the specified point according to the
738+ * specified rotation vector.
739+ * @since 1.6
740+ */
741+ public static AffineTransform getRotateInstance(double vecx,
742+ double vecy,
743+ double anchorx,
744+ double anchory)
745+ {
746+ AffineTransform Tx = new AffineTransform();
747+ Tx.setToRotation(vecx, vecy, anchorx, anchory);
748+ return Tx;
749+ }
750+
751+ /**
752+ * Returns a transform that rotates coordinates by the specified
753+ * number of quadrants.
754+ * This operation is equivalent to calling:
755+ * <pre>
756+ * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
757+ * </pre>
758+ * Rotating by a positive number of quadrants rotates points on
759+ * the positive X axis toward the positive Y axis.
760+ * @param numquadrants the number of 90 degree arcs to rotate by
761+ * @return an <code>AffineTransform</code> object that rotates
762+ * coordinates by the specified number of quadrants.
763+ * @since 1.6
764+ */
765+ public static AffineTransform getQuadrantRotateInstance(int numquadrants) {
766+ AffineTransform Tx = new AffineTransform();
767+ Tx.setToQuadrantRotation(numquadrants);
768+ return Tx;
769+ }
770+
771+ /**
772+ * Returns a transform that rotates coordinates by the specified
773+ * number of quadrants around the specified anchor point.
774+ * This operation is equivalent to calling:
775+ * <pre>
776+ * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
777+ * anchorx, anchory);
778+ * </pre>
779+ * Rotating by a positive number of quadrants rotates points on
780+ * the positive X axis toward the positive Y axis.
781+ *
782+ * @param numquadrants the number of 90 degree arcs to rotate by
783+ * @param anchorx the X coordinate of the rotation anchor point
784+ * @param anchory the Y coordinate of the rotation anchor point
785+ * @return an <code>AffineTransform</code> object that rotates
786+ * coordinates by the specified number of quadrants around the
787+ * specified anchor point.
788+ * @since 1.6
789+ */
790+ public static AffineTransform getQuadrantRotateInstance(int numquadrants,
791+ double anchorx,
792+ double anchory)
793+ {
794+ AffineTransform Tx = new AffineTransform();
795+ Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
796+ return Tx;
797+ }
798+
799+ /**
800+ * Returns a transform representing a scaling transformation.
801+ * The matrix representing the returned transform is:
802+ * <pre>
803+ * [ sx 0 0 ]
804+ * [ 0 sy 0 ]
805+ * [ 0 0 1 ]
806+ * </pre>
807+ * @param sx the factor by which coordinates are scaled along the
808+ * X axis direction
809+ * @param sy the factor by which coordinates are scaled along the
810+ * Y axis direction
811+ * @return an <code>AffineTransform</code> object that scales
812+ * coordinates by the specified factors.
813+ * @since 1.2
814+ */
815+ public static AffineTransform getScaleInstance(double sx, double sy) {
816+ AffineTransform Tx = new AffineTransform();
817+ Tx.setToScale(sx, sy);
818+ return Tx;
819+ }
820+
821+ /**
822+ * Returns a transform representing a shearing transformation.
823+ * The matrix representing the returned transform is:
824+ * <pre>
825+ * [ 1 shx 0 ]
826+ * [ shy 1 0 ]
827+ * [ 0 0 1 ]
828+ * </pre>
829+ * @param shx the multiplier by which coordinates are shifted in the
830+ * direction of the positive X axis as a factor of their Y coordinate
831+ * @param shy the multiplier by which coordinates are shifted in the
832+ * direction of the positive Y axis as a factor of their X coordinate
833+ * @return an <code>AffineTransform</code> object that shears
834+ * coordinates by the specified multipliers.
835+ * @since 1.2
836+ */
837+ public static AffineTransform getShearInstance(double shx, double shy) {
838+ AffineTransform Tx = new AffineTransform();
839+ Tx.setToShear(shx, shy);
840+ return Tx;
841+ }
842+
843+ /**
844+ * Retrieves the flag bits describing the conversion properties of
845+ * this transform.
846+ * The return value is either one of the constants TYPE_IDENTITY
847+ * or TYPE_GENERAL_TRANSFORM, or a combination of the
848+ * appriopriate flag bits.
849+ * A valid combination of flag bits is an exclusive OR operation
850+ * that can combine
851+ * the TYPE_TRANSLATION flag bit
852+ * in addition to either of the
853+ * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
854+ * as well as either of the
855+ * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
856+ * @return the OR combination of any of the indicated flags that
857+ * apply to this transform
858+ * @see #TYPE_IDENTITY
859+ * @see #TYPE_TRANSLATION
860+ * @see #TYPE_UNIFORM_SCALE
861+ * @see #TYPE_GENERAL_SCALE
862+ * @see #TYPE_QUADRANT_ROTATION
863+ * @see #TYPE_GENERAL_ROTATION
864+ * @see #TYPE_GENERAL_TRANSFORM
865+ * @since 1.2
866+ */
867+ public int getType() {
868+ if (type == TYPE_UNKNOWN) {
869+ calculateType();
870+ }
871+ return type;
872+ }
873+
874+ /**
875+ * This is the utility function to calculate the flag bits when
876+ * they have not been cached.
877+ * @see #getType
878+ */
879+ private void calculateType() {
880+ int ret = TYPE_IDENTITY;
881+ boolean sgn0, sgn1;
882+ double M0, M1, M2, M3;
883+ updateState();
884+ switch (state) {
885+ default:
886+ stateError();
887+ /* NOTREACHED */
888+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
889+ ret = TYPE_TRANSLATION;
890+ /* NOBREAK */
891+ case (APPLY_SHEAR | APPLY_SCALE):
892+ if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
893+ // Transformed unit vectors are not perpendicular...
894+ this.type = TYPE_GENERAL_TRANSFORM;
895+ return;
896+ }
897+ sgn0 = (M0 >= 0.0);
898+ sgn1 = (M1 >= 0.0);
899+ if (sgn0 == sgn1) {
900+ // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
901+ // This is the "unflipped" (right-handed) state
902+ if (M0 != M1 || M2 != -M3) {
903+ ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
904+ } else if (M0 * M1 - M2 * M3 != 1.0) {
905+ ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
906+ } else {
907+ ret |= TYPE_GENERAL_ROTATION;
908+ }
909+ } else {
910+ // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
911+ // This is the "flipped" (left-handed) state
912+ if (M0 != -M1 || M2 != M3) {
913+ ret |= (TYPE_GENERAL_ROTATION |
914+ TYPE_FLIP |
915+ TYPE_GENERAL_SCALE);
916+ } else if (M0 * M1 - M2 * M3 != 1.0) {
917+ ret |= (TYPE_GENERAL_ROTATION |
918+ TYPE_FLIP |
919+ TYPE_UNIFORM_SCALE);
920+ } else {
921+ ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
922+ }
923+ }
924+ break;
925+ case (APPLY_SHEAR | APPLY_TRANSLATE):
926+ ret = TYPE_TRANSLATION;
927+ /* NOBREAK */
928+ case (APPLY_SHEAR):
929+ sgn0 = ((M0 = m01) >= 0.0);
930+ sgn1 = ((M1 = m10) >= 0.0);
931+ if (sgn0 != sgn1) {
932+ // Different signs - simple 90 degree rotation
933+ if (M0 != -M1) {
934+ ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
935+ } else if (M0 != 1.0 && M0 != -1.0) {
936+ ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
937+ } else {
938+ ret |= TYPE_QUADRANT_ROTATION;
939+ }
940+ } else {
941+ // Same signs - 90 degree rotation plus an axis flip too
942+ if (M0 == M1) {
943+ ret |= (TYPE_QUADRANT_ROTATION |
944+ TYPE_FLIP |
945+ TYPE_UNIFORM_SCALE);
946+ } else {
947+ ret |= (TYPE_QUADRANT_ROTATION |
948+ TYPE_FLIP |
949+ TYPE_GENERAL_SCALE);
950+ }
951+ }
952+ break;
953+ case (APPLY_SCALE | APPLY_TRANSLATE):
954+ ret = TYPE_TRANSLATION;
955+ /* NOBREAK */
956+ case (APPLY_SCALE):
957+ sgn0 = ((M0 = m00) >= 0.0);
958+ sgn1 = ((M1 = m11) >= 0.0);
959+ if (sgn0 == sgn1) {
960+ if (sgn0) {
961+ // Both scaling factors non-negative - simple scale
962+ // Note: APPLY_SCALE implies M0, M1 are not both 1
963+ if (M0 == M1) {
964+ ret |= TYPE_UNIFORM_SCALE;
965+ } else {
966+ ret |= TYPE_GENERAL_SCALE;
967+ }
968+ } else {
969+ // Both scaling factors negative - 180 degree rotation
970+ if (M0 != M1) {
971+ ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
972+ } else if (M0 != -1.0) {
973+ ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
974+ } else {
975+ ret |= TYPE_QUADRANT_ROTATION;
976+ }
977+ }
978+ } else {
979+ // Scaling factor signs different - flip about some axis
980+ if (M0 == -M1) {
981+ if (M0 == 1.0 || M0 == -1.0) {
982+ ret |= TYPE_FLIP;
983+ } else {
984+ ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
985+ }
986+ } else {
987+ ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
988+ }
989+ }
990+ break;
991+ case (APPLY_TRANSLATE):
992+ ret = TYPE_TRANSLATION;
993+ break;
994+ case (APPLY_IDENTITY):
995+ break;
996+ }
997+ this.type = ret;
998+ }
999+
1000+ /**
1001+ * Returns the determinant of the matrix representation of the transform.
1002+ * The determinant is useful both to determine if the transform can
1003+ * be inverted and to get a single value representing the
1004+ * combined X and Y scaling of the transform.
1005+ * <p>
1006+ * If the determinant is non-zero, then this transform is
1007+ * invertible and the various methods that depend on the inverse
1008+ * transform do not need to throw a
1009+ * {@link NoninvertibleTransformException}.
1010+ * If the determinant is zero then this transform can not be
1011+ * inverted since the transform maps all input coordinates onto
1012+ * a line or a point.
1013+ * If the determinant is near enough to zero then inverse transform
1014+ * operations might not carry enough precision to produce meaningful
1015+ * results.
1016+ * <p>
1017+ * If this transform represents a uniform scale, as indicated by
1018+ * the <code>getType</code> method then the determinant also
1019+ * represents the square of the uniform scale factor by which all of
1020+ * the points are expanded from or contracted towards the origin.
1021+ * If this transform represents a non-uniform scale or more general
1022+ * transform then the determinant is not likely to represent a
1023+ * value useful for any purpose other than determining if inverse
1024+ * transforms are possible.
1025+ * <p>
1026+ * Mathematically, the determinant is calculated using the formula:
1027+ * <pre>
1028+ * | m00 m01 m02 |
1029+ * | m10 m11 m12 | = m00 * m11 - m01 * m10
1030+ * | 0 0 1 |
1031+ * </pre>
1032+ *
1033+ * @return the determinant of the matrix used to transform the
1034+ * coordinates.
1035+ * @see #getType
1036+ * @see #createInverse
1037+ * @see #inverseTransform
1038+ * @see #TYPE_UNIFORM_SCALE
1039+ * @since 1.2
1040+ */
1041+ public double getDeterminant() {
1042+ switch (state) {
1043+ default:
1044+ stateError();
1045+ /* NOTREACHED */
1046+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1047+ case (APPLY_SHEAR | APPLY_SCALE):
1048+ return m00 * m11 - m01 * m10;
1049+ case (APPLY_SHEAR | APPLY_TRANSLATE):
1050+ case (APPLY_SHEAR):
1051+ return -(m01 * m10);
1052+ case (APPLY_SCALE | APPLY_TRANSLATE):
1053+ case (APPLY_SCALE):
1054+ return m00 * m11;
1055+ case (APPLY_TRANSLATE):
1056+ case (APPLY_IDENTITY):
1057+ return 1.0;
1058+ }
1059+ }
1060+
1061+ /**
1062+ * Manually recalculates the state of the transform when the matrix
1063+ * changes too much to predict the effects on the state.
1064+ * The following table specifies what the various settings of the
1065+ * state field say about the values of the corresponding matrix
1066+ * element fields.
1067+ * Note that the rules governing the SCALE fields are slightly
1068+ * different depending on whether the SHEAR flag is also set.
1069+ * <pre>
1070+ * SCALE SHEAR TRANSLATE
1071+ * m00/m11 m01/m10 m02/m12
1072+ *
1073+ * IDENTITY 1.0 0.0 0.0
1074+ * TRANSLATE (TR) 1.0 0.0 not both 0.0
1075+ * SCALE (SC) not both 1.0 0.0 0.0
1076+ * TR | SC not both 1.0 0.0 not both 0.0
1077+ * SHEAR (SH) 0.0 not both 0.0 0.0
1078+ * TR | SH 0.0 not both 0.0 not both 0.0
1079+ * SC | SH not both 0.0 not both 0.0 0.0
1080+ * TR | SC | SH not both 0.0 not both 0.0 not both 0.0
1081+ * </pre>
1082+ */
1083+ void updateState() {
1084+ if (m01 == 0.0 && m10 == 0.0) {
1085+ if (m00 == 1.0 && m11 == 1.0) {
1086+ if (m02 == 0.0 && m12 == 0.0) {
1087+ state = APPLY_IDENTITY;
1088+ type = TYPE_IDENTITY;
1089+ } else {
1090+ state = APPLY_TRANSLATE;
1091+ type = TYPE_TRANSLATION;
1092+ }
1093+ } else {
1094+ if (m02 == 0.0 && m12 == 0.0) {
1095+ state = APPLY_SCALE;
1096+ type = TYPE_UNKNOWN;
1097+ } else {
1098+ state = (APPLY_SCALE | APPLY_TRANSLATE);
1099+ type = TYPE_UNKNOWN;
1100+ }
1101+ }
1102+ } else {
1103+ if (m00 == 0.0 && m11 == 0.0) {
1104+ if (m02 == 0.0 && m12 == 0.0) {
1105+ state = APPLY_SHEAR;
1106+ type = TYPE_UNKNOWN;
1107+ } else {
1108+ state = (APPLY_SHEAR | APPLY_TRANSLATE);
1109+ type = TYPE_UNKNOWN;
1110+ }
1111+ } else {
1112+ if (m02 == 0.0 && m12 == 0.0) {
1113+ state = (APPLY_SHEAR | APPLY_SCALE);
1114+ type = TYPE_UNKNOWN;
1115+ } else {
1116+ state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
1117+ type = TYPE_UNKNOWN;
1118+ }
1119+ }
1120+ }
1121+ }
1122+
1123+ /*
1124+ * Convenience method used internally to throw exceptions when
1125+ * a case was forgotten in a switch statement.
1126+ */
1127+ private void stateError() {
1128+ throw new InternalError("missing case in transform state switch");
1129+ }
1130+
1131+ /**
1132+ * Retrieves the 6 specifiable values in the 3x3 affine transformation
1133+ * matrix and places them into an array of double precisions values.
1134+ * The values are stored in the array as
1135+ * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;m02&nbsp;m12&nbsp;}.
1136+ * An array of 4 doubles can also be specified, in which case only the
1137+ * first four elements representing the non-transform
1138+ * parts of the array are retrieved and the values are stored into
1139+ * the array as {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;}
1140+ * @param flatmatrix the double array used to store the returned
1141+ * values.
1142+ * @see #getScaleX
1143+ * @see #getScaleY
1144+ * @see #getShearX
1145+ * @see #getShearY
1146+ * @see #getTranslateX
1147+ * @see #getTranslateY
1148+ * @since 1.2
1149+ */
1150+ public void getMatrix(double[] flatmatrix) {
1151+ flatmatrix[0] = m00;
1152+ flatmatrix[1] = m10;
1153+ flatmatrix[2] = m01;
1154+ flatmatrix[3] = m11;
1155+ if (flatmatrix.length > 5) {
1156+ flatmatrix[4] = m02;
1157+ flatmatrix[5] = m12;
1158+ }
1159+ }
1160+
1161+ /**
1162+ * Returns the X coordinate scaling element (m00) of the 3x3
1163+ * affine transformation matrix.
1164+ * @return a double value that is the X coordinate of the scaling
1165+ * element of the affine transformation matrix.
1166+ * @see #getMatrix
1167+ * @since 1.2
1168+ */
1169+ public double getScaleX() {
1170+ return m00;
1171+ }
1172+
1173+ /**
1174+ * Returns the Y coordinate scaling element (m11) of the 3x3
1175+ * affine transformation matrix.
1176+ * @return a double value that is the Y coordinate of the scaling
1177+ * element of the affine transformation matrix.
1178+ * @see #getMatrix
1179+ * @since 1.2
1180+ */
1181+ public double getScaleY() {
1182+ return m11;
1183+ }
1184+
1185+ /**
1186+ * Returns the X coordinate shearing element (m01) of the 3x3
1187+ * affine transformation matrix.
1188+ * @return a double value that is the X coordinate of the shearing
1189+ * element of the affine transformation matrix.
1190+ * @see #getMatrix
1191+ * @since 1.2
1192+ */
1193+ public double getShearX() {
1194+ return m01;
1195+ }
1196+
1197+ /**
1198+ * Returns the Y coordinate shearing element (m10) of the 3x3
1199+ * affine transformation matrix.
1200+ * @return a double value that is the Y coordinate of the shearing
1201+ * element of the affine transformation matrix.
1202+ * @see #getMatrix
1203+ * @since 1.2
1204+ */
1205+ public double getShearY() {
1206+ return m10;
1207+ }
1208+
1209+ /**
1210+ * Returns the X coordinate of the translation element (m02) of the
1211+ * 3x3 affine transformation matrix.
1212+ * @return a double value that is the X coordinate of the translation
1213+ * element of the affine transformation matrix.
1214+ * @see #getMatrix
1215+ * @since 1.2
1216+ */
1217+ public double getTranslateX() {
1218+ return m02;
1219+ }
1220+
1221+ /**
1222+ * Returns the Y coordinate of the translation element (m12) of the
1223+ * 3x3 affine transformation matrix.
1224+ * @return a double value that is the Y coordinate of the translation
1225+ * element of the affine transformation matrix.
1226+ * @see #getMatrix
1227+ * @since 1.2
1228+ */
1229+ public double getTranslateY() {
1230+ return m12;
1231+ }
1232+
1233+ /**
1234+ * Concatenates this transform with a translation transformation.
1235+ * This is equivalent to calling concatenate(T), where T is an
1236+ * <code>AffineTransform</code> represented by the following matrix:
1237+ * <pre>
1238+ * [ 1 0 tx ]
1239+ * [ 0 1 ty ]
1240+ * [ 0 0 1 ]
1241+ * </pre>
1242+ * @param tx the distance by which coordinates are translated in the
1243+ * X axis direction
1244+ * @param ty the distance by which coordinates are translated in the
1245+ * Y axis direction
1246+ * @since 1.2
1247+ */
1248+ public void translate(double tx, double ty) {
1249+ switch (state) {
1250+ default:
1251+ stateError();
1252+ /* NOTREACHED */
1253+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1254+ m02 = tx * m00 + ty * m01 + m02;
1255+ m12 = tx * m10 + ty * m11 + m12;
1256+ if (m02 == 0.0 && m12 == 0.0) {
1257+ state = APPLY_SHEAR | APPLY_SCALE;
1258+ if (type != TYPE_UNKNOWN) {
1259+ type -= TYPE_TRANSLATION;
1260+ }
1261+ }
1262+ return;
1263+ case (APPLY_SHEAR | APPLY_SCALE):
1264+ m02 = tx * m00 + ty * m01;
1265+ m12 = tx * m10 + ty * m11;
1266+ if (m02 != 0.0 || m12 != 0.0) {
1267+ state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1268+ type |= TYPE_TRANSLATION;
1269+ }
1270+ return;
1271+ case (APPLY_SHEAR | APPLY_TRANSLATE):
1272+ m02 = ty * m01 + m02;
1273+ m12 = tx * m10 + m12;
1274+ if (m02 == 0.0 && m12 == 0.0) {
1275+ state = APPLY_SHEAR;
1276+ if (type != TYPE_UNKNOWN) {
1277+ type -= TYPE_TRANSLATION;
1278+ }
1279+ }
1280+ return;
1281+ case (APPLY_SHEAR):
1282+ m02 = ty * m01;
1283+ m12 = tx * m10;
1284+ if (m02 != 0.0 || m12 != 0.0) {
1285+ state = APPLY_SHEAR | APPLY_TRANSLATE;
1286+ type |= TYPE_TRANSLATION;
1287+ }
1288+ return;
1289+ case (APPLY_SCALE | APPLY_TRANSLATE):
1290+ m02 = tx * m00 + m02;
1291+ m12 = ty * m11 + m12;
1292+ if (m02 == 0.0 && m12 == 0.0) {
1293+ state = APPLY_SCALE;
1294+ if (type != TYPE_UNKNOWN) {
1295+ type -= TYPE_TRANSLATION;
1296+ }
1297+ }
1298+ return;
1299+ case (APPLY_SCALE):
1300+ m02 = tx * m00;
1301+ m12 = ty * m11;
1302+ if (m02 != 0.0 || m12 != 0.0) {
1303+ state = APPLY_SCALE | APPLY_TRANSLATE;
1304+ type |= TYPE_TRANSLATION;
1305+ }
1306+ return;
1307+ case (APPLY_TRANSLATE):
1308+ m02 = tx + m02;
1309+ m12 = ty + m12;
1310+ if (m02 == 0.0 && m12 == 0.0) {
1311+ state = APPLY_IDENTITY;
1312+ type = TYPE_IDENTITY;
1313+ }
1314+ return;
1315+ case (APPLY_IDENTITY):
1316+ m02 = tx;
1317+ m12 = ty;
1318+ if (tx != 0.0 || ty != 0.0) {
1319+ state = APPLY_TRANSLATE;
1320+ type = TYPE_TRANSLATION;
1321+ }
1322+ return;
1323+ }
1324+ }
1325+
1326+ // Utility methods to optimize rotate methods.
1327+ // These tables translate the flags during predictable quadrant
1328+ // rotations where the shear and scale values are swapped and negated.
1329+ private static final int rot90conversion[] = {
1330+ /* IDENTITY => */ APPLY_SHEAR,
1331+ /* TRANSLATE (TR) => */ APPLY_SHEAR | APPLY_TRANSLATE,
1332+ /* SCALE (SC) => */ APPLY_SHEAR,
1333+ /* SC | TR => */ APPLY_SHEAR | APPLY_TRANSLATE,
1334+ /* SHEAR (SH) => */ APPLY_SCALE,
1335+ /* SH | TR => */ APPLY_SCALE | APPLY_TRANSLATE,
1336+ /* SH | SC => */ APPLY_SHEAR | APPLY_SCALE,
1337+ /* SH | SC | TR => */ APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE,
1338+ };
1339+ private final void rotate90() {
1340+ double M0 = m00;
1341+ m00 = m01;
1342+ m01 = -M0;
1343+ M0 = m10;
1344+ m10 = m11;
1345+ m11 = -M0;
1346+ int state = rot90conversion[this.state];
1347+ if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1348+ m00 == 1.0 && m11 == 1.0)
1349+ {
1350+ state -= APPLY_SCALE;
1351+ }
1352+ this.state = state;
1353+ type = TYPE_UNKNOWN;
1354+ }
1355+ private final void rotate180() {
1356+ m00 = -m00;
1357+ m11 = -m11;
1358+ int state = this.state;
1359+ if ((state & (APPLY_SHEAR)) != 0) {
1360+ // If there was a shear, then this rotation has no
1361+ // effect on the state.
1362+ m01 = -m01;
1363+ m10 = -m10;
1364+ } else {
1365+ // No shear means the SCALE state may toggle when
1366+ // m00 and m11 are negated.
1367+ if (m00 == 1.0 && m11 == 1.0) {
1368+ this.state = state & ~APPLY_SCALE;
1369+ } else {
1370+ this.state = state | APPLY_SCALE;
1371+ }
1372+ }
1373+ type = TYPE_UNKNOWN;
1374+ }
1375+ private final void rotate270() {
1376+ double M0 = m00;
1377+ m00 = -m01;
1378+ m01 = M0;
1379+ M0 = m10;
1380+ m10 = -m11;
1381+ m11 = M0;
1382+ int state = rot90conversion[this.state];
1383+ if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1384+ m00 == 1.0 && m11 == 1.0)
1385+ {
1386+ state -= APPLY_SCALE;
1387+ }
1388+ this.state = state;
1389+ type = TYPE_UNKNOWN;
1390+ }
1391+
1392+ /**
1393+ * Concatenates this transform with a rotation transformation.
1394+ * This is equivalent to calling concatenate(R), where R is an
1395+ * <code>AffineTransform</code> represented by the following matrix:
1396+ * <pre>
1397+ * [ cos(theta) -sin(theta) 0 ]
1398+ * [ sin(theta) cos(theta) 0 ]
1399+ * [ 0 0 1 ]
1400+ * </pre>
1401+ * Rotating by a positive angle theta rotates points on the positive
1402+ * X axis toward the positive Y axis.
1403+ * Note also the discussion of
1404+ * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1405+ * above.
1406+ * @param theta the angle of rotation measured in radians
1407+ * @since 1.2
1408+ */
1409+ public void rotate(double theta) {
1410+ double sin = Math.sin(theta);
1411+ if (sin == 1.0) {
1412+ rotate90();
1413+ } else if (sin == -1.0) {
1414+ rotate270();
1415+ } else {
1416+ double cos = Math.cos(theta);
1417+ if (cos == -1.0) {
1418+ rotate180();
1419+ } else if (cos != 1.0) {
1420+ double M0, M1;
1421+ M0 = m00;
1422+ M1 = m01;
1423+ m00 = cos * M0 + sin * M1;
1424+ m01 = -sin * M0 + cos * M1;
1425+ M0 = m10;
1426+ M1 = m11;
1427+ m10 = cos * M0 + sin * M1;
1428+ m11 = -sin * M0 + cos * M1;
1429+ updateState();
1430+ }
1431+ }
1432+ }
1433+
1434+ /**
1435+ * Concatenates this transform with a transform that rotates
1436+ * coordinates around an anchor point.
1437+ * This operation is equivalent to translating the coordinates so
1438+ * that the anchor point is at the origin (S1), then rotating them
1439+ * about the new origin (S2), and finally translating so that the
1440+ * intermediate origin is restored to the coordinates of the original
1441+ * anchor point (S3).
1442+ * <p>
1443+ * This operation is equivalent to the following sequence of calls:
1444+ * <pre>
1445+ * translate(anchorx, anchory); // S3: final translation
1446+ * rotate(theta); // S2: rotate around anchor
1447+ * translate(-anchorx, -anchory); // S1: translate anchor to origin
1448+ * </pre>
1449+ * Rotating by a positive angle theta rotates points on the positive
1450+ * X axis toward the positive Y axis.
1451+ * Note also the discussion of
1452+ * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1453+ * above.
1454+ *
1455+ * @param theta the angle of rotation measured in radians
1456+ * @param anchorx the X coordinate of the rotation anchor point
1457+ * @param anchory the Y coordinate of the rotation anchor point
1458+ * @since 1.2
1459+ */
1460+ public void rotate(double theta, double anchorx, double anchory) {
1461+ // REMIND: Simple for now - optimize later
1462+ translate(anchorx, anchory);
1463+ rotate(theta);
1464+ translate(-anchorx, -anchory);
1465+ }
1466+
1467+ /**
1468+ * Concatenates this transform with a transform that rotates
1469+ * coordinates according to a rotation vector.
1470+ * All coordinates rotate about the origin by the same amount.
1471+ * The amount of rotation is such that coordinates along the former
1472+ * positive X axis will subsequently align with the vector pointing
1473+ * from the origin to the specified vector coordinates.
1474+ * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1475+ * no additional rotation is added to this transform.
1476+ * This operation is equivalent to calling:
1477+ * <pre>
1478+ * rotate(Math.atan2(vecy, vecx));
1479+ * </pre>
1480+ *
1481+ * @param vecx the X coordinate of the rotation vector
1482+ * @param vecy the Y coordinate of the rotation vector
1483+ * @since 1.6
1484+ */
1485+ public void rotate(double vecx, double vecy) {
1486+ if (vecy == 0.0) {
1487+ if (vecx < 0.0) {
1488+ rotate180();
1489+ }
1490+ // If vecx > 0.0 - no rotation
1491+ // If vecx == 0.0 - undefined rotation - treat as no rotation
1492+ } else if (vecx == 0.0) {
1493+ if (vecy > 0.0) {
1494+ rotate90();
1495+ } else { // vecy must be < 0.0
1496+ rotate270();
1497+ }
1498+ } else {
1499+ double len = Math.sqrt(vecx * vecx + vecy * vecy);
1500+ double sin = vecy / len;
1501+ double cos = vecx / len;
1502+ double M0, M1;
1503+ M0 = m00;
1504+ M1 = m01;
1505+ m00 = cos * M0 + sin * M1;
1506+ m01 = -sin * M0 + cos * M1;
1507+ M0 = m10;
1508+ M1 = m11;
1509+ m10 = cos * M0 + sin * M1;
1510+ m11 = -sin * M0 + cos * M1;
1511+ updateState();
1512+ }
1513+ }
1514+
1515+ /**
1516+ * Concatenates this transform with a transform that rotates
1517+ * coordinates around an anchor point according to a rotation
1518+ * vector.
1519+ * All coordinates rotate about the specified anchor coordinates
1520+ * by the same amount.
1521+ * The amount of rotation is such that coordinates along the former
1522+ * positive X axis will subsequently align with the vector pointing
1523+ * from the origin to the specified vector coordinates.
1524+ * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1525+ * the transform is not modified in any way.
1526+ * This method is equivalent to calling:
1527+ * <pre>
1528+ * rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1529+ * </pre>
1530+ *
1531+ * @param vecx the X coordinate of the rotation vector
1532+ * @param vecy the Y coordinate of the rotation vector
1533+ * @param anchorx the X coordinate of the rotation anchor point
1534+ * @param anchory the Y coordinate of the rotation anchor point
1535+ * @since 1.6
1536+ */
1537+ public void rotate(double vecx, double vecy,
1538+ double anchorx, double anchory)
1539+ {
1540+ // REMIND: Simple for now - optimize later
1541+ translate(anchorx, anchory);
1542+ rotate(vecx, vecy);
1543+ translate(-anchorx, -anchory);
1544+ }
1545+
1546+ /**
1547+ * Concatenates this transform with a transform that rotates
1548+ * coordinates by the specified number of quadrants.
1549+ * This is equivalent to calling:
1550+ * <pre>
1551+ * rotate(numquadrants * Math.PI / 2.0);
1552+ * </pre>
1553+ * Rotating by a positive number of quadrants rotates points on
1554+ * the positive X axis toward the positive Y axis.
1555+ * @param numquadrants the number of 90 degree arcs to rotate by
1556+ * @since 1.6
1557+ */
1558+ public void quadrantRotate(int numquadrants) {
1559+ switch (numquadrants & 3) {
1560+ case 0:
1561+ break;
1562+ case 1:
1563+ rotate90();
1564+ break;
1565+ case 2:
1566+ rotate180();
1567+ break;
1568+ case 3:
1569+ rotate270();
1570+ break;
1571+ }
1572+ }
1573+
1574+ /**
1575+ * Concatenates this transform with a transform that rotates
1576+ * coordinates by the specified number of quadrants around
1577+ * the specified anchor point.
1578+ * This method is equivalent to calling:
1579+ * <pre>
1580+ * rotate(numquadrants * Math.PI / 2.0, anchorx, anchory);
1581+ * </pre>
1582+ * Rotating by a positive number of quadrants rotates points on
1583+ * the positive X axis toward the positive Y axis.
1584+ *
1585+ * @param numquadrants the number of 90 degree arcs to rotate by
1586+ * @param anchorx the X coordinate of the rotation anchor point
1587+ * @param anchory the Y coordinate of the rotation anchor point
1588+ * @since 1.6
1589+ */
1590+ public void quadrantRotate(int numquadrants,
1591+ double anchorx, double anchory)
1592+ {
1593+ switch (numquadrants & 3) {
1594+ case 0:
1595+ return;
1596+ case 1:
1597+ m02 += anchorx * (m00 - m01) + anchory * (m01 + m00);
1598+ m12 += anchorx * (m10 - m11) + anchory * (m11 + m10);
1599+ rotate90();
1600+ break;
1601+ case 2:
1602+ m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1603+ m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1604+ rotate180();
1605+ break;
1606+ case 3:
1607+ m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1608+ m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1609+ rotate270();
1610+ break;
1611+ }
1612+ if (m02 == 0.0 && m12 == 0.0) {
1613+ state &= ~APPLY_TRANSLATE;
1614+ } else {
1615+ state |= APPLY_TRANSLATE;
1616+ }
1617+ }
1618+
1619+ /**
1620+ * Concatenates this transform with a scaling transformation.
1621+ * This is equivalent to calling concatenate(S), where S is an
1622+ * <code>AffineTransform</code> represented by the following matrix:
1623+ * <pre>
1624+ * [ sx 0 0 ]
1625+ * [ 0 sy 0 ]
1626+ * [ 0 0 1 ]
1627+ * </pre>
1628+ * @param sx the factor by which coordinates are scaled along the
1629+ * X axis direction
1630+ * @param sy the factor by which coordinates are scaled along the
1631+ * Y axis direction
1632+ * @since 1.2
1633+ */
1634+ public void scale(double sx, double sy) {
1635+ int state = this.state;
1636+ switch (state) {
1637+ default:
1638+ stateError();
1639+ /* NOTREACHED */
1640+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1641+ case (APPLY_SHEAR | APPLY_SCALE):
1642+ m00 *= sx;
1643+ m11 *= sy;
1644+ /* NOBREAK */
1645+ case (APPLY_SHEAR | APPLY_TRANSLATE):
1646+ case (APPLY_SHEAR):
1647+ m01 *= sy;
1648+ m10 *= sx;
1649+ if (m01 == 0 && m10 == 0) {
1650+ state &= APPLY_TRANSLATE;
1651+ if (m00 == 1.0 && m11 == 1.0) {
1652+ this.type = (state == APPLY_IDENTITY
1653+ ? TYPE_IDENTITY
1654+ : TYPE_TRANSLATION);
1655+ } else {
1656+ state |= APPLY_SCALE;
1657+ this.type = TYPE_UNKNOWN;
1658+ }
1659+ this.state = state;
1660+ }
1661+ return;
1662+ case (APPLY_SCALE | APPLY_TRANSLATE):
1663+ case (APPLY_SCALE):
1664+ m00 *= sx;
1665+ m11 *= sy;
1666+ if (m00 == 1.0 && m11 == 1.0) {
1667+ this.state = (state &= APPLY_TRANSLATE);
1668+ this.type = (state == APPLY_IDENTITY
1669+ ? TYPE_IDENTITY
1670+ : TYPE_TRANSLATION);
1671+ } else {
1672+ this.type = TYPE_UNKNOWN;
1673+ }
1674+ return;
1675+ case (APPLY_TRANSLATE):
1676+ case (APPLY_IDENTITY):
1677+ m00 = sx;
1678+ m11 = sy;
1679+ if (sx != 1.0 || sy != 1.0) {
1680+ this.state = state | APPLY_SCALE;
1681+ this.type = TYPE_UNKNOWN;
1682+ }
1683+ return;
1684+ }
1685+ }
1686+
1687+ /**
1688+ * Concatenates this transform with a shearing transformation.
1689+ * This is equivalent to calling concatenate(SH), where SH is an
1690+ * <code>AffineTransform</code> represented by the following matrix:
1691+ * <pre>
1692+ * [ 1 shx 0 ]
1693+ * [ shy 1 0 ]
1694+ * [ 0 0 1 ]
1695+ * </pre>
1696+ * @param shx the multiplier by which coordinates are shifted in the
1697+ * direction of the positive X axis as a factor of their Y coordinate
1698+ * @param shy the multiplier by which coordinates are shifted in the
1699+ * direction of the positive Y axis as a factor of their X coordinate
1700+ * @since 1.2
1701+ */
1702+ public void shear(double shx, double shy) {
1703+ int state = this.state;
1704+ switch (state) {
1705+ default:
1706+ stateError();
1707+ /* NOTREACHED */
1708+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1709+ case (APPLY_SHEAR | APPLY_SCALE):
1710+ double M0, M1;
1711+ M0 = m00;
1712+ M1 = m01;
1713+ m00 = M0 + M1 * shy;
1714+ m01 = M0 * shx + M1;
1715+
1716+ M0 = m10;
1717+ M1 = m11;
1718+ m10 = M0 + M1 * shy;
1719+ m11 = M0 * shx + M1;
1720+ updateState();
1721+ return;
1722+ case (APPLY_SHEAR | APPLY_TRANSLATE):
1723+ case (APPLY_SHEAR):
1724+ m00 = m01 * shy;
1725+ m11 = m10 * shx;
1726+ if (m00 != 0.0 || m11 != 0.0) {
1727+ this.state = state | APPLY_SCALE;
1728+ }
1729+ this.type = TYPE_UNKNOWN;
1730+ return;
1731+ case (APPLY_SCALE | APPLY_TRANSLATE):
1732+ case (APPLY_SCALE):
1733+ m01 = m00 * shx;
1734+ m10 = m11 * shy;
1735+ if (m01 != 0.0 || m10 != 0.0) {
1736+ this.state = state | APPLY_SHEAR;
1737+ }
1738+ this.type = TYPE_UNKNOWN;
1739+ return;
1740+ case (APPLY_TRANSLATE):
1741+ case (APPLY_IDENTITY):
1742+ m01 = shx;
1743+ m10 = shy;
1744+ if (m01 != 0.0 || m10 != 0.0) {
1745+ this.state = state | APPLY_SCALE | APPLY_SHEAR;
1746+ this.type = TYPE_UNKNOWN;
1747+ }
1748+ return;
1749+ }
1750+ }
1751+
1752+ /**
1753+ * Resets this transform to the Identity transform.
1754+ * @since 1.2
1755+ */
1756+ public void setToIdentity() {
1757+ m00 = m11 = 1.0;
1758+ m10 = m01 = m02 = m12 = 0.0;
1759+ state = APPLY_IDENTITY;
1760+ type = TYPE_IDENTITY;
1761+ }
1762+
1763+ /**
1764+ * Sets this transform to a translation transformation.
1765+ * The matrix representing this transform becomes:
1766+ * <pre>
1767+ * [ 1 0 tx ]
1768+ * [ 0 1 ty ]
1769+ * [ 0 0 1 ]
1770+ * </pre>
1771+ * @param tx the distance by which coordinates are translated in the
1772+ * X axis direction
1773+ * @param ty the distance by which coordinates are translated in the
1774+ * Y axis direction
1775+ * @since 1.2
1776+ */
1777+ public void setToTranslation(double tx, double ty) {
1778+ m00 = 1.0;
1779+ m10 = 0.0;
1780+ m01 = 0.0;
1781+ m11 = 1.0;
1782+ m02 = tx;
1783+ m12 = ty;
1784+ if (tx != 0.0 || ty != 0.0) {
1785+ state = APPLY_TRANSLATE;
1786+ type = TYPE_TRANSLATION;
1787+ } else {
1788+ state = APPLY_IDENTITY;
1789+ type = TYPE_IDENTITY;
1790+ }
1791+ }
1792+
1793+ /**
1794+ * Sets this transform to a rotation transformation.
1795+ * The matrix representing this transform becomes:
1796+ * <pre>
1797+ * [ cos(theta) -sin(theta) 0 ]
1798+ * [ sin(theta) cos(theta) 0 ]
1799+ * [ 0 0 1 ]
1800+ * </pre>
1801+ * Rotating by a positive angle theta rotates points on the positive
1802+ * X axis toward the positive Y axis.
1803+ * Note also the discussion of
1804+ * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1805+ * above.
1806+ * @param theta the angle of rotation measured in radians
1807+ * @since 1.2
1808+ */
1809+ public void setToRotation(double theta) {
1810+ double sin = Math.sin(theta);
1811+ double cos;
1812+ if (sin == 1.0 || sin == -1.0) {
1813+ cos = 0.0;
1814+ state = APPLY_SHEAR;
1815+ type = TYPE_QUADRANT_ROTATION;
1816+ } else {
1817+ cos = Math.cos(theta);
1818+ if (cos == -1.0) {
1819+ sin = 0.0;
1820+ state = APPLY_SCALE;
1821+ type = TYPE_QUADRANT_ROTATION;
1822+ } else if (cos == 1.0) {
1823+ sin = 0.0;
1824+ state = APPLY_IDENTITY;
1825+ type = TYPE_IDENTITY;
1826+ } else {
1827+ state = APPLY_SHEAR | APPLY_SCALE;
1828+ type = TYPE_GENERAL_ROTATION;
1829+ }
1830+ }
1831+ m00 = cos;
1832+ m10 = sin;
1833+ m01 = -sin;
1834+ m11 = cos;
1835+ m02 = 0.0;
1836+ m12 = 0.0;
1837+ }
1838+
1839+ /**
1840+ * Sets this transform to a translated rotation transformation.
1841+ * This operation is equivalent to translating the coordinates so
1842+ * that the anchor point is at the origin (S1), then rotating them
1843+ * about the new origin (S2), and finally translating so that the
1844+ * intermediate origin is restored to the coordinates of the original
1845+ * anchor point (S3).
1846+ * <p>
1847+ * This operation is equivalent to the following sequence of calls:
1848+ * <pre>
1849+ * setToTranslation(anchorx, anchory); // S3: final translation
1850+ * rotate(theta); // S2: rotate around anchor
1851+ * translate(-anchorx, -anchory); // S1: translate anchor to origin
1852+ * </pre>
1853+ * The matrix representing this transform becomes:
1854+ * <pre>
1855+ * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
1856+ * [ sin(theta) cos(theta) y-x*sin-y*cos ]
1857+ * [ 0 0 1 ]
1858+ * </pre>
1859+ * Rotating by a positive angle theta rotates points on the positive
1860+ * X axis toward the positive Y axis.
1861+ * Note also the discussion of
1862+ * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1863+ * above.
1864+ *
1865+ * @param theta the angle of rotation measured in radians
1866+ * @param anchorx the X coordinate of the rotation anchor point
1867+ * @param anchory the Y coordinate of the rotation anchor point
1868+ * @since 1.2
1869+ */
1870+ public void setToRotation(double theta, double anchorx, double anchory) {
1871+ setToRotation(theta);
1872+ double sin = m10;
1873+ double oneMinusCos = 1.0 - m00;
1874+ m02 = anchorx * oneMinusCos + anchory * sin;
1875+ m12 = anchory * oneMinusCos - anchorx * sin;
1876+ if (m02 != 0.0 || m12 != 0.0) {
1877+ state |= APPLY_TRANSLATE;
1878+ type |= TYPE_TRANSLATION;
1879+ }
1880+ }
1881+
1882+ /**
1883+ * Sets this transform to a rotation transformation that rotates
1884+ * coordinates according to a rotation vector.
1885+ * All coordinates rotate about the origin by the same amount.
1886+ * The amount of rotation is such that coordinates along the former
1887+ * positive X axis will subsequently align with the vector pointing
1888+ * from the origin to the specified vector coordinates.
1889+ * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1890+ * the transform is set to an identity transform.
1891+ * This operation is equivalent to calling:
1892+ * <pre>
1893+ * setToRotation(Math.atan2(vecy, vecx));
1894+ * </pre>
1895+ *
1896+ * @param vecx the X coordinate of the rotation vector
1897+ * @param vecy the Y coordinate of the rotation vector
1898+ * @since 1.6
1899+ */
1900+ public void setToRotation(double vecx, double vecy) {
1901+ double sin, cos;
1902+ if (vecy == 0) {
1903+ sin = 0.0;
1904+ if (vecx < 0.0) {
1905+ cos = -1.0;
1906+ state = APPLY_SCALE;
1907+ type = TYPE_QUADRANT_ROTATION;
1908+ } else {
1909+ cos = 1.0;
1910+ state = APPLY_IDENTITY;
1911+ type = TYPE_IDENTITY;
1912+ }
1913+ } else if (vecx == 0) {
1914+ cos = 0.0;
1915+ sin = (vecy > 0.0) ? 1.0 : -1.0;
1916+ state = APPLY_SHEAR;
1917+ type = TYPE_QUADRANT_ROTATION;
1918+ } else {
1919+ double len = Math.sqrt(vecx * vecx + vecy * vecy);
1920+ cos = vecx / len;
1921+ sin = vecy / len;
1922+ state = APPLY_SHEAR | APPLY_SCALE;
1923+ type = TYPE_GENERAL_ROTATION;
1924+ }
1925+ m00 = cos;
1926+ m10 = sin;
1927+ m01 = -sin;
1928+ m11 = cos;
1929+ m02 = 0.0;
1930+ m12 = 0.0;
1931+ }
1932+
1933+ /**
1934+ * Sets this transform to a rotation transformation that rotates
1935+ * coordinates around an anchor point according to a rotation
1936+ * vector.
1937+ * All coordinates rotate about the specified anchor coordinates
1938+ * by the same amount.
1939+ * The amount of rotation is such that coordinates along the former
1940+ * positive X axis will subsequently align with the vector pointing
1941+ * from the origin to the specified vector coordinates.
1942+ * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1943+ * the transform is set to an identity transform.
1944+ * This operation is equivalent to calling:
1945+ * <pre>
1946+ * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1947+ * </pre>
1948+ *
1949+ * @param vecx the X coordinate of the rotation vector
1950+ * @param vecy the Y coordinate of the rotation vector
1951+ * @param anchorx the X coordinate of the rotation anchor point
1952+ * @param anchory the Y coordinate of the rotation anchor point
1953+ * @since 1.6
1954+ */
1955+ public void setToRotation(double vecx, double vecy,
1956+ double anchorx, double anchory)
1957+ {
1958+ setToRotation(vecx, vecy);
1959+ double sin = m10;
1960+ double oneMinusCos = 1.0 - m00;
1961+ m02 = anchorx * oneMinusCos + anchory * sin;
1962+ m12 = anchory * oneMinusCos - anchorx * sin;
1963+ if (m02 != 0.0 || m12 != 0.0) {
1964+ state |= APPLY_TRANSLATE;
1965+ type |= TYPE_TRANSLATION;
1966+ }
1967+ }
1968+
1969+ /**
1970+ * Sets this transform to a rotation transformation that rotates
1971+ * coordinates by the specified number of quadrants.
1972+ * This operation is equivalent to calling:
1973+ * <pre>
1974+ * setToRotation(numquadrants * Math.PI / 2.0);
1975+ * </pre>
1976+ * Rotating by a positive number of quadrants rotates points on
1977+ * the positive X axis toward the positive Y axis.
1978+ * @param numquadrants the number of 90 degree arcs to rotate by
1979+ * @since 1.6
1980+ */
1981+ public void setToQuadrantRotation(int numquadrants) {
1982+ switch (numquadrants & 3) {
1983+ case 0:
1984+ m00 = 1.0;
1985+ m10 = 0.0;
1986+ m01 = 0.0;
1987+ m11 = 1.0;
1988+ m02 = 0.0;
1989+ m12 = 0.0;
1990+ state = APPLY_IDENTITY;
1991+ type = TYPE_IDENTITY;
1992+ break;
1993+ case 1:
1994+ m00 = 0.0;
1995+ m10 = 1.0;
1996+ m01 = -1.0;
1997+ m11 = 0.0;
1998+ m02 = 0.0;
1999+ m12 = 0.0;
2000+ state = APPLY_SHEAR;
2001+ type = TYPE_QUADRANT_ROTATION;
2002+ break;
2003+ case 2:
2004+ m00 = -1.0;
2005+ m10 = 0.0;
2006+ m01 = 0.0;
2007+ m11 = -1.0;
2008+ m02 = 0.0;
2009+ m12 = 0.0;
2010+ state = APPLY_SCALE;
2011+ type = TYPE_QUADRANT_ROTATION;
2012+ break;
2013+ case 3:
2014+ m00 = 0.0;
2015+ m10 = -1.0;
2016+ m01 = 1.0;
2017+ m11 = 0.0;
2018+ m02 = 0.0;
2019+ m12 = 0.0;
2020+ state = APPLY_SHEAR;
2021+ type = TYPE_QUADRANT_ROTATION;
2022+ break;
2023+ }
2024+ }
2025+
2026+ /**
2027+ * Sets this transform to a translated rotation transformation
2028+ * that rotates coordinates by the specified number of quadrants
2029+ * around the specified anchor point.
2030+ * This operation is equivalent to calling:
2031+ * <pre>
2032+ * setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory);
2033+ * </pre>
2034+ * Rotating by a positive number of quadrants rotates points on
2035+ * the positive X axis toward the positive Y axis.
2036+ *
2037+ * @param numquadrants the number of 90 degree arcs to rotate by
2038+ * @param anchorx the X coordinate of the rotation anchor point
2039+ * @param anchory the Y coordinate of the rotation anchor point
2040+ * @since 1.6
2041+ */
2042+ public void setToQuadrantRotation(int numquadrants,
2043+ double anchorx, double anchory)
2044+ {
2045+ switch (numquadrants & 3) {
2046+ case 0:
2047+ m00 = 1.0;
2048+ m10 = 0.0;
2049+ m01 = 0.0;
2050+ m11 = 1.0;
2051+ m02 = 0.0;
2052+ m12 = 0.0;
2053+ state = APPLY_IDENTITY;
2054+ type = TYPE_IDENTITY;
2055+ break;
2056+ case 1:
2057+ m00 = 0.0;
2058+ m10 = 1.0;
2059+ m01 = -1.0;
2060+ m11 = 0.0;
2061+ m02 = anchorx + anchory;
2062+ m12 = anchory - anchorx;
2063+ if (m02 == 0.0 && m12 == 0.0) {
2064+ state = APPLY_SHEAR;
2065+ type = TYPE_QUADRANT_ROTATION;
2066+ } else {
2067+ state = APPLY_SHEAR | APPLY_TRANSLATE;
2068+ type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2069+ }
2070+ break;
2071+ case 2:
2072+ m00 = -1.0;
2073+ m10 = 0.0;
2074+ m01 = 0.0;
2075+ m11 = -1.0;
2076+ m02 = anchorx + anchorx;
2077+ m12 = anchory + anchory;
2078+ if (m02 == 0.0 && m12 == 0.0) {
2079+ state = APPLY_SCALE;
2080+ type = TYPE_QUADRANT_ROTATION;
2081+ } else {
2082+ state = APPLY_SCALE | APPLY_TRANSLATE;
2083+ type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2084+ }
2085+ break;
2086+ case 3:
2087+ m00 = 0.0;
2088+ m10 = -1.0;
2089+ m01 = 1.0;
2090+ m11 = 0.0;
2091+ m02 = anchorx - anchory;
2092+ m12 = anchory + anchorx;
2093+ if (m02 == 0.0 && m12 == 0.0) {
2094+ state = APPLY_SHEAR;
2095+ type = TYPE_QUADRANT_ROTATION;
2096+ } else {
2097+ state = APPLY_SHEAR | APPLY_TRANSLATE;
2098+ type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2099+ }
2100+ break;
2101+ }
2102+ }
2103+
2104+ /**
2105+ * Sets this transform to a scaling transformation.
2106+ * The matrix representing this transform becomes:
2107+ * <pre>
2108+ * [ sx 0 0 ]
2109+ * [ 0 sy 0 ]
2110+ * [ 0 0 1 ]
2111+ * </pre>
2112+ * @param sx the factor by which coordinates are scaled along the
2113+ * X axis direction
2114+ * @param sy the factor by which coordinates are scaled along the
2115+ * Y axis direction
2116+ * @since 1.2
2117+ */
2118+ public void setToScale(double sx, double sy) {
2119+ m00 = sx;
2120+ m10 = 0.0;
2121+ m01 = 0.0;
2122+ m11 = sy;
2123+ m02 = 0.0;
2124+ m12 = 0.0;
2125+ if (sx != 1.0 || sy != 1.0) {
2126+ state = APPLY_SCALE;
2127+ type = TYPE_UNKNOWN;
2128+ } else {
2129+ state = APPLY_IDENTITY;
2130+ type = TYPE_IDENTITY;
2131+ }
2132+ }
2133+
2134+ /**
2135+ * Sets this transform to a shearing transformation.
2136+ * The matrix representing this transform becomes:
2137+ * <pre>
2138+ * [ 1 shx 0 ]
2139+ * [ shy 1 0 ]
2140+ * [ 0 0 1 ]
2141+ * </pre>
2142+ * @param shx the multiplier by which coordinates are shifted in the
2143+ * direction of the positive X axis as a factor of their Y coordinate
2144+ * @param shy the multiplier by which coordinates are shifted in the
2145+ * direction of the positive Y axis as a factor of their X coordinate
2146+ * @since 1.2
2147+ */
2148+ public void setToShear(double shx, double shy) {
2149+ m00 = 1.0;
2150+ m01 = shx;
2151+ m10 = shy;
2152+ m11 = 1.0;
2153+ m02 = 0.0;
2154+ m12 = 0.0;
2155+ if (shx != 0.0 || shy != 0.0) {
2156+ state = (APPLY_SHEAR | APPLY_SCALE);
2157+ type = TYPE_UNKNOWN;
2158+ } else {
2159+ state = APPLY_IDENTITY;
2160+ type = TYPE_IDENTITY;
2161+ }
2162+ }
2163+
2164+ /**
2165+ * Sets this transform to a copy of the transform in the specified
2166+ * <code>AffineTransform</code> object.
2167+ * @param Tx the <code>AffineTransform</code> object from which to
2168+ * copy the transform
2169+ * @since 1.2
2170+ */
2171+ public void setTransform(AffineTransform Tx) {
2172+ this.m00 = Tx.m00;
2173+ this.m10 = Tx.m10;
2174+ this.m01 = Tx.m01;
2175+ this.m11 = Tx.m11;
2176+ this.m02 = Tx.m02;
2177+ this.m12 = Tx.m12;
2178+ this.state = Tx.state;
2179+ this.type = Tx.type;
2180+ }
2181+
2182+ /**
2183+ * Sets this transform to the matrix specified by the 6
2184+ * double precision values.
2185+ *
2186+ * @param m00 the X coordinate scaling element of the 3x3 matrix
2187+ * @param m10 the Y coordinate shearing element of the 3x3 matrix
2188+ * @param m01 the X coordinate shearing element of the 3x3 matrix
2189+ * @param m11 the Y coordinate scaling element of the 3x3 matrix
2190+ * @param m02 the X coordinate translation element of the 3x3 matrix
2191+ * @param m12 the Y coordinate translation element of the 3x3 matrix
2192+ * @since 1.2
2193+ */
2194+ public void setTransform(double m00, double m10,
2195+ double m01, double m11,
2196+ double m02, double m12) {
2197+ this.m00 = m00;
2198+ this.m10 = m10;
2199+ this.m01 = m01;
2200+ this.m11 = m11;
2201+ this.m02 = m02;
2202+ this.m12 = m12;
2203+ updateState();
2204+ }
2205+
2206+ /**
2207+ * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2208+ * this <code>AffineTransform</code> Cx in the most commonly useful
2209+ * way to provide a new user space
2210+ * that is mapped to the former user space by <code>Tx</code>.
2211+ * Cx is updated to perform the combined transformation.
2212+ * Transforming a point p by the updated transform Cx' is
2213+ * equivalent to first transforming p by <code>Tx</code> and then
2214+ * transforming the result by the original transform Cx like this:
2215+ * Cx'(p) = Cx(Tx(p))
2216+ * In matrix notation, if this transform Cx is
2217+ * represented by the matrix [this] and <code>Tx</code> is represented
2218+ * by the matrix [Tx] then this method does the following:
2219+ * <pre>
2220+ * [this] = [this] x [Tx]
2221+ * </pre>
2222+ * @param Tx the <code>AffineTransform</code> object to be
2223+ * concatenated with this <code>AffineTransform</code> object.
2224+ * @see #preConcatenate
2225+ * @since 1.2
2226+ */
2227+ public void concatenate(AffineTransform Tx) {
2228+ double M0, M1;
2229+ double T00, T01, T10, T11;
2230+ double T02, T12;
2231+ int mystate = state;
2232+ int txstate = Tx.state;
2233+ switch ((txstate << HI_SHIFT) | mystate) {
2234+
2235+ /* ---------- Tx == IDENTITY cases ---------- */
2236+ case (HI_IDENTITY | APPLY_IDENTITY):
2237+ case (HI_IDENTITY | APPLY_TRANSLATE):
2238+ case (HI_IDENTITY | APPLY_SCALE):
2239+ case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2240+ case (HI_IDENTITY | APPLY_SHEAR):
2241+ case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2242+ case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2243+ case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2244+ return;
2245+
2246+ /* ---------- this == IDENTITY cases ---------- */
2247+ case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2248+ m01 = Tx.m01;
2249+ m10 = Tx.m10;
2250+ /* NOBREAK */
2251+ case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2252+ m00 = Tx.m00;
2253+ m11 = Tx.m11;
2254+ /* NOBREAK */
2255+ case (HI_TRANSLATE | APPLY_IDENTITY):
2256+ m02 = Tx.m02;
2257+ m12 = Tx.m12;
2258+ state = txstate;
2259+ type = Tx.type;
2260+ return;
2261+ case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
2262+ m01 = Tx.m01;
2263+ m10 = Tx.m10;
2264+ /* NOBREAK */
2265+ case (HI_SCALE | APPLY_IDENTITY):
2266+ m00 = Tx.m00;
2267+ m11 = Tx.m11;
2268+ state = txstate;
2269+ type = Tx.type;
2270+ return;
2271+ case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
2272+ m02 = Tx.m02;
2273+ m12 = Tx.m12;
2274+ /* NOBREAK */
2275+ case (HI_SHEAR | APPLY_IDENTITY):
2276+ m01 = Tx.m01;
2277+ m10 = Tx.m10;
2278+ m00 = m11 = 0.0;
2279+ state = txstate;
2280+ type = Tx.type;
2281+ return;
2282+
2283+ /* ---------- Tx == TRANSLATE cases ---------- */
2284+ case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2285+ case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2286+ case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2287+ case (HI_TRANSLATE | APPLY_SHEAR):
2288+ case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2289+ case (HI_TRANSLATE | APPLY_SCALE):
2290+ case (HI_TRANSLATE | APPLY_TRANSLATE):
2291+ translate(Tx.m02, Tx.m12);
2292+ return;
2293+
2294+ /* ---------- Tx == SCALE cases ---------- */
2295+ case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2296+ case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2297+ case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2298+ case (HI_SCALE | APPLY_SHEAR):
2299+ case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2300+ case (HI_SCALE | APPLY_SCALE):
2301+ case (HI_SCALE | APPLY_TRANSLATE):
2302+ scale(Tx.m00, Tx.m11);
2303+ return;
2304+
2305+ /* ---------- Tx == SHEAR cases ---------- */
2306+ case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2307+ case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2308+ T01 = Tx.m01; T10 = Tx.m10;
2309+ M0 = m00;
2310+ m00 = m01 * T10;
2311+ m01 = M0 * T01;
2312+ M0 = m10;
2313+ m10 = m11 * T10;
2314+ m11 = M0 * T01;
2315+ type = TYPE_UNKNOWN;
2316+ return;
2317+ case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2318+ case (HI_SHEAR | APPLY_SHEAR):
2319+ m00 = m01 * Tx.m10;
2320+ m01 = 0.0;
2321+ m11 = m10 * Tx.m01;
2322+ m10 = 0.0;
2323+ state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2324+ type = TYPE_UNKNOWN;
2325+ return;
2326+ case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2327+ case (HI_SHEAR | APPLY_SCALE):
2328+ m01 = m00 * Tx.m01;
2329+ m00 = 0.0;
2330+ m10 = m11 * Tx.m10;
2331+ m11 = 0.0;
2332+ state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2333+ type = TYPE_UNKNOWN;
2334+ return;
2335+ case (HI_SHEAR | APPLY_TRANSLATE):
2336+ m00 = 0.0;
2337+ m01 = Tx.m01;
2338+ m10 = Tx.m10;
2339+ m11 = 0.0;
2340+ state = APPLY_TRANSLATE | APPLY_SHEAR;
2341+ type = TYPE_UNKNOWN;
2342+ return;
2343+ }
2344+ // If Tx has more than one attribute, it is not worth optimizing
2345+ // all of those cases...
2346+ T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
2347+ T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
2348+ switch (mystate) {
2349+ default:
2350+ stateError();
2351+ /* NOTREACHED */
2352+ case (APPLY_SHEAR | APPLY_SCALE):
2353+ state = mystate | txstate;
2354+ /* NOBREAK */
2355+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2356+ M0 = m00;
2357+ M1 = m01;
2358+ m00 = T00 * M0 + T10 * M1;
2359+ m01 = T01 * M0 + T11 * M1;
2360+ m02 += T02 * M0 + T12 * M1;
2361+
2362+ M0 = m10;
2363+ M1 = m11;
2364+ m10 = T00 * M0 + T10 * M1;
2365+ m11 = T01 * M0 + T11 * M1;
2366+ m12 += T02 * M0 + T12 * M1;
2367+ type = TYPE_UNKNOWN;
2368+ return;
2369+
2370+ case (APPLY_SHEAR | APPLY_TRANSLATE):
2371+ case (APPLY_SHEAR):
2372+ M0 = m01;
2373+ m00 = T10 * M0;
2374+ m01 = T11 * M0;
2375+ m02 += T12 * M0;
2376+
2377+ M0 = m10;
2378+ m10 = T00 * M0;
2379+ m11 = T01 * M0;
2380+ m12 += T02 * M0;
2381+ break;
2382+
2383+ case (APPLY_SCALE | APPLY_TRANSLATE):
2384+ case (APPLY_SCALE):
2385+ M0 = m00;
2386+ m00 = T00 * M0;
2387+ m01 = T01 * M0;
2388+ m02 += T02 * M0;
2389+
2390+ M0 = m11;
2391+ m10 = T10 * M0;
2392+ m11 = T11 * M0;
2393+ m12 += T12 * M0;
2394+ break;
2395+
2396+ case (APPLY_TRANSLATE):
2397+ m00 = T00;
2398+ m01 = T01;
2399+ m02 += T02;
2400+
2401+ m10 = T10;
2402+ m11 = T11;
2403+ m12 += T12;
2404+ state = txstate | APPLY_TRANSLATE;
2405+ type = TYPE_UNKNOWN;
2406+ return;
2407+ }
2408+ updateState();
2409+ }
2410+
2411+ /**
2412+ * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2413+ * this <code>AffineTransform</code> Cx
2414+ * in a less commonly used way such that <code>Tx</code> modifies the
2415+ * coordinate transformation relative to the absolute pixel
2416+ * space rather than relative to the existing user space.
2417+ * Cx is updated to perform the combined transformation.
2418+ * Transforming a point p by the updated transform Cx' is
2419+ * equivalent to first transforming p by the original transform
2420+ * Cx and then transforming the result by
2421+ * <code>Tx</code> like this:
2422+ * Cx'(p) = Tx(Cx(p))
2423+ * In matrix notation, if this transform Cx
2424+ * is represented by the matrix [this] and <code>Tx</code> is
2425+ * represented by the matrix [Tx] then this method does the
2426+ * following:
2427+ * <pre>
2428+ * [this] = [Tx] x [this]
2429+ * </pre>
2430+ * @param Tx the <code>AffineTransform</code> object to be
2431+ * concatenated with this <code>AffineTransform</code> object.
2432+ * @see #concatenate
2433+ * @since 1.2
2434+ */
2435+ public void preConcatenate(AffineTransform Tx) {
2436+ double M0, M1;
2437+ double T00, T01, T10, T11;
2438+ double T02, T12;
2439+ int mystate = state;
2440+ int txstate = Tx.state;
2441+ switch ((txstate << HI_SHIFT) | mystate) {
2442+ case (HI_IDENTITY | APPLY_IDENTITY):
2443+ case (HI_IDENTITY | APPLY_TRANSLATE):
2444+ case (HI_IDENTITY | APPLY_SCALE):
2445+ case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2446+ case (HI_IDENTITY | APPLY_SHEAR):
2447+ case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2448+ case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2449+ case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2450+ // Tx is IDENTITY...
2451+ return;
2452+
2453+ case (HI_TRANSLATE | APPLY_IDENTITY):
2454+ case (HI_TRANSLATE | APPLY_SCALE):
2455+ case (HI_TRANSLATE | APPLY_SHEAR):
2456+ case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2457+ // Tx is TRANSLATE, this has no TRANSLATE
2458+ m02 = Tx.m02;
2459+ m12 = Tx.m12;
2460+ state = mystate | APPLY_TRANSLATE;
2461+ type |= TYPE_TRANSLATION;
2462+ return;
2463+
2464+ case (HI_TRANSLATE | APPLY_TRANSLATE):
2465+ case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2466+ case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2467+ case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2468+ // Tx is TRANSLATE, this has one too
2469+ m02 = m02 + Tx.m02;
2470+ m12 = m12 + Tx.m12;
2471+ return;
2472+
2473+ case (HI_SCALE | APPLY_TRANSLATE):
2474+ case (HI_SCALE | APPLY_IDENTITY):
2475+ // Only these two existing states need a new state
2476+ state = mystate | APPLY_SCALE;
2477+ /* NOBREAK */
2478+ case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2479+ case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2480+ case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2481+ case (HI_SCALE | APPLY_SHEAR):
2482+ case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2483+ case (HI_SCALE | APPLY_SCALE):
2484+ // Tx is SCALE, this is anything
2485+ T00 = Tx.m00;
2486+ T11 = Tx.m11;
2487+ if ((mystate & APPLY_SHEAR) != 0) {
2488+ m01 = m01 * T00;
2489+ m10 = m10 * T11;
2490+ if ((mystate & APPLY_SCALE) != 0) {
2491+ m00 = m00 * T00;
2492+ m11 = m11 * T11;
2493+ }
2494+ } else {
2495+ m00 = m00 * T00;
2496+ m11 = m11 * T11;
2497+ }
2498+ if ((mystate & APPLY_TRANSLATE) != 0) {
2499+ m02 = m02 * T00;
2500+ m12 = m12 * T11;
2501+ }
2502+ type = TYPE_UNKNOWN;
2503+ return;
2504+ case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2505+ case (HI_SHEAR | APPLY_SHEAR):
2506+ mystate = mystate | APPLY_SCALE;
2507+ /* NOBREAK */
2508+ case (HI_SHEAR | APPLY_TRANSLATE):
2509+ case (HI_SHEAR | APPLY_IDENTITY):
2510+ case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2511+ case (HI_SHEAR | APPLY_SCALE):
2512+ state = mystate ^ APPLY_SHEAR;
2513+ /* NOBREAK */
2514+ case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2515+ case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2516+ // Tx is SHEAR, this is anything
2517+ T01 = Tx.m01;
2518+ T10 = Tx.m10;
2519+
2520+ M0 = m00;
2521+ m00 = m10 * T01;
2522+ m10 = M0 * T10;
2523+
2524+ M0 = m01;
2525+ m01 = m11 * T01;
2526+ m11 = M0 * T10;
2527+
2528+ M0 = m02;
2529+ m02 = m12 * T01;
2530+ m12 = M0 * T10;
2531+ type = TYPE_UNKNOWN;
2532+ return;
2533+ }
2534+ // If Tx has more than one attribute, it is not worth optimizing
2535+ // all of those cases...
2536+ T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
2537+ T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
2538+ switch (mystate) {
2539+ default:
2540+ stateError();
2541+ /* NOTREACHED */
2542+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2543+ M0 = m02;
2544+ M1 = m12;
2545+ T02 += M0 * T00 + M1 * T01;
2546+ T12 += M0 * T10 + M1 * T11;
2547+
2548+ /* NOBREAK */
2549+ case (APPLY_SHEAR | APPLY_SCALE):
2550+ m02 = T02;
2551+ m12 = T12;
2552+
2553+ M0 = m00;
2554+ M1 = m10;
2555+ m00 = M0 * T00 + M1 * T01;
2556+ m10 = M0 * T10 + M1 * T11;
2557+
2558+ M0 = m01;
2559+ M1 = m11;
2560+ m01 = M0 * T00 + M1 * T01;
2561+ m11 = M0 * T10 + M1 * T11;
2562+ break;
2563+
2564+ case (APPLY_SHEAR | APPLY_TRANSLATE):
2565+ M0 = m02;
2566+ M1 = m12;
2567+ T02 += M0 * T00 + M1 * T01;
2568+ T12 += M0 * T10 + M1 * T11;
2569+
2570+ /* NOBREAK */
2571+ case (APPLY_SHEAR):
2572+ m02 = T02;
2573+ m12 = T12;
2574+
2575+ M0 = m10;
2576+ m00 = M0 * T01;
2577+ m10 = M0 * T11;
2578+
2579+ M0 = m01;
2580+ m01 = M0 * T00;
2581+ m11 = M0 * T10;
2582+ break;
2583+
2584+ case (APPLY_SCALE | APPLY_TRANSLATE):
2585+ M0 = m02;
2586+ M1 = m12;
2587+ T02 += M0 * T00 + M1 * T01;
2588+ T12 += M0 * T10 + M1 * T11;
2589+
2590+ /* NOBREAK */
2591+ case (APPLY_SCALE):
2592+ m02 = T02;
2593+ m12 = T12;
2594+
2595+ M0 = m00;
2596+ m00 = M0 * T00;
2597+ m10 = M0 * T10;
2598+
2599+ M0 = m11;
2600+ m01 = M0 * T01;
2601+ m11 = M0 * T11;
2602+ break;
2603+
2604+ case (APPLY_TRANSLATE):
2605+ M0 = m02;
2606+ M1 = m12;
2607+ T02 += M0 * T00 + M1 * T01;
2608+ T12 += M0 * T10 + M1 * T11;
2609+
2610+ /* NOBREAK */
2611+ case (APPLY_IDENTITY):
2612+ m02 = T02;
2613+ m12 = T12;
2614+
2615+ m00 = T00;
2616+ m10 = T10;
2617+
2618+ m01 = T01;
2619+ m11 = T11;
2620+
2621+ state = mystate | txstate;
2622+ type = TYPE_UNKNOWN;
2623+ return;
2624+ }
2625+ updateState();
2626+ }
2627+
2628+ /**
2629+ * Returns an <code>AffineTransform</code> object representing the
2630+ * inverse transformation.
2631+ * The inverse transform Tx' of this transform Tx
2632+ * maps coordinates transformed by Tx back
2633+ * to their original coordinates.
2634+ * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2635+ * <p>
2636+ * If this transform maps all coordinates onto a point or a line
2637+ * then it will not have an inverse, since coordinates that do
2638+ * not lie on the destination point or line will not have an inverse
2639+ * mapping.
2640+ * The <code>getDeterminant</code> method can be used to determine if this
2641+ * transform has no inverse, in which case an exception will be
2642+ * thrown if the <code>createInverse</code> method is called.
2643+ * @return a new <code>AffineTransform</code> object representing the
2644+ * inverse transformation.
2645+ * @see #getDeterminant
2646+ * @exception NoninvertibleTransformException
2647+ * if the matrix cannot be inverted.
2648+ * @since 1.2
2649+ */
2650+ public AffineTransform createInverse()
2651+ throws NoninvertibleTransformException
2652+ {
2653+ double det;
2654+ switch (state) {
2655+ default:
2656+ stateError();
2657+ /* NOTREACHED */
2658+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2659+ det = m00 * m11 - m01 * m10;
2660+ if (Math.abs(det) <= Double.MIN_VALUE) {
2661+ throw new NoninvertibleTransformException("Determinant is "+
2662+ det);
2663+ }
2664+ return new AffineTransform( m11 / det, -m10 / det,
2665+ -m01 / det, m00 / det,
2666+ (m01 * m12 - m11 * m02) / det,
2667+ (m10 * m02 - m00 * m12) / det,
2668+ (APPLY_SHEAR |
2669+ APPLY_SCALE |
2670+ APPLY_TRANSLATE));
2671+ case (APPLY_SHEAR | APPLY_SCALE):
2672+ det = m00 * m11 - m01 * m10;
2673+ if (Math.abs(det) <= Double.MIN_VALUE) {
2674+ throw new NoninvertibleTransformException("Determinant is "+
2675+ det);
2676+ }
2677+ return new AffineTransform( m11 / det, -m10 / det,
2678+ -m01 / det, m00 / det,
2679+ 0.0, 0.0,
2680+ (APPLY_SHEAR | APPLY_SCALE));
2681+ case (APPLY_SHEAR | APPLY_TRANSLATE):
2682+ if (m01 == 0.0 || m10 == 0.0) {
2683+ throw new NoninvertibleTransformException("Determinant is 0");
2684+ }
2685+ return new AffineTransform( 0.0, 1.0 / m01,
2686+ 1.0 / m10, 0.0,
2687+ -m12 / m10, -m02 / m01,
2688+ (APPLY_SHEAR | APPLY_TRANSLATE));
2689+ case (APPLY_SHEAR):
2690+ if (m01 == 0.0 || m10 == 0.0) {
2691+ throw new NoninvertibleTransformException("Determinant is 0");
2692+ }
2693+ return new AffineTransform(0.0, 1.0 / m01,
2694+ 1.0 / m10, 0.0,
2695+ 0.0, 0.0,
2696+ (APPLY_SHEAR));
2697+ case (APPLY_SCALE | APPLY_TRANSLATE):
2698+ if (m00 == 0.0 || m11 == 0.0) {
2699+ throw new NoninvertibleTransformException("Determinant is 0");
2700+ }
2701+ return new AffineTransform( 1.0 / m00, 0.0,
2702+ 0.0, 1.0 / m11,
2703+ -m02 / m00, -m12 / m11,
2704+ (APPLY_SCALE | APPLY_TRANSLATE));
2705+ case (APPLY_SCALE):
2706+ if (m00 == 0.0 || m11 == 0.0) {
2707+ throw new NoninvertibleTransformException("Determinant is 0");
2708+ }
2709+ return new AffineTransform(1.0 / m00, 0.0,
2710+ 0.0, 1.0 / m11,
2711+ 0.0, 0.0,
2712+ (APPLY_SCALE));
2713+ case (APPLY_TRANSLATE):
2714+ return new AffineTransform( 1.0, 0.0,
2715+ 0.0, 1.0,
2716+ -m02, -m12,
2717+ (APPLY_TRANSLATE));
2718+ case (APPLY_IDENTITY):
2719+ return new AffineTransform();
2720+ }
2721+
2722+ /* NOTREACHED */
2723+ }
2724+
2725+ /**
2726+ * Sets this transform to the inverse of itself.
2727+ * The inverse transform Tx' of this transform Tx
2728+ * maps coordinates transformed by Tx back
2729+ * to their original coordinates.
2730+ * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2731+ * <p>
2732+ * If this transform maps all coordinates onto a point or a line
2733+ * then it will not have an inverse, since coordinates that do
2734+ * not lie on the destination point or line will not have an inverse
2735+ * mapping.
2736+ * The <code>getDeterminant</code> method can be used to determine if this
2737+ * transform has no inverse, in which case an exception will be
2738+ * thrown if the <code>invert</code> method is called.
2739+ * @see #getDeterminant
2740+ * @exception NoninvertibleTransformException
2741+ * if the matrix cannot be inverted.
2742+ * @since 1.6
2743+ */
2744+ public void invert()
2745+ throws NoninvertibleTransformException
2746+ {
2747+ double M00, M01, M02;
2748+ double M10, M11, M12;
2749+ double det;
2750+ switch (state) {
2751+ default:
2752+ stateError();
2753+ /* NOTREACHED */
2754+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2755+ M00 = m00; M01 = m01; M02 = m02;
2756+ M10 = m10; M11 = m11; M12 = m12;
2757+ det = M00 * M11 - M01 * M10;
2758+ if (Math.abs(det) <= Double.MIN_VALUE) {
2759+ throw new NoninvertibleTransformException("Determinant is "+
2760+ det);
2761+ }
2762+ m00 = M11 / det;
2763+ m10 = -M10 / det;
2764+ m01 = -M01 / det;
2765+ m11 = M00 / det;
2766+ m02 = (M01 * M12 - M11 * M02) / det;
2767+ m12 = (M10 * M02 - M00 * M12) / det;
2768+ break;
2769+ case (APPLY_SHEAR | APPLY_SCALE):
2770+ M00 = m00; M01 = m01;
2771+ M10 = m10; M11 = m11;
2772+ det = M00 * M11 - M01 * M10;
2773+ if (Math.abs(det) <= Double.MIN_VALUE) {
2774+ throw new NoninvertibleTransformException("Determinant is "+
2775+ det);
2776+ }
2777+ m00 = M11 / det;
2778+ m10 = -M10 / det;
2779+ m01 = -M01 / det;
2780+ m11 = M00 / det;
2781+ // m02 = 0.0;
2782+ // m12 = 0.0;
2783+ break;
2784+ case (APPLY_SHEAR | APPLY_TRANSLATE):
2785+ M01 = m01; M02 = m02;
2786+ M10 = m10; M12 = m12;
2787+ if (M01 == 0.0 || M10 == 0.0) {
2788+ throw new NoninvertibleTransformException("Determinant is 0");
2789+ }
2790+ // m00 = 0.0;
2791+ m10 = 1.0 / M01;
2792+ m01 = 1.0 / M10;
2793+ // m11 = 0.0;
2794+ m02 = -M12 / M10;
2795+ m12 = -M02 / M01;
2796+ break;
2797+ case (APPLY_SHEAR):
2798+ M01 = m01;
2799+ M10 = m10;
2800+ if (M01 == 0.0 || M10 == 0.0) {
2801+ throw new NoninvertibleTransformException("Determinant is 0");
2802+ }
2803+ // m00 = 0.0;
2804+ m10 = 1.0 / M01;
2805+ m01 = 1.0 / M10;
2806+ // m11 = 0.0;
2807+ // m02 = 0.0;
2808+ // m12 = 0.0;
2809+ break;
2810+ case (APPLY_SCALE | APPLY_TRANSLATE):
2811+ M00 = m00; M02 = m02;
2812+ M11 = m11; M12 = m12;
2813+ if (M00 == 0.0 || M11 == 0.0) {
2814+ throw new NoninvertibleTransformException("Determinant is 0");
2815+ }
2816+ m00 = 1.0 / M00;
2817+ // m10 = 0.0;
2818+ // m01 = 0.0;
2819+ m11 = 1.0 / M11;
2820+ m02 = -M02 / M00;
2821+ m12 = -M12 / M11;
2822+ break;
2823+ case (APPLY_SCALE):
2824+ M00 = m00;
2825+ M11 = m11;
2826+ if (M00 == 0.0 || M11 == 0.0) {
2827+ throw new NoninvertibleTransformException("Determinant is 0");
2828+ }
2829+ m00 = 1.0 / M00;
2830+ // m10 = 0.0;
2831+ // m01 = 0.0;
2832+ m11 = 1.0 / M11;
2833+ // m02 = 0.0;
2834+ // m12 = 0.0;
2835+ break;
2836+ case (APPLY_TRANSLATE):
2837+ // m00 = 1.0;
2838+ // m10 = 0.0;
2839+ // m01 = 0.0;
2840+ // m11 = 1.0;
2841+ m02 = -m02;
2842+ m12 = -m12;
2843+ break;
2844+ case (APPLY_IDENTITY):
2845+ // m00 = 1.0;
2846+ // m10 = 0.0;
2847+ // m01 = 0.0;
2848+ // m11 = 1.0;
2849+ // m02 = 0.0;
2850+ // m12 = 0.0;
2851+ break;
2852+ }
2853+ }
2854+
2855+ /**
2856+ * Transforms the specified <code>ptSrc</code> and stores the result
2857+ * in <code>ptDst</code>.
2858+ * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2859+ * object is allocated and then the result of the transformation is
2860+ * stored in this object.
2861+ * In either case, <code>ptDst</code>, which contains the
2862+ * transformed point, is returned for convenience.
2863+ * If <code>ptSrc</code> and <code>ptDst</code> are the same
2864+ * object, the input point is correctly overwritten with
2865+ * the transformed point.
2866+ * @param ptSrc the specified <code>Point2D</code> to be transformed
2867+ * @param ptDst the specified <code>Point2D</code> that stores the
2868+ * result of transforming <code>ptSrc</code>
2869+ * @return the <code>ptDst</code> after transforming
2870+ * <code>ptSrc</code> and stroring the result in <code>ptDst</code>.
2871+ * @since 1.2
2872+ */
2873+ public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2874+ if (ptDst == null) {
2875+ if (ptSrc instanceof Point2D.Double) {
2876+ ptDst = new Point2D.Double();
2877+ } else {
2878+ ptDst = new Point2D.Float();
2879+ }
2880+ }
2881+ // Copy source coords into local variables in case src == dst
2882+ double x = ptSrc.getX();
2883+ double y = ptSrc.getY();
2884+ switch (state) {
2885+ default:
2886+ stateError();
2887+ /* NOTREACHED */
2888+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2889+ ptDst.setLocation(x * m00 + y * m01 + m02,
2890+ x * m10 + y * m11 + m12);
2891+ return ptDst;
2892+ case (APPLY_SHEAR | APPLY_SCALE):
2893+ ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2894+ return ptDst;
2895+ case (APPLY_SHEAR | APPLY_TRANSLATE):
2896+ ptDst.setLocation(y * m01 + m02, x * m10 + m12);
2897+ return ptDst;
2898+ case (APPLY_SHEAR):
2899+ ptDst.setLocation(y * m01, x * m10);
2900+ return ptDst;
2901+ case (APPLY_SCALE | APPLY_TRANSLATE):
2902+ ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2903+ return ptDst;
2904+ case (APPLY_SCALE):
2905+ ptDst.setLocation(x * m00, y * m11);
2906+ return ptDst;
2907+ case (APPLY_TRANSLATE):
2908+ ptDst.setLocation(x + m02, y + m12);
2909+ return ptDst;
2910+ case (APPLY_IDENTITY):
2911+ ptDst.setLocation(x, y);
2912+ return ptDst;
2913+ }
2914+
2915+ /* NOTREACHED */
2916+ }
2917+
2918+ /**
2919+ * Transforms an array of point objects by this transform.
2920+ * If any element of the <code>ptDst</code> array is
2921+ * <code>null</code>, a new <code>Point2D</code> object is allocated
2922+ * and stored into that element before storing the results of the
2923+ * transformation.
2924+ * <p>
2925+ * Note that this method does not take any precautions to
2926+ * avoid problems caused by storing results into <code>Point2D</code>
2927+ * objects that will be used as the source for calculations
2928+ * further down the source array.
2929+ * This method does guarantee that if a specified <code>Point2D</code>
2930+ * object is both the source and destination for the same single point
2931+ * transform operation then the results will not be stored until
2932+ * the calculations are complete to avoid storing the results on
2933+ * top of the operands.
2934+ * If, however, the destination <code>Point2D</code> object for one
2935+ * operation is the same object as the source <code>Point2D</code>
2936+ * object for another operation further down the source array then
2937+ * the original coordinates in that point are overwritten before
2938+ * they can be converted.
2939+ * @param ptSrc the array containing the source point objects
2940+ * @param ptDst the array into which the transform point objects are
2941+ * returned
2942+ * @param srcOff the offset to the first point object to be
2943+ * transformed in the source array
2944+ * @param dstOff the offset to the location of the first
2945+ * transformed point object that is stored in the destination array
2946+ * @param numPts the number of point objects to be transformed
2947+ * @since 1.2
2948+ */
2949+ public void transform(Point2D[] ptSrc, int srcOff,
2950+ Point2D[] ptDst, int dstOff,
2951+ int numPts) {
2952+ int state = this.state;
2953+ while (--numPts >= 0) {
2954+ // Copy source coords into local variables in case src == dst
2955+ Point2D src = ptSrc[srcOff++];
2956+ double x = src.getX();
2957+ double y = src.getY();
2958+ Point2D dst = ptDst[dstOff++];
2959+ if (dst == null) {
2960+ if (src instanceof Point2D.Double) {
2961+ dst = new Point2D.Double();
2962+ } else {
2963+ dst = new Point2D.Float();
2964+ }
2965+ ptDst[dstOff - 1] = dst;
2966+ }
2967+ switch (state) {
2968+ default:
2969+ stateError();
2970+ /* NOTREACHED */
2971+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2972+ dst.setLocation(x * m00 + y * m01 + m02,
2973+ x * m10 + y * m11 + m12);
2974+ break;
2975+ case (APPLY_SHEAR | APPLY_SCALE):
2976+ dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2977+ break;
2978+ case (APPLY_SHEAR | APPLY_TRANSLATE):
2979+ dst.setLocation(y * m01 + m02, x * m10 + m12);
2980+ break;
2981+ case (APPLY_SHEAR):
2982+ dst.setLocation(y * m01, x * m10);
2983+ break;
2984+ case (APPLY_SCALE | APPLY_TRANSLATE):
2985+ dst.setLocation(x * m00 + m02, y * m11 + m12);
2986+ break;
2987+ case (APPLY_SCALE):
2988+ dst.setLocation(x * m00, y * m11);
2989+ break;
2990+ case (APPLY_TRANSLATE):
2991+ dst.setLocation(x + m02, y + m12);
2992+ break;
2993+ case (APPLY_IDENTITY):
2994+ dst.setLocation(x, y);
2995+ break;
2996+ }
2997+ }
2998+
2999+ /* NOTREACHED */
3000+ }
3001+
3002+ /**
3003+ * Transforms an array of floating point coordinates by this transform.
3004+ * The two coordinate array sections can be exactly the same or
3005+ * can be overlapping sections of the same array without affecting the
3006+ * validity of the results.
3007+ * This method ensures that no source coordinates are overwritten by a
3008+ * previous operation before they can be transformed.
3009+ * The coordinates are stored in the arrays starting at the specified
3010+ * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3011+ * @param srcPts the array containing the source point coordinates.
3012+ * Each point is stored as a pair of x,&nbsp;y coordinates.
3013+ * @param dstPts the array into which the transformed point coordinates
3014+ * are returned. Each point is stored as a pair of x,&nbsp;y
3015+ * coordinates.
3016+ * @param srcOff the offset to the first point to be transformed
3017+ * in the source array
3018+ * @param dstOff the offset to the location of the first
3019+ * transformed point that is stored in the destination array
3020+ * @param numPts the number of points to be transformed
3021+ * @since 1.2
3022+ */
3023+ public void transform(float[] srcPts, int srcOff,
3024+ float[] dstPts, int dstOff,
3025+ int numPts) {
3026+ double M00, M01, M02, M10, M11, M12; // For caching
3027+ if (dstPts == srcPts &&
3028+ dstOff > srcOff && dstOff < srcOff + numPts * 2)
3029+ {
3030+ // If the arrays overlap partially with the destination higher
3031+ // than the source and we transform the coordinates normally
3032+ // we would overwrite some of the later source coordinates
3033+ // with results of previous transformations.
3034+ // To get around this we use arraycopy to copy the points
3035+ // to their final destination with correct overwrite
3036+ // handling and then transform them in place in the new
3037+ // safer location.
3038+ System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3039+ // srcPts = dstPts; // They are known to be equal.
3040+ srcOff = dstOff;
3041+ }
3042+ switch (state) {
3043+ default:
3044+ stateError();
3045+ /* NOTREACHED */
3046+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3047+ M00 = m00; M01 = m01; M02 = m02;
3048+ M10 = m10; M11 = m11; M12 = m12;
3049+ while (--numPts >= 0) {
3050+ double x = srcPts[srcOff++];
3051+ double y = srcPts[srcOff++];
3052+ dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3053+ dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3054+ }
3055+ return;
3056+ case (APPLY_SHEAR | APPLY_SCALE):
3057+ M00 = m00; M01 = m01;
3058+ M10 = m10; M11 = m11;
3059+ while (--numPts >= 0) {
3060+ double x = srcPts[srcOff++];
3061+ double y = srcPts[srcOff++];
3062+ dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3063+ dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3064+ }
3065+ return;
3066+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3067+ M01 = m01; M02 = m02;
3068+ M10 = m10; M12 = m12;
3069+ while (--numPts >= 0) {
3070+ double x = srcPts[srcOff++];
3071+ dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3072+ dstPts[dstOff++] = (float) (M10 * x + M12);
3073+ }
3074+ return;
3075+ case (APPLY_SHEAR):
3076+ M01 = m01; M10 = m10;
3077+ while (--numPts >= 0) {
3078+ double x = srcPts[srcOff++];
3079+ dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3080+ dstPts[dstOff++] = (float) (M10 * x);
3081+ }
3082+ return;
3083+ case (APPLY_SCALE | APPLY_TRANSLATE):
3084+ M00 = m00; M02 = m02;
3085+ M11 = m11; M12 = m12;
3086+ while (--numPts >= 0) {
3087+ dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3088+ dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3089+ }
3090+ return;
3091+ case (APPLY_SCALE):
3092+ M00 = m00; M11 = m11;
3093+ while (--numPts >= 0) {
3094+ dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3095+ dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3096+ }
3097+ return;
3098+ case (APPLY_TRANSLATE):
3099+ M02 = m02; M12 = m12;
3100+ while (--numPts >= 0) {
3101+ dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3102+ dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3103+ }
3104+ return;
3105+ case (APPLY_IDENTITY):
3106+ if (srcPts != dstPts || srcOff != dstOff) {
3107+ System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3108+ numPts * 2);
3109+ }
3110+ return;
3111+ }
3112+
3113+ /* NOTREACHED */
3114+ }
3115+
3116+ /**
3117+ * Transforms an array of double precision coordinates by this transform.
3118+ * The two coordinate array sections can be exactly the same or
3119+ * can be overlapping sections of the same array without affecting the
3120+ * validity of the results.
3121+ * This method ensures that no source coordinates are
3122+ * overwritten by a previous operation before they can be transformed.
3123+ * The coordinates are stored in the arrays starting at the indicated
3124+ * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3125+ * @param srcPts the array containing the source point coordinates.
3126+ * Each point is stored as a pair of x,&nbsp;y coordinates.
3127+ * @param dstPts the array into which the transformed point
3128+ * coordinates are returned. Each point is stored as a pair of
3129+ * x,&nbsp;y coordinates.
3130+ * @param srcOff the offset to the first point to be transformed
3131+ * in the source array
3132+ * @param dstOff the offset to the location of the first
3133+ * transformed point that is stored in the destination array
3134+ * @param numPts the number of point objects to be transformed
3135+ * @since 1.2
3136+ */
3137+ public void transform(double[] srcPts, int srcOff,
3138+ double[] dstPts, int dstOff,
3139+ int numPts) {
3140+ double M00, M01, M02, M10, M11, M12; // For caching
3141+ if (dstPts == srcPts &&
3142+ dstOff > srcOff && dstOff < srcOff + numPts * 2)
3143+ {
3144+ // If the arrays overlap partially with the destination higher
3145+ // than the source and we transform the coordinates normally
3146+ // we would overwrite some of the later source coordinates
3147+ // with results of previous transformations.
3148+ // To get around this we use arraycopy to copy the points
3149+ // to their final destination with correct overwrite
3150+ // handling and then transform them in place in the new
3151+ // safer location.
3152+ System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3153+ // srcPts = dstPts; // They are known to be equal.
3154+ srcOff = dstOff;
3155+ }
3156+ switch (state) {
3157+ default:
3158+ stateError();
3159+ /* NOTREACHED */
3160+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3161+ M00 = m00; M01 = m01; M02 = m02;
3162+ M10 = m10; M11 = m11; M12 = m12;
3163+ while (--numPts >= 0) {
3164+ double x = srcPts[srcOff++];
3165+ double y = srcPts[srcOff++];
3166+ dstPts[dstOff++] = M00 * x + M01 * y + M02;
3167+ dstPts[dstOff++] = M10 * x + M11 * y + M12;
3168+ }
3169+ return;
3170+ case (APPLY_SHEAR | APPLY_SCALE):
3171+ M00 = m00; M01 = m01;
3172+ M10 = m10; M11 = m11;
3173+ while (--numPts >= 0) {
3174+ double x = srcPts[srcOff++];
3175+ double y = srcPts[srcOff++];
3176+ dstPts[dstOff++] = M00 * x + M01 * y;
3177+ dstPts[dstOff++] = M10 * x + M11 * y;
3178+ }
3179+ return;
3180+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3181+ M01 = m01; M02 = m02;
3182+ M10 = m10; M12 = m12;
3183+ while (--numPts >= 0) {
3184+ double x = srcPts[srcOff++];
3185+ dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3186+ dstPts[dstOff++] = M10 * x + M12;
3187+ }
3188+ return;
3189+ case (APPLY_SHEAR):
3190+ M01 = m01; M10 = m10;
3191+ while (--numPts >= 0) {
3192+ double x = srcPts[srcOff++];
3193+ dstPts[dstOff++] = M01 * srcPts[srcOff++];
3194+ dstPts[dstOff++] = M10 * x;
3195+ }
3196+ return;
3197+ case (APPLY_SCALE | APPLY_TRANSLATE):
3198+ M00 = m00; M02 = m02;
3199+ M11 = m11; M12 = m12;
3200+ while (--numPts >= 0) {
3201+ dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3202+ dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3203+ }
3204+ return;
3205+ case (APPLY_SCALE):
3206+ M00 = m00; M11 = m11;
3207+ while (--numPts >= 0) {
3208+ dstPts[dstOff++] = M00 * srcPts[srcOff++];
3209+ dstPts[dstOff++] = M11 * srcPts[srcOff++];
3210+ }
3211+ return;
3212+ case (APPLY_TRANSLATE):
3213+ M02 = m02; M12 = m12;
3214+ while (--numPts >= 0) {
3215+ dstPts[dstOff++] = srcPts[srcOff++] + M02;
3216+ dstPts[dstOff++] = srcPts[srcOff++] + M12;
3217+ }
3218+ return;
3219+ case (APPLY_IDENTITY):
3220+ if (srcPts != dstPts || srcOff != dstOff) {
3221+ System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3222+ numPts * 2);
3223+ }
3224+ return;
3225+ }
3226+
3227+ /* NOTREACHED */
3228+ }
3229+
3230+ /**
3231+ * Transforms an array of floating point coordinates by this transform
3232+ * and stores the results into an array of doubles.
3233+ * The coordinates are stored in the arrays starting at the specified
3234+ * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3235+ * @param srcPts the array containing the source point coordinates.
3236+ * Each point is stored as a pair of x,&nbsp;y coordinates.
3237+ * @param dstPts the array into which the transformed point coordinates
3238+ * are returned. Each point is stored as a pair of x,&nbsp;y
3239+ * coordinates.
3240+ * @param srcOff the offset to the first point to be transformed
3241+ * in the source array
3242+ * @param dstOff the offset to the location of the first
3243+ * transformed point that is stored in the destination array
3244+ * @param numPts the number of points to be transformed
3245+ * @since 1.2
3246+ */
3247+ public void transform(float[] srcPts, int srcOff,
3248+ double[] dstPts, int dstOff,
3249+ int numPts) {
3250+ double M00, M01, M02, M10, M11, M12; // For caching
3251+ switch (state) {
3252+ default:
3253+ stateError();
3254+ /* NOTREACHED */
3255+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3256+ M00 = m00; M01 = m01; M02 = m02;
3257+ M10 = m10; M11 = m11; M12 = m12;
3258+ while (--numPts >= 0) {
3259+ double x = srcPts[srcOff++];
3260+ double y = srcPts[srcOff++];
3261+ dstPts[dstOff++] = M00 * x + M01 * y + M02;
3262+ dstPts[dstOff++] = M10 * x + M11 * y + M12;
3263+ }
3264+ return;
3265+ case (APPLY_SHEAR | APPLY_SCALE):
3266+ M00 = m00; M01 = m01;
3267+ M10 = m10; M11 = m11;
3268+ while (--numPts >= 0) {
3269+ double x = srcPts[srcOff++];
3270+ double y = srcPts[srcOff++];
3271+ dstPts[dstOff++] = M00 * x + M01 * y;
3272+ dstPts[dstOff++] = M10 * x + M11 * y;
3273+ }
3274+ return;
3275+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3276+ M01 = m01; M02 = m02;
3277+ M10 = m10; M12 = m12;
3278+ while (--numPts >= 0) {
3279+ double x = srcPts[srcOff++];
3280+ dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3281+ dstPts[dstOff++] = M10 * x + M12;
3282+ }
3283+ return;
3284+ case (APPLY_SHEAR):
3285+ M01 = m01; M10 = m10;
3286+ while (--numPts >= 0) {
3287+ double x = srcPts[srcOff++];
3288+ dstPts[dstOff++] = M01 * srcPts[srcOff++];
3289+ dstPts[dstOff++] = M10 * x;
3290+ }
3291+ return;
3292+ case (APPLY_SCALE | APPLY_TRANSLATE):
3293+ M00 = m00; M02 = m02;
3294+ M11 = m11; M12 = m12;
3295+ while (--numPts >= 0) {
3296+ dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3297+ dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3298+ }
3299+ return;
3300+ case (APPLY_SCALE):
3301+ M00 = m00; M11 = m11;
3302+ while (--numPts >= 0) {
3303+ dstPts[dstOff++] = M00 * srcPts[srcOff++];
3304+ dstPts[dstOff++] = M11 * srcPts[srcOff++];
3305+ }
3306+ return;
3307+ case (APPLY_TRANSLATE):
3308+ M02 = m02; M12 = m12;
3309+ while (--numPts >= 0) {
3310+ dstPts[dstOff++] = srcPts[srcOff++] + M02;
3311+ dstPts[dstOff++] = srcPts[srcOff++] + M12;
3312+ }
3313+ return;
3314+ case (APPLY_IDENTITY):
3315+ while (--numPts >= 0) {
3316+ dstPts[dstOff++] = srcPts[srcOff++];
3317+ dstPts[dstOff++] = srcPts[srcOff++];
3318+ }
3319+ return;
3320+ }
3321+
3322+ /* NOTREACHED */
3323+ }
3324+
3325+ /**
3326+ * Transforms an array of double precision coordinates by this transform
3327+ * and stores the results into an array of floats.
3328+ * The coordinates are stored in the arrays starting at the specified
3329+ * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3330+ * @param srcPts the array containing the source point coordinates.
3331+ * Each point is stored as a pair of x,&nbsp;y coordinates.
3332+ * @param dstPts the array into which the transformed point
3333+ * coordinates are returned. Each point is stored as a pair of
3334+ * x,&nbsp;y coordinates.
3335+ * @param srcOff the offset to the first point to be transformed
3336+ * in the source array
3337+ * @param dstOff the offset to the location of the first
3338+ * transformed point that is stored in the destination array
3339+ * @param numPts the number of point objects to be transformed
3340+ * @since 1.2
3341+ */
3342+ public void transform(double[] srcPts, int srcOff,
3343+ float[] dstPts, int dstOff,
3344+ int numPts) {
3345+ double M00, M01, M02, M10, M11, M12; // For caching
3346+ switch (state) {
3347+ default:
3348+ stateError();
3349+ /* NOTREACHED */
3350+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3351+ M00 = m00; M01 = m01; M02 = m02;
3352+ M10 = m10; M11 = m11; M12 = m12;
3353+ while (--numPts >= 0) {
3354+ double x = srcPts[srcOff++];
3355+ double y = srcPts[srcOff++];
3356+ dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3357+ dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3358+ }
3359+ return;
3360+ case (APPLY_SHEAR | APPLY_SCALE):
3361+ M00 = m00; M01 = m01;
3362+ M10 = m10; M11 = m11;
3363+ while (--numPts >= 0) {
3364+ double x = srcPts[srcOff++];
3365+ double y = srcPts[srcOff++];
3366+ dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3367+ dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3368+ }
3369+ return;
3370+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3371+ M01 = m01; M02 = m02;
3372+ M10 = m10; M12 = m12;
3373+ while (--numPts >= 0) {
3374+ double x = srcPts[srcOff++];
3375+ dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3376+ dstPts[dstOff++] = (float) (M10 * x + M12);
3377+ }
3378+ return;
3379+ case (APPLY_SHEAR):
3380+ M01 = m01; M10 = m10;
3381+ while (--numPts >= 0) {
3382+ double x = srcPts[srcOff++];
3383+ dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3384+ dstPts[dstOff++] = (float) (M10 * x);
3385+ }
3386+ return;
3387+ case (APPLY_SCALE | APPLY_TRANSLATE):
3388+ M00 = m00; M02 = m02;
3389+ M11 = m11; M12 = m12;
3390+ while (--numPts >= 0) {
3391+ dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3392+ dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3393+ }
3394+ return;
3395+ case (APPLY_SCALE):
3396+ M00 = m00; M11 = m11;
3397+ while (--numPts >= 0) {
3398+ dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3399+ dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3400+ }
3401+ return;
3402+ case (APPLY_TRANSLATE):
3403+ M02 = m02; M12 = m12;
3404+ while (--numPts >= 0) {
3405+ dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3406+ dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3407+ }
3408+ return;
3409+ case (APPLY_IDENTITY):
3410+ while (--numPts >= 0) {
3411+ dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3412+ dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3413+ }
3414+ return;
3415+ }
3416+
3417+ /* NOTREACHED */
3418+ }
3419+
3420+ /**
3421+ * Inverse transforms the specified <code>ptSrc</code> and stores the
3422+ * result in <code>ptDst</code>.
3423+ * If <code>ptDst</code> is <code>null</code>, a new
3424+ * <code>Point2D</code> object is allocated and then the result of the
3425+ * transform is stored in this object.
3426+ * In either case, <code>ptDst</code>, which contains the transformed
3427+ * point, is returned for convenience.
3428+ * If <code>ptSrc</code> and <code>ptDst</code> are the same
3429+ * object, the input point is correctly overwritten with the
3430+ * transformed point.
3431+ * @param ptSrc the point to be inverse transformed
3432+ * @param ptDst the resulting transformed point
3433+ * @return <code>ptDst</code>, which contains the result of the
3434+ * inverse transform.
3435+ * @exception NoninvertibleTransformException if the matrix cannot be
3436+ * inverted.
3437+ * @since 1.2
3438+ */
3439+ public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
3440+ throws NoninvertibleTransformException
3441+ {
3442+ if (ptDst == null) {
3443+ if (ptSrc instanceof Point2D.Double) {
3444+ ptDst = new Point2D.Double();
3445+ } else {
3446+ ptDst = new Point2D.Float();
3447+ }
3448+ }
3449+ // Copy source coords into local variables in case src == dst
3450+ double x = ptSrc.getX();
3451+ double y = ptSrc.getY();
3452+ switch (state) {
3453+ default:
3454+ stateError();
3455+ /* NOTREACHED */
3456+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3457+ x -= m02;
3458+ y -= m12;
3459+ /* NOBREAK */
3460+ case (APPLY_SHEAR | APPLY_SCALE):
3461+ double det = m00 * m11 - m01 * m10;
3462+ if (Math.abs(det) <= Double.MIN_VALUE) {
3463+ throw new NoninvertibleTransformException("Determinant is "+
3464+ det);
3465+ }
3466+ ptDst.setLocation((x * m11 - y * m01) / det,
3467+ (y * m00 - x * m10) / det);
3468+ return ptDst;
3469+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3470+ x -= m02;
3471+ y -= m12;
3472+ /* NOBREAK */
3473+ case (APPLY_SHEAR):
3474+ if (m01 == 0.0 || m10 == 0.0) {
3475+ throw new NoninvertibleTransformException("Determinant is 0");
3476+ }
3477+ ptDst.setLocation(y / m10, x / m01);
3478+ return ptDst;
3479+ case (APPLY_SCALE | APPLY_TRANSLATE):
3480+ x -= m02;
3481+ y -= m12;
3482+ /* NOBREAK */
3483+ case (APPLY_SCALE):
3484+ if (m00 == 0.0 || m11 == 0.0) {
3485+ throw new NoninvertibleTransformException("Determinant is 0");
3486+ }
3487+ ptDst.setLocation(x / m00, y / m11);
3488+ return ptDst;
3489+ case (APPLY_TRANSLATE):
3490+ ptDst.setLocation(x - m02, y - m12);
3491+ return ptDst;
3492+ case (APPLY_IDENTITY):
3493+ ptDst.setLocation(x, y);
3494+ return ptDst;
3495+ }
3496+
3497+ /* NOTREACHED */
3498+ }
3499+
3500+ /**
3501+ * Inverse transforms an array of double precision coordinates by
3502+ * this transform.
3503+ * The two coordinate array sections can be exactly the same or
3504+ * can be overlapping sections of the same array without affecting the
3505+ * validity of the results.
3506+ * This method ensures that no source coordinates are
3507+ * overwritten by a previous operation before they can be transformed.
3508+ * The coordinates are stored in the arrays starting at the specified
3509+ * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3510+ * @param srcPts the array containing the source point coordinates.
3511+ * Each point is stored as a pair of x,&nbsp;y coordinates.
3512+ * @param dstPts the array into which the transformed point
3513+ * coordinates are returned. Each point is stored as a pair of
3514+ * x,&nbsp;y coordinates.
3515+ * @param srcOff the offset to the first point to be transformed
3516+ * in the source array
3517+ * @param dstOff the offset to the location of the first
3518+ * transformed point that is stored in the destination array
3519+ * @param numPts the number of point objects to be transformed
3520+ * @exception NoninvertibleTransformException if the matrix cannot be
3521+ * inverted.
3522+ * @since 1.2
3523+ */
3524+ public void inverseTransform(double[] srcPts, int srcOff,
3525+ double[] dstPts, int dstOff,
3526+ int numPts)
3527+ throws NoninvertibleTransformException
3528+ {
3529+ double M00, M01, M02, M10, M11, M12; // For caching
3530+ double det;
3531+ if (dstPts == srcPts &&
3532+ dstOff > srcOff && dstOff < srcOff + numPts * 2)
3533+ {
3534+ // If the arrays overlap partially with the destination higher
3535+ // than the source and we transform the coordinates normally
3536+ // we would overwrite some of the later source coordinates
3537+ // with results of previous transformations.
3538+ // To get around this we use arraycopy to copy the points
3539+ // to their final destination with correct overwrite
3540+ // handling and then transform them in place in the new
3541+ // safer location.
3542+ System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3543+ // srcPts = dstPts; // They are known to be equal.
3544+ srcOff = dstOff;
3545+ }
3546+ switch (state) {
3547+ default:
3548+ stateError();
3549+ /* NOTREACHED */
3550+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3551+ M00 = m00; M01 = m01; M02 = m02;
3552+ M10 = m10; M11 = m11; M12 = m12;
3553+ det = M00 * M11 - M01 * M10;
3554+ if (Math.abs(det) <= Double.MIN_VALUE) {
3555+ throw new NoninvertibleTransformException("Determinant is "+
3556+ det);
3557+ }
3558+ while (--numPts >= 0) {
3559+ double x = srcPts[srcOff++] - M02;
3560+ double y = srcPts[srcOff++] - M12;
3561+ dstPts[dstOff++] = (x * M11 - y * M01) / det;
3562+ dstPts[dstOff++] = (y * M00 - x * M10) / det;
3563+ }
3564+ return;
3565+ case (APPLY_SHEAR | APPLY_SCALE):
3566+ M00 = m00; M01 = m01;
3567+ M10 = m10; M11 = m11;
3568+ det = M00 * M11 - M01 * M10;
3569+ if (Math.abs(det) <= Double.MIN_VALUE) {
3570+ throw new NoninvertibleTransformException("Determinant is "+
3571+ det);
3572+ }
3573+ while (--numPts >= 0) {
3574+ double x = srcPts[srcOff++];
3575+ double y = srcPts[srcOff++];
3576+ dstPts[dstOff++] = (x * M11 - y * M01) / det;
3577+ dstPts[dstOff++] = (y * M00 - x * M10) / det;
3578+ }
3579+ return;
3580+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3581+ M01 = m01; M02 = m02;
3582+ M10 = m10; M12 = m12;
3583+ if (M01 == 0.0 || M10 == 0.0) {
3584+ throw new NoninvertibleTransformException("Determinant is 0");
3585+ }
3586+ while (--numPts >= 0) {
3587+ double x = srcPts[srcOff++] - M02;
3588+ dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
3589+ dstPts[dstOff++] = x / M01;
3590+ }
3591+ return;
3592+ case (APPLY_SHEAR):
3593+ M01 = m01; M10 = m10;
3594+ if (M01 == 0.0 || M10 == 0.0) {
3595+ throw new NoninvertibleTransformException("Determinant is 0");
3596+ }
3597+ while (--numPts >= 0) {
3598+ double x = srcPts[srcOff++];
3599+ dstPts[dstOff++] = srcPts[srcOff++] / M10;
3600+ dstPts[dstOff++] = x / M01;
3601+ }
3602+ return;
3603+ case (APPLY_SCALE | APPLY_TRANSLATE):
3604+ M00 = m00; M02 = m02;
3605+ M11 = m11; M12 = m12;
3606+ if (M00 == 0.0 || M11 == 0.0) {
3607+ throw new NoninvertibleTransformException("Determinant is 0");
3608+ }
3609+ while (--numPts >= 0) {
3610+ dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
3611+ dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
3612+ }
3613+ return;
3614+ case (APPLY_SCALE):
3615+ M00 = m00; M11 = m11;
3616+ if (M00 == 0.0 || M11 == 0.0) {
3617+ throw new NoninvertibleTransformException("Determinant is 0");
3618+ }
3619+ while (--numPts >= 0) {
3620+ dstPts[dstOff++] = srcPts[srcOff++] / M00;
3621+ dstPts[dstOff++] = srcPts[srcOff++] / M11;
3622+ }
3623+ return;
3624+ case (APPLY_TRANSLATE):
3625+ M02 = m02; M12 = m12;
3626+ while (--numPts >= 0) {
3627+ dstPts[dstOff++] = srcPts[srcOff++] - M02;
3628+ dstPts[dstOff++] = srcPts[srcOff++] - M12;
3629+ }
3630+ return;
3631+ case (APPLY_IDENTITY):
3632+ if (srcPts != dstPts || srcOff != dstOff) {
3633+ System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3634+ numPts * 2);
3635+ }
3636+ return;
3637+ }
3638+
3639+ /* NOTREACHED */
3640+ }
3641+
3642+ /**
3643+ * Transforms the relative distance vector specified by
3644+ * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
3645+ * A relative distance vector is transformed without applying the
3646+ * translation components of the affine transformation matrix
3647+ * using the following equations:
3648+ * <pre>
3649+ * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3650+ * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3651+ * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3652+ * </pre>
3653+ * If <code>ptDst</code> is <code>null</code>, a new
3654+ * <code>Point2D</code> object is allocated and then the result of the
3655+ * transform is stored in this object.
3656+ * In either case, <code>ptDst</code>, which contains the
3657+ * transformed point, is returned for convenience.
3658+ * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
3659+ * the input point is correctly overwritten with the transformed
3660+ * point.
3661+ * @param ptSrc the distance vector to be delta transformed
3662+ * @param ptDst the resulting transformed distance vector
3663+ * @return <code>ptDst</code>, which contains the result of the
3664+ * transformation.
3665+ * @since 1.2
3666+ */
3667+ public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
3668+ if (ptDst == null) {
3669+ if (ptSrc instanceof Point2D.Double) {
3670+ ptDst = new Point2D.Double();
3671+ } else {
3672+ ptDst = new Point2D.Float();
3673+ }
3674+ }
3675+ // Copy source coords into local variables in case src == dst
3676+ double x = ptSrc.getX();
3677+ double y = ptSrc.getY();
3678+ switch (state) {
3679+ default:
3680+ stateError();
3681+ /* NOTREACHED */
3682+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3683+ case (APPLY_SHEAR | APPLY_SCALE):
3684+ ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
3685+ return ptDst;
3686+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3687+ case (APPLY_SHEAR):
3688+ ptDst.setLocation(y * m01, x * m10);
3689+ return ptDst;
3690+ case (APPLY_SCALE | APPLY_TRANSLATE):
3691+ case (APPLY_SCALE):
3692+ ptDst.setLocation(x * m00, y * m11);
3693+ return ptDst;
3694+ case (APPLY_TRANSLATE):
3695+ case (APPLY_IDENTITY):
3696+ ptDst.setLocation(x, y);
3697+ return ptDst;
3698+ }
3699+
3700+ /* NOTREACHED */
3701+ }
3702+
3703+ /**
3704+ * Transforms an array of relative distance vectors by this
3705+ * transform.
3706+ * A relative distance vector is transformed without applying the
3707+ * translation components of the affine transformation matrix
3708+ * using the following equations:
3709+ * <pre>
3710+ * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3711+ * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3712+ * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3713+ * </pre>
3714+ * The two coordinate array sections can be exactly the same or
3715+ * can be overlapping sections of the same array without affecting the
3716+ * validity of the results.
3717+ * This method ensures that no source coordinates are
3718+ * overwritten by a previous operation before they can be transformed.
3719+ * The coordinates are stored in the arrays starting at the indicated
3720+ * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3721+ * @param srcPts the array containing the source distance vectors.
3722+ * Each vector is stored as a pair of relative x,&nbsp;y coordinates.
3723+ * @param dstPts the array into which the transformed distance vectors
3724+ * are returned. Each vector is stored as a pair of relative
3725+ * x,&nbsp;y coordinates.
3726+ * @param srcOff the offset to the first vector to be transformed
3727+ * in the source array
3728+ * @param dstOff the offset to the location of the first
3729+ * transformed vector that is stored in the destination array
3730+ * @param numPts the number of vector coordinate pairs to be
3731+ * transformed
3732+ * @since 1.2
3733+ */
3734+ public void deltaTransform(double[] srcPts, int srcOff,
3735+ double[] dstPts, int dstOff,
3736+ int numPts) {
3737+ double M00, M01, M10, M11; // For caching
3738+ if (dstPts == srcPts &&
3739+ dstOff > srcOff && dstOff < srcOff + numPts * 2)
3740+ {
3741+ // If the arrays overlap partially with the destination higher
3742+ // than the source and we transform the coordinates normally
3743+ // we would overwrite some of the later source coordinates
3744+ // with results of previous transformations.
3745+ // To get around this we use arraycopy to copy the points
3746+ // to their final destination with correct overwrite
3747+ // handling and then transform them in place in the new
3748+ // safer location.
3749+ System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3750+ // srcPts = dstPts; // They are known to be equal.
3751+ srcOff = dstOff;
3752+ }
3753+ switch (state) {
3754+ default:
3755+ stateError();
3756+ /* NOTREACHED */
3757+ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3758+ case (APPLY_SHEAR | APPLY_SCALE):
3759+ M00 = m00; M01 = m01;
3760+ M10 = m10; M11 = m11;
3761+ while (--numPts >= 0) {
3762+ double x = srcPts[srcOff++];
3763+ double y = srcPts[srcOff++];
3764+ dstPts[dstOff++] = x * M00 + y * M01;
3765+ dstPts[dstOff++] = x * M10 + y * M11;
3766+ }
3767+ return;
3768+ case (APPLY_SHEAR | APPLY_TRANSLATE):
3769+ case (APPLY_SHEAR):
3770+ M01 = m01; M10 = m10;
3771+ while (--numPts >= 0) {
3772+ double x = srcPts[srcOff++];
3773+ dstPts[dstOff++] = srcPts[srcOff++] * M01;
3774+ dstPts[dstOff++] = x * M10;
3775+ }
3776+ return;
3777+ case (APPLY_SCALE | APPLY_TRANSLATE):
3778+ case (APPLY_SCALE):
3779+ M00 = m00; M11 = m11;
3780+ while (--numPts >= 0) {
3781+ dstPts[dstOff++] = srcPts[srcOff++] * M00;
3782+ dstPts[dstOff++] = srcPts[srcOff++] * M11;
3783+ }
3784+ return;
3785+ case (APPLY_TRANSLATE):
3786+ case (APPLY_IDENTITY):
3787+ if (srcPts != dstPts || srcOff != dstOff) {
3788+ System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3789+ numPts * 2);
3790+ }
3791+ return;
3792+ }
3793+
3794+ /* NOTREACHED */
3795+ }
3796+
3797+ /**
3798+ * Returns a new {@link Shape} object defined by the geometry of the
3799+ * specified <code>Shape</code> after it has been transformed by
3800+ * this transform.
3801+ * @param pSrc the specified <code>Shape</code> object to be
3802+ * transformed by this transform.
3803+ * @return a new <code>Shape</code> object that defines the geometry
3804+ * of the transformed <code>Shape</code>, or null if {@code pSrc} is null.
3805+ * @since 1.2
3806+ */
3807+ public Shape createTransformedShape(Shape pSrc) {
3808+ if (pSrc == null) {
3809+ return null;
3810+ }
3811+ return new Path2D.Double(pSrc, this);
3812+ }
3813+
3814+ // Round values to sane precision for printing
3815+ // Note that Math.sin(Math.PI) has an error of about 10^-16
3816+ private static double _matround(double matval) {
3817+ return Math.rint(matval * 1E15) / 1E15;
3818+ }
3819+
3820+ /**
3821+ * Returns a <code>String</code> that represents the value of this
3822+ * {@link Object}.
3823+ * @return a <code>String</code> representing the value of this
3824+ * <code>Object</code>.
3825+ * @since 1.2
3826+ */
3827+ public String toString() {
3828+ return ("AffineTransform[["
3829+ + _matround(m00) + ", "
3830+ + _matround(m01) + ", "
3831+ + _matround(m02) + "], ["
3832+ + _matround(m10) + ", "
3833+ + _matround(m11) + ", "
3834+ + _matround(m12) + "]]");
3835+ }
3836+
3837+ /**
3838+ * Returns <code>true</code> if this <code>AffineTransform</code> is
3839+ * an identity transform.
3840+ * @return <code>true</code> if this <code>AffineTransform</code> is
3841+ * an identity transform; <code>false</code> otherwise.
3842+ * @since 1.2
3843+ */
3844+ public boolean isIdentity() {
3845+ return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3846+ }
3847+
3848+ /**
3849+ * Returns a copy of this <code>AffineTransform</code> object.
3850+ * @return an <code>Object</code> that is a copy of this
3851+ * <code>AffineTransform</code> object.
3852+ * @since 1.2
3853+ */
3854+ public Object clone() {
3855+ try {
3856+ return super.clone();
3857+ } catch (CloneNotSupportedException e) {
3858+ // this shouldn't happen, since we are Cloneable
3859+ throw new InternalError();
3860+ }
3861+ }
3862+
3863+ /**
3864+ * Returns the hashcode for this transform.
3865+ * @return a hash code for this transform.
3866+ * @since 1.2
3867+ */
3868+ public int hashCode() {
3869+ long bits = Double.doubleToLongBits(m00);
3870+ bits = bits * 31 + Double.doubleToLongBits(m01);
3871+ bits = bits * 31 + Double.doubleToLongBits(m02);
3872+ bits = bits * 31 + Double.doubleToLongBits(m10);
3873+ bits = bits * 31 + Double.doubleToLongBits(m11);
3874+ bits = bits * 31 + Double.doubleToLongBits(m12);
3875+ return (((int) bits) ^ ((int) (bits >> 32)));
3876+ }
3877+
3878+ /**
3879+ * Returns <code>true</code> if this <code>AffineTransform</code>
3880+ * represents the same affine coordinate transform as the specified
3881+ * argument.
3882+ * @param obj the <code>Object</code> to test for equality with this
3883+ * <code>AffineTransform</code>
3884+ * @return <code>true</code> if <code>obj</code> equals this
3885+ * <code>AffineTransform</code> object; <code>false</code> otherwise.
3886+ * @since 1.2
3887+ */
3888+ public boolean equals(Object obj) {
3889+ if (!(obj instanceof AffineTransform)) {
3890+ return false;
3891+ }
3892+
3893+ AffineTransform a = (AffineTransform)obj;
3894+
3895+ return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) &&
3896+ (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3897+ }
3898+
3899+ /* Serialization support. A readObject method is neccessary because
3900+ * the state field is part of the implementation of this particular
3901+ * AffineTransform and not part of the public specification. The
3902+ * state variable's value needs to be recalculated on the fly by the
3903+ * readObject method as it is in the 6-argument matrix constructor.
3904+ */
3905+
3906+ /*
3907+ * JDK 1.2 serialVersionUID
3908+ */
3909+ private static final long serialVersionUID = 1330973210523860834L;
3910+
3911+ private void writeObject(java.io.ObjectOutputStream s)
3912+ throws java.lang.ClassNotFoundException, java.io.IOException
3913+ {
3914+ s.defaultWriteObject();
3915+ }
3916+
3917+ private void readObject(java.io.ObjectInputStream s)
3918+ throws java.lang.ClassNotFoundException, java.io.IOException
3919+ {
3920+ s.defaultReadObject();
3921+ updateState();
3922+ }
3923+}
java/pkg/java/awt/geom/Arc2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Arc2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Arc2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Arc2D.java+1474−0
@@ -0,0 +1,1474 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * 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+ protected 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+}
java/pkg/java/awt/geom/ArcIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/ArcIterator.java+312−0
@@ -0,0 +1,312 @@
1+/*
2+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of an arc
32+ * through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class ArcIterator implements PathIterator {
37+ double x, y, w, h, angStRad, increment, cv;
38+ AffineTransform affine;
39+ int index;
40+ int arcSegs;
41+ int lineSegs;
42+
43+ ArcIterator(Arc2D a, AffineTransform at) {
44+ this.w = a.getWidth() / 2;
45+ this.h = a.getHeight() / 2;
46+ this.x = a.getX() + w;
47+ this.y = a.getY() + h;
48+ this.angStRad = -Math.toRadians(a.getAngleStart());
49+ this.affine = at;
50+ double ext = -a.getAngleExtent();
51+ if (ext >= 360.0 || ext <= -360) {
52+ arcSegs = 4;
53+ this.increment = Math.PI / 2;
54+ // btan(Math.PI / 2);
55+ this.cv = 0.5522847498307933;
56+ if (ext < 0) {
57+ increment = -increment;
58+ cv = -cv;
59+ }
60+ } else {
61+ arcSegs = (int) Math.ceil(Math.abs(ext) / 90.0);
62+ this.increment = Math.toRadians(ext / arcSegs);
63+ this.cv = btan(increment);
64+ if (cv == 0) {
65+ arcSegs = 0;
66+ }
67+ }
68+ switch (a.getArcType()) {
69+ case Arc2D.OPEN:
70+ lineSegs = 0;
71+ break;
72+ case Arc2D.CHORD:
73+ lineSegs = 1;
74+ break;
75+ case Arc2D.PIE:
76+ lineSegs = 2;
77+ break;
78+ }
79+ if (w < 0 || h < 0) {
80+ arcSegs = lineSegs = -1;
81+ }
82+ }
83+
84+ /**
85+ * Return the winding rule for determining the insideness of the
86+ * path.
87+ * @see #WIND_EVEN_ODD
88+ * @see #WIND_NON_ZERO
89+ */
90+ public int getWindingRule() {
91+ return WIND_NON_ZERO;
92+ }
93+
94+ /**
95+ * Tests if there are more points to read.
96+ * @return true if there are more points to read
97+ */
98+ public boolean isDone() {
99+ return index > arcSegs + lineSegs;
100+ }
101+
102+ /**
103+ * Moves the iterator to the next segment of the path forwards
104+ * along the primary direction of traversal as long as there are
105+ * more points in that direction.
106+ */
107+ public void next() {
108+ index++;
109+ }
110+
111+ /*
112+ * btan computes the length (k) of the control segments at
113+ * the beginning and end of a cubic bezier that approximates
114+ * a segment of an arc with extent less than or equal to
115+ * 90 degrees. This length (k) will be used to generate the
116+ * 2 bezier control points for such a segment.
117+ *
118+ * Assumptions:
119+ * a) arc is centered on 0,0 with radius of 1.0
120+ * b) arc extent is less than 90 degrees
121+ * c) control points should preserve tangent
122+ * d) control segments should have equal length
123+ *
124+ * Initial data:
125+ * start angle: ang1
126+ * end angle: ang2 = ang1 + extent
127+ * start point: P1 = (x1, y1) = (cos(ang1), sin(ang1))
128+ * end point: P4 = (x4, y4) = (cos(ang2), sin(ang2))
129+ *
130+ * Control points:
131+ * P2 = (x2, y2)
132+ * | x2 = x1 - k * sin(ang1) = cos(ang1) - k * sin(ang1)
133+ * | y2 = y1 + k * cos(ang1) = sin(ang1) + k * cos(ang1)
134+ *
135+ * P3 = (x3, y3)
136+ * | x3 = x4 + k * sin(ang2) = cos(ang2) + k * sin(ang2)
137+ * | y3 = y4 - k * cos(ang2) = sin(ang2) - k * cos(ang2)
138+ *
139+ * The formula for this length (k) can be found using the
140+ * following derivations:
141+ *
142+ * Midpoints:
143+ * a) bezier (t = 1/2)
144+ * bPm = P1 * (1-t)^3 +
145+ * 3 * P2 * t * (1-t)^2 +
146+ * 3 * P3 * t^2 * (1-t) +
147+ * P4 * t^3 =
148+ * = (P1 + 3P2 + 3P3 + P4)/8
149+ *
150+ * b) arc
151+ * aPm = (cos((ang1 + ang2)/2), sin((ang1 + ang2)/2))
152+ *
153+ * Let angb = (ang2 - ang1)/2; angb is half of the angle
154+ * between ang1 and ang2.
155+ *
156+ * Solve the equation bPm == aPm
157+ *
158+ * a) For xm coord:
159+ * x1 + 3*x2 + 3*x3 + x4 = 8*cos((ang1 + ang2)/2)
160+ *
161+ * cos(ang1) + 3*cos(ang1) - 3*k*sin(ang1) +
162+ * 3*cos(ang2) + 3*k*sin(ang2) + cos(ang2) =
163+ * = 8*cos((ang1 + ang2)/2)
164+ *
165+ * 4*cos(ang1) + 4*cos(ang2) + 3*k*(sin(ang2) - sin(ang1)) =
166+ * = 8*cos((ang1 + ang2)/2)
167+ *
168+ * 8*cos((ang1 + ang2)/2)*cos((ang2 - ang1)/2) +
169+ * 6*k*sin((ang2 - ang1)/2)*cos((ang1 + ang2)/2) =
170+ * = 8*cos((ang1 + ang2)/2)
171+ *
172+ * 4*cos(angb) + 3*k*sin(angb) = 4
173+ *
174+ * k = 4 / 3 * (1 - cos(angb)) / sin(angb)
175+ *
176+ * b) For ym coord we derive the same formula.
177+ *
178+ * Since this formula can generate "NaN" values for small
179+ * angles, we will derive a safer form that does not involve
180+ * dividing by very small values:
181+ * (1 - cos(angb)) / sin(angb) =
182+ * = (1 - cos(angb))*(1 + cos(angb)) / sin(angb)*(1 + cos(angb)) =
183+ * = (1 - cos(angb)^2) / sin(angb)*(1 + cos(angb)) =
184+ * = sin(angb)^2 / sin(angb)*(1 + cos(angb)) =
185+ * = sin(angb) / (1 + cos(angb))
186+ *
187+ */
188+ private static double btan(double increment) {
189+ increment /= 2.0;
190+ return 4.0 / 3.0 * Math.sin(increment) / (1.0 + Math.cos(increment));
191+ }
192+
193+ /**
194+ * Returns the coordinates and type of the current path segment in
195+ * the iteration.
196+ * The return value is the path segment type:
197+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
198+ * A float array of length 6 must be passed in and may be used to
199+ * store the coordinates of the point(s).
200+ * Each point is stored as a pair of float x,y coordinates.
201+ * SEG_MOVETO and SEG_LINETO types will return one point,
202+ * SEG_QUADTO will return two points,
203+ * SEG_CUBICTO will return 3 points
204+ * and SEG_CLOSE will not return any points.
205+ * @see #SEG_MOVETO
206+ * @see #SEG_LINETO
207+ * @see #SEG_QUADTO
208+ * @see #SEG_CUBICTO
209+ * @see #SEG_CLOSE
210+ */
211+ public int currentSegment(float[] coords) {
212+ if (isDone()) {
213+ throw new NoSuchElementException("arc iterator out of bounds");
214+ }
215+ double angle = angStRad;
216+ if (index == 0) {
217+ coords[0] = (float) (x + Math.cos(angle) * w);
218+ coords[1] = (float) (y + Math.sin(angle) * h);
219+ if (affine != null) {
220+ affine.transform(coords, 0, coords, 0, 1);
221+ }
222+ return SEG_MOVETO;
223+ }
224+ if (index > arcSegs) {
225+ if (index == arcSegs + lineSegs) {
226+ return SEG_CLOSE;
227+ }
228+ coords[0] = (float) x;
229+ coords[1] = (float) y;
230+ if (affine != null) {
231+ affine.transform(coords, 0, coords, 0, 1);
232+ }
233+ return SEG_LINETO;
234+ }
235+ angle += increment * (index - 1);
236+ double relx = Math.cos(angle);
237+ double rely = Math.sin(angle);
238+ coords[0] = (float) (x + (relx - cv * rely) * w);
239+ coords[1] = (float) (y + (rely + cv * relx) * h);
240+ angle += increment;
241+ relx = Math.cos(angle);
242+ rely = Math.sin(angle);
243+ coords[2] = (float) (x + (relx + cv * rely) * w);
244+ coords[3] = (float) (y + (rely - cv * relx) * h);
245+ coords[4] = (float) (x + relx * w);
246+ coords[5] = (float) (y + rely * h);
247+ if (affine != null) {
248+ affine.transform(coords, 0, coords, 0, 3);
249+ }
250+ return SEG_CUBICTO;
251+ }
252+
253+ /**
254+ * Returns the coordinates and type of the current path segment in
255+ * the iteration.
256+ * The return value is the path segment type:
257+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
258+ * A double array of length 6 must be passed in and may be used to
259+ * store the coordinates of the point(s).
260+ * Each point is stored as a pair of double x,y coordinates.
261+ * SEG_MOVETO and SEG_LINETO types will return one point,
262+ * SEG_QUADTO will return two points,
263+ * SEG_CUBICTO will return 3 points
264+ * and SEG_CLOSE will not return any points.
265+ * @see #SEG_MOVETO
266+ * @see #SEG_LINETO
267+ * @see #SEG_QUADTO
268+ * @see #SEG_CUBICTO
269+ * @see #SEG_CLOSE
270+ */
271+ public int currentSegment(double[] coords) {
272+ if (isDone()) {
273+ throw new NoSuchElementException("arc iterator out of bounds");
274+ }
275+ double angle = angStRad;
276+ if (index == 0) {
277+ coords[0] = x + Math.cos(angle) * w;
278+ coords[1] = y + Math.sin(angle) * h;
279+ if (affine != null) {
280+ affine.transform(coords, 0, coords, 0, 1);
281+ }
282+ return SEG_MOVETO;
283+ }
284+ if (index > arcSegs) {
285+ if (index == arcSegs + lineSegs) {
286+ return SEG_CLOSE;
287+ }
288+ coords[0] = x;
289+ coords[1] = y;
290+ if (affine != null) {
291+ affine.transform(coords, 0, coords, 0, 1);
292+ }
293+ return SEG_LINETO;
294+ }
295+ angle += increment * (index - 1);
296+ double relx = Math.cos(angle);
297+ double rely = Math.sin(angle);
298+ coords[0] = x + (relx - cv * rely) * w;
299+ coords[1] = y + (rely + cv * relx) * h;
300+ angle += increment;
301+ relx = Math.cos(angle);
302+ rely = Math.sin(angle);
303+ coords[2] = x + (relx + cv * rely) * w;
304+ coords[3] = y + (rely - cv * relx) * h;
305+ coords[4] = x + relx * w;
306+ coords[5] = y + rely * h;
307+ if (affine != null) {
308+ affine.transform(coords, 0, coords, 0, 3);
309+ }
310+ return SEG_CUBICTO;
311+ }
312+}
java/pkg/java/awt/geom/Area.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Area.java+744−0
@@ -0,0 +1,744 @@
1+/*
2+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.awt.Rectangle;
30+import java.util.Vector;
31+import java.util.Enumeration;
32+import java.util.NoSuchElementException;
33+import sun.awt.geom.Curve;
34+import sun.awt.geom.Crossings;
35+import sun.awt.geom.AreaOp;
36+
37+/**
38+ * An <code>Area</code> object stores and manipulates a
39+ * resolution-independent description of an enclosed area of
40+ * 2-dimensional space.
41+ * <code>Area</code> objects can be transformed and can perform
42+ * various Constructive Area Geometry (CAG) operations when combined
43+ * with other <code>Area</code> objects.
44+ * The CAG operations include area
45+ * {@link #add addition}, {@link #subtract subtraction},
46+ * {@link #intersect intersection}, and {@link #exclusiveOr exclusive or}.
47+ * See the linked method documentation for examples of the various
48+ * operations.
49+ * <p>
50+ * The <code>Area</code> class implements the <code>Shape</code>
51+ * interface and provides full support for all of its hit-testing
52+ * and path iteration facilities, but an <code>Area</code> is more
53+ * specific than a generalized path in a number of ways:
54+ * <ul>
55+ * <li>Only closed paths and sub-paths are stored.
56+ * <code>Area</code> objects constructed from unclosed paths
57+ * are implicitly closed during construction as if those paths
58+ * had been filled by the <code>Graphics2D.fill</code> method.
59+ * <li>The interiors of the individual stored sub-paths are all
60+ * non-empty and non-overlapping. Paths are decomposed during
61+ * construction into separate component non-overlapping parts,
62+ * empty pieces of the path are discarded, and then these
63+ * non-empty and non-overlapping properties are maintained
64+ * through all subsequent CAG operations. Outlines of different
65+ * component sub-paths may touch each other, as long as they
66+ * do not cross so that their enclosed areas overlap.
67+ * <li>The geometry of the path describing the outline of the
68+ * <code>Area</code> resembles the path from which it was
69+ * constructed only in that it describes the same enclosed
70+ * 2-dimensional area, but may use entirely different types
71+ * and ordering of the path segments to do so.
72+ * </ul>
73+ * Interesting issues which are not always obvious when using
74+ * the <code>Area</code> include:
75+ * <ul>
76+ * <li>Creating an <code>Area</code> from an unclosed (open)
77+ * <code>Shape</code> results in a closed outline in the
78+ * <code>Area</code> object.
79+ * <li>Creating an <code>Area</code> from a <code>Shape</code>
80+ * which encloses no area (even when "closed") produces an
81+ * empty <code>Area</code>. A common example of this issue
82+ * is that producing an <code>Area</code> from a line will
83+ * be empty since the line encloses no area. An empty
84+ * <code>Area</code> will iterate no geometry in its
85+ * <code>PathIterator</code> objects.
86+ * <li>A self-intersecting <code>Shape</code> may be split into
87+ * two (or more) sub-paths each enclosing one of the
88+ * non-intersecting portions of the original path.
89+ * <li>An <code>Area</code> may take more path segments to
90+ * describe the same geometry even when the original
91+ * outline is simple and obvious. The analysis that the
92+ * <code>Area</code> class must perform on the path may
93+ * not reflect the same concepts of "simple and obvious"
94+ * as a human being perceives.
95+ * </ul>
96+ *
97+ * @since 1.2
98+ */
99+public class Area implements Shape, Cloneable {
100+ private static Vector EmptyCurves = new Vector();
101+
102+ private Vector curves;
103+
104+ /**
105+ * Default constructor which creates an empty area.
106+ * @since 1.2
107+ */
108+ public Area() {
109+ curves = EmptyCurves;
110+ }
111+
112+ /**
113+ * The <code>Area</code> class creates an area geometry from the
114+ * specified {@link Shape} object. The geometry is explicitly
115+ * closed, if the <code>Shape</code> is not already closed. The
116+ * fill rule (even-odd or winding) specified by the geometry of the
117+ * <code>Shape</code> is used to determine the resulting enclosed area.
118+ * @param s the <code>Shape</code> from which the area is constructed
119+ * @throws NullPointerException if <code>s</code> is null
120+ * @since 1.2
121+ */
122+ public Area(Shape s) {
123+ if (s instanceof Area) {
124+ curves = ((Area) s).curves;
125+ } else {
126+ curves = pathToCurves(s.getPathIterator(null));
127+ }
128+ }
129+
130+ private static Vector pathToCurves(PathIterator pi) {
131+ Vector curves = new Vector();
132+ int windingRule = pi.getWindingRule();
133+ // coords array is big enough for holding:
134+ // coordinates returned from currentSegment (6)
135+ // OR
136+ // two subdivided quadratic curves (2+4+4=10)
137+ // AND
138+ // 0-1 horizontal splitting parameters
139+ // OR
140+ // 2 parametric equation derivative coefficients
141+ // OR
142+ // three subdivided cubic curves (2+6+6+6=20)
143+ // AND
144+ // 0-2 horizontal splitting parameters
145+ // OR
146+ // 3 parametric equation derivative coefficients
147+ double coords[] = new double[23];
148+ double movx = 0, movy = 0;
149+ double curx = 0, cury = 0;
150+ double newx, newy;
151+ while (!pi.isDone()) {
152+ switch (pi.currentSegment(coords)) {
153+ case PathIterator.SEG_MOVETO:
154+ Curve.insertLine(curves, curx, cury, movx, movy);
155+ curx = movx = coords[0];
156+ cury = movy = coords[1];
157+ Curve.insertMove(curves, movx, movy);
158+ break;
159+ case PathIterator.SEG_LINETO:
160+ newx = coords[0];
161+ newy = coords[1];
162+ Curve.insertLine(curves, curx, cury, newx, newy);
163+ curx = newx;
164+ cury = newy;
165+ break;
166+ case PathIterator.SEG_QUADTO:
167+ newx = coords[2];
168+ newy = coords[3];
169+ Curve.insertQuad(curves, curx, cury, coords);
170+ curx = newx;
171+ cury = newy;
172+ break;
173+ case PathIterator.SEG_CUBICTO:
174+ newx = coords[4];
175+ newy = coords[5];
176+ Curve.insertCubic(curves, curx, cury, coords);
177+ curx = newx;
178+ cury = newy;
179+ break;
180+ case PathIterator.SEG_CLOSE:
181+ Curve.insertLine(curves, curx, cury, movx, movy);
182+ curx = movx;
183+ cury = movy;
184+ break;
185+ }
186+ pi.next();
187+ }
188+ Curve.insertLine(curves, curx, cury, movx, movy);
189+ AreaOp operator;
190+ if (windingRule == PathIterator.WIND_EVEN_ODD) {
191+ operator = new AreaOp.EOWindOp();
192+ } else {
193+ operator = new AreaOp.NZWindOp();
194+ }
195+ return operator.calculate(curves, EmptyCurves);
196+ }
197+
198+ /**
199+ * Adds the shape of the specified <code>Area</code> to the
200+ * shape of this <code>Area</code>.
201+ * The resulting shape of this <code>Area</code> will include
202+ * the union of both shapes, or all areas that were contained
203+ * in either this or the specified <code>Area</code>.
204+ * <pre>
205+ * // Example:
206+ * Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
207+ * Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
208+ * a1.add(a2);
209+ *
210+ * a1(before) + a2 = a1(after)
211+ *
212+ * ################ ################ ################
213+ * ############## ############## ################
214+ * ############ ############ ################
215+ * ########## ########## ################
216+ * ######## ######## ################
217+ * ###### ###### ###### ######
218+ * #### #### #### ####
219+ * ## ## ## ##
220+ * </pre>
221+ * @param rhs the <code>Area</code> to be added to the
222+ * current shape
223+ * @throws NullPointerException if <code>rhs</code> is null
224+ * @since 1.2
225+ */
226+ public void add(Area rhs) {
227+ curves = new AreaOp.AddOp().calculate(this.curves, rhs.curves);
228+ invalidateBounds();
229+ }
230+
231+ /**
232+ * Subtracts the shape of the specified <code>Area</code> from the
233+ * shape of this <code>Area</code>.
234+ * The resulting shape of this <code>Area</code> will include
235+ * areas that were contained only in this <code>Area</code>
236+ * and not in the specified <code>Area</code>.
237+ * <pre>
238+ * // Example:
239+ * Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
240+ * Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
241+ * a1.subtract(a2);
242+ *
243+ * a1(before) - a2 = a1(after)
244+ *
245+ * ################ ################
246+ * ############## ############## ##
247+ * ############ ############ ####
248+ * ########## ########## ######
249+ * ######## ######## ########
250+ * ###### ###### ######
251+ * #### #### ####
252+ * ## ## ##
253+ * </pre>
254+ * @param rhs the <code>Area</code> to be subtracted from the
255+ * current shape
256+ * @throws NullPointerException if <code>rhs</code> is null
257+ * @since 1.2
258+ */
259+ public void subtract(Area rhs) {
260+ curves = new AreaOp.SubOp().calculate(this.curves, rhs.curves);
261+ invalidateBounds();
262+ }
263+
264+ /**
265+ * Sets the shape of this <code>Area</code> to the intersection of
266+ * its current shape and the shape of the specified <code>Area</code>.
267+ * The resulting shape of this <code>Area</code> will include
268+ * only areas that were contained in both this <code>Area</code>
269+ * and also in the specified <code>Area</code>.
270+ * <pre>
271+ * // Example:
272+ * Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
273+ * Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
274+ * a1.intersect(a2);
275+ *
276+ * a1(before) intersect a2 = a1(after)
277+ *
278+ * ################ ################ ################
279+ * ############## ############## ############
280+ * ############ ############ ########
281+ * ########## ########## ####
282+ * ######## ########
283+ * ###### ######
284+ * #### ####
285+ * ## ##
286+ * </pre>
287+ * @param rhs the <code>Area</code> to be intersected with this
288+ * <code>Area</code>
289+ * @throws NullPointerException if <code>rhs</code> is null
290+ * @since 1.2
291+ */
292+ public void intersect(Area rhs) {
293+ curves = new AreaOp.IntOp().calculate(this.curves, rhs.curves);
294+ invalidateBounds();
295+ }
296+
297+ /**
298+ * Sets the shape of this <code>Area</code> to be the combined area
299+ * of its current shape and the shape of the specified <code>Area</code>,
300+ * minus their intersection.
301+ * The resulting shape of this <code>Area</code> will include
302+ * only areas that were contained in either this <code>Area</code>
303+ * or in the specified <code>Area</code>, but not in both.
304+ * <pre>
305+ * // Example:
306+ * Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
307+ * Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
308+ * a1.exclusiveOr(a2);
309+ *
310+ * a1(before) xor a2 = a1(after)
311+ *
312+ * ################ ################
313+ * ############## ############## ## ##
314+ * ############ ############ #### ####
315+ * ########## ########## ###### ######
316+ * ######## ######## ################
317+ * ###### ###### ###### ######
318+ * #### #### #### ####
319+ * ## ## ## ##
320+ * </pre>
321+ * @param rhs the <code>Area</code> to be exclusive ORed with this
322+ * <code>Area</code>.
323+ * @throws NullPointerException if <code>rhs</code> is null
324+ * @since 1.2
325+ */
326+ public void exclusiveOr(Area rhs) {
327+ curves = new AreaOp.XorOp().calculate(this.curves, rhs.curves);
328+ invalidateBounds();
329+ }
330+
331+ /**
332+ * Removes all of the geometry from this <code>Area</code> and
333+ * restores it to an empty area.
334+ * @since 1.2
335+ */
336+ public void reset() {
337+ curves = new Vector();
338+ invalidateBounds();
339+ }
340+
341+ /**
342+ * Tests whether this <code>Area</code> object encloses any area.
343+ * @return <code>true</code> if this <code>Area</code> object
344+ * represents an empty area; <code>false</code> otherwise.
345+ * @since 1.2
346+ */
347+ public boolean isEmpty() {
348+ return (curves.size() == 0);
349+ }
350+
351+ /**
352+ * Tests whether this <code>Area</code> consists entirely of
353+ * straight edged polygonal geometry.
354+ * @return <code>true</code> if the geometry of this
355+ * <code>Area</code> consists entirely of line segments;
356+ * <code>false</code> otherwise.
357+ * @since 1.2
358+ */
359+ public boolean isPolygonal() {
360+ Enumeration enum_ = curves.elements();
361+ while (enum_.hasMoreElements()) {
362+ if (((Curve) enum_.nextElement()).getOrder() > 1) {
363+ return false;
364+ }
365+ }
366+ return true;
367+ }
368+
369+ /**
370+ * Tests whether this <code>Area</code> is rectangular in shape.
371+ * @return <code>true</code> if the geometry of this
372+ * <code>Area</code> is rectangular in shape; <code>false</code>
373+ * otherwise.
374+ * @since 1.2
375+ */
376+ public boolean isRectangular() {
377+ int size = curves.size();
378+ if (size == 0) {
379+ return true;
380+ }
381+ if (size > 3) {
382+ return false;
383+ }
384+ Curve c1 = (Curve) curves.get(1);
385+ Curve c2 = (Curve) curves.get(2);
386+ if (c1.getOrder() != 1 || c2.getOrder() != 1) {
387+ return false;
388+ }
389+ if (c1.getXTop() != c1.getXBot() || c2.getXTop() != c2.getXBot()) {
390+ return false;
391+ }
392+ if (c1.getYTop() != c2.getYTop() || c1.getYBot() != c2.getYBot()) {
393+ // One might be able to prove that this is impossible...
394+ return false;
395+ }
396+ return true;
397+ }
398+
399+ /**
400+ * Tests whether this <code>Area</code> is comprised of a single
401+ * closed subpath. This method returns <code>true</code> if the
402+ * path contains 0 or 1 subpaths, or <code>false</code> if the path
403+ * contains more than 1 subpath. The subpaths are counted by the
404+ * number of {@link PathIterator#SEG_MOVETO SEG_MOVETO} segments
405+ * that appear in the path.
406+ * @return <code>true</code> if the <code>Area</code> is comprised
407+ * of a single basic geometry; <code>false</code> otherwise.
408+ * @since 1.2
409+ */
410+ public boolean isSingular() {
411+ if (curves.size() < 3) {
412+ return true;
413+ }
414+ Enumeration enum_ = curves.elements();
415+ enum_.nextElement(); // First Order0 "moveto"
416+ while (enum_.hasMoreElements()) {
417+ if (((Curve) enum_.nextElement()).getOrder() == 0) {
418+ return false;
419+ }
420+ }
421+ return true;
422+ }
423+
424+ private Rectangle2D cachedBounds;
425+ private void invalidateBounds() {
426+ cachedBounds = null;
427+ }
428+ private Rectangle2D getCachedBounds() {
429+ if (cachedBounds != null) {
430+ return cachedBounds;
431+ }
432+ Rectangle2D r = new Rectangle2D.Double();
433+ if (curves.size() > 0) {
434+ Curve c = (Curve) curves.get(0);
435+ // First point is always an order 0 curve (moveto)
436+ r.setRect(c.getX0(), c.getY0(), 0, 0);
437+ for (int i = 1; i < curves.size(); i++) {
438+ ((Curve) curves.get(i)).enlarge(r);
439+ }
440+ }
441+ return (cachedBounds = r);
442+ }
443+
444+ /**
445+ * Returns a high precision bounding {@link Rectangle2D} that
446+ * completely encloses this <code>Area</code>.
447+ * <p>
448+ * The Area class will attempt to return the tightest bounding
449+ * box possible for the Shape. The bounding box will not be
450+ * padded to include the control points of curves in the outline
451+ * of the Shape, but should tightly fit the actual geometry of
452+ * the outline itself.
453+ * @return the bounding <code>Rectangle2D</code> for the
454+ * <code>Area</code>.
455+ * @since 1.2
456+ */
457+ public Rectangle2D getBounds2D() {
458+ return getCachedBounds().getBounds2D();
459+ }
460+
461+ /**
462+ * Returns a bounding {@link Rectangle} that completely encloses
463+ * this <code>Area</code>.
464+ * <p>
465+ * The Area class will attempt to return the tightest bounding
466+ * box possible for the Shape. The bounding box will not be
467+ * padded to include the control points of curves in the outline
468+ * of the Shape, but should tightly fit the actual geometry of
469+ * the outline itself. Since the returned object represents
470+ * the bounding box with integers, the bounding box can only be
471+ * as tight as the nearest integer coordinates that encompass
472+ * the geometry of the Shape.
473+ * @return the bounding <code>Rectangle</code> for the
474+ * <code>Area</code>.
475+ * @since 1.2
476+ */
477+ public Rectangle getBounds() {
478+ return getCachedBounds().getBounds();
479+ }
480+
481+ /**
482+ * Returns an exact copy of this <code>Area</code> object.
483+ * @return Created clone object
484+ * @since 1.2
485+ */
486+ public Object clone() {
487+ return new Area(this);
488+ }
489+
490+ /**
491+ * Tests whether the geometries of the two <code>Area</code> objects
492+ * are equal.
493+ * This method will return false if the argument is null.
494+ * @param other the <code>Area</code> to be compared to this
495+ * <code>Area</code>
496+ * @return <code>true</code> if the two geometries are equal;
497+ * <code>false</code> otherwise.
498+ * @since 1.2
499+ */
500+ public boolean equals(Area other) {
501+ // REMIND: A *much* simpler operation should be possible...
502+ // Should be able to do a curve-wise comparison since all Areas
503+ // should evaluate their curves in the same top-down order.
504+ if (other == this) {
505+ return true;
506+ }
507+ if (other == null) {
508+ return false;
509+ }
510+ Vector c = new AreaOp.XorOp().calculate(this.curves, other.curves);
511+ return c.isEmpty();
512+ }
513+
514+ /**
515+ * Transforms the geometry of this <code>Area</code> using the specified
516+ * {@link AffineTransform}. The geometry is transformed in place, which
517+ * permanently changes the enclosed area defined by this object.
518+ * @param t the transformation used to transform the area
519+ * @throws NullPointerException if <code>t</code> is null
520+ * @since 1.2
521+ */
522+ public void transform(AffineTransform t) {
523+ if (t == null) {
524+ throw new NullPointerException("transform must not be null");
525+ }
526+ // REMIND: A simpler operation can be performed for some types
527+ // of transform.
528+ curves = pathToCurves(getPathIterator(t));
529+ invalidateBounds();
530+ }
531+
532+ /**
533+ * Creates a new <code>Area</code> object that contains the same
534+ * geometry as this <code>Area</code> transformed by the specified
535+ * <code>AffineTransform</code>. This <code>Area</code> object
536+ * is unchanged.
537+ * @param t the specified <code>AffineTransform</code> used to transform
538+ * the new <code>Area</code>
539+ * @throws NullPointerException if <code>t</code> is null
540+ * @return a new <code>Area</code> object representing the transformed
541+ * geometry.
542+ * @since 1.2
543+ */
544+ public Area createTransformedArea(AffineTransform t) {
545+ Area a = new Area(this);
546+ a.transform(t);
547+ return a;
548+ }
549+
550+ /**
551+ * {@inheritDoc}
552+ * @since 1.2
553+ */
554+ public boolean contains(double x, double y) {
555+ if (!getCachedBounds().contains(x, y)) {
556+ return false;
557+ }
558+ Enumeration enum_ = curves.elements();
559+ int crossings = 0;
560+ while (enum_.hasMoreElements()) {
561+ Curve c = (Curve) enum_.nextElement();
562+ crossings += c.crossingsFor(x, y);
563+ }
564+ return ((crossings & 1) == 1);
565+ }
566+
567+ /**
568+ * {@inheritDoc}
569+ * @since 1.2
570+ */
571+ public boolean contains(Point2D p) {
572+ return contains(p.getX(), p.getY());
573+ }
574+
575+ /**
576+ * {@inheritDoc}
577+ * @since 1.2
578+ */
579+ public boolean contains(double x, double y, double w, double h) {
580+ if (w < 0 || h < 0) {
581+ return false;
582+ }
583+ if (!getCachedBounds().contains(x, y, w, h)) {
584+ return false;
585+ }
586+ Crossings c = Crossings.findCrossings(curves, x, y, x+w, y+h);
587+ return (c != null && c.covers(y, y+h));
588+ }
589+
590+ /**
591+ * {@inheritDoc}
592+ * @since 1.2
593+ */
594+ public boolean contains(Rectangle2D r) {
595+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
596+ }
597+
598+ /**
599+ * {@inheritDoc}
600+ * @since 1.2
601+ */
602+ public boolean intersects(double x, double y, double w, double h) {
603+ if (w < 0 || h < 0) {
604+ return false;
605+ }
606+ if (!getCachedBounds().intersects(x, y, w, h)) {
607+ return false;
608+ }
609+ Crossings c = Crossings.findCrossings(curves, x, y, x+w, y+h);
610+ return (c == null || !c.isEmpty());
611+ }
612+
613+ /**
614+ * {@inheritDoc}
615+ * @since 1.2
616+ */
617+ public boolean intersects(Rectangle2D r) {
618+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
619+ }
620+
621+ /**
622+ * Creates a {@link PathIterator} for the outline of this
623+ * <code>Area</code> object. This <code>Area</code> object is unchanged.
624+ * @param at an optional <code>AffineTransform</code> to be applied to
625+ * the coordinates as they are returned in the iteration, or
626+ * <code>null</code> if untransformed coordinates are desired
627+ * @return the <code>PathIterator</code> object that returns the
628+ * geometry of the outline of this <code>Area</code>, one
629+ * segment at a time.
630+ * @since 1.2
631+ */
632+ public PathIterator getPathIterator(AffineTransform at) {
633+ return new AreaIterator(curves, at);
634+ }
635+
636+ /**
637+ * Creates a <code>PathIterator</code> for the flattened outline of
638+ * this <code>Area</code> object. Only uncurved path segments
639+ * represented by the SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point
640+ * types are returned by the iterator. This <code>Area</code>
641+ * object is unchanged.
642+ * @param at an optional <code>AffineTransform</code> to be
643+ * applied to the coordinates as they are returned in the
644+ * iteration, or <code>null</code> if untransformed coordinates
645+ * are desired
646+ * @param flatness the maximum amount that the control points
647+ * for a given curve can vary from colinear before a subdivided
648+ * curve is replaced by a straight line connecting the end points
649+ * @return the <code>PathIterator</code> object that returns the
650+ * geometry of the outline of this <code>Area</code>, one segment
651+ * at a time.
652+ * @since 1.2
653+ */
654+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
655+ return new FlatteningPathIterator(getPathIterator(at), flatness);
656+ }
657+}
658+
659+class AreaIterator implements PathIterator {
660+ private AffineTransform transform;
661+ private Vector curves;
662+ private int index;
663+ private Curve prevcurve;
664+ private Curve thiscurve;
665+
666+ public AreaIterator(Vector curves, AffineTransform at) {
667+ this.curves = curves;
668+ this.transform = at;
669+ if (curves.size() >= 1) {
670+ thiscurve = (Curve) curves.get(0);
671+ }
672+ }
673+
674+ public int getWindingRule() {
675+ // REMIND: Which is better, EVEN_ODD or NON_ZERO?
676+ // The paths calculated could be classified either way.
677+ //return WIND_EVEN_ODD;
678+ return WIND_NON_ZERO;
679+ }
680+
681+ public boolean isDone() {
682+ return (prevcurve == null && thiscurve == null);
683+ }
684+
685+ public void next() {
686+ if (prevcurve != null) {
687+ prevcurve = null;
688+ } else {
689+ prevcurve = thiscurve;
690+ index++;
691+ if (index < curves.size()) {
692+ thiscurve = (Curve) curves.get(index);
693+ if (thiscurve.getOrder() != 0 &&
694+ prevcurve.getX1() == thiscurve.getX0() &&
695+ prevcurve.getY1() == thiscurve.getY0())
696+ {
697+ prevcurve = null;
698+ }
699+ } else {
700+ thiscurve = null;
701+ }
702+ }
703+ }
704+
705+ public int currentSegment(float coords[]) {
706+ double dcoords[] = new double[6];
707+ int segtype = currentSegment(dcoords);
708+ int numpoints = (segtype == SEG_CLOSE ? 0
709+ : (segtype == SEG_QUADTO ? 2
710+ : (segtype == SEG_CUBICTO ? 3
711+ : 1)));
712+ for (int i = 0; i < numpoints * 2; i++) {
713+ coords[i] = (float) dcoords[i];
714+ }
715+ return segtype;
716+ }
717+
718+ public int currentSegment(double coords[]) {
719+ int segtype;
720+ int numpoints;
721+ if (prevcurve != null) {
722+ // Need to finish off junction between curves
723+ if (thiscurve == null || thiscurve.getOrder() == 0) {
724+ return SEG_CLOSE;
725+ }
726+ coords[0] = thiscurve.getX0();
727+ coords[1] = thiscurve.getY0();
728+ segtype = SEG_LINETO;
729+ numpoints = 1;
730+ } else if (thiscurve == null) {
731+ throw new NoSuchElementException("area iterator out of bounds");
732+ } else {
733+ segtype = thiscurve.getSegment(coords);
734+ numpoints = thiscurve.getOrder();
735+ if (numpoints == 0) {
736+ numpoints = 1;
737+ }
738+ }
739+ if (transform != null) {
740+ transform.transform(coords, 0, coords, 0, numpoints);
741+ }
742+ return segtype;
743+ }
744+}
java/pkg/java/awt/geom/AreaIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/CubicCurve2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/CubicCurve2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/CubicCurve2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/CubicCurve2D.java+1575−0
@@ -0,0 +1,1575 @@
1+/*
2+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.awt.Rectangle;
30+import java.util.Arrays;
31+import java.io.Serializable;
32+import sun.awt.geom.Curve;
33+
34+import static java.lang.Math.abs;
35+import static java.lang.Math.max;
36+import static java.lang.Math.ulp;
37+
38+/**
39+ * The <code>CubicCurve2D</code> class defines a cubic parametric curve
40+ * segment in {@code (x,y)} coordinate space.
41+ * <p>
42+ * This class is only the abstract superclass for all objects which
43+ * store a 2D cubic curve segment.
44+ * The actual storage representation of the coordinates is left to
45+ * the subclass.
46+ *
47+ * @author Jim Graham
48+ * @since 1.2
49+ */
50+public abstract class CubicCurve2D implements Shape, Cloneable {
51+
52+ /**
53+ * A cubic parametric curve segment specified with
54+ * {@code float} coordinates.
55+ * @since 1.2
56+ */
57+ public static class Float extends CubicCurve2D implements Serializable {
58+ /**
59+ * The X coordinate of the start point
60+ * of the cubic curve segment.
61+ * @since 1.2
62+ * @serial
63+ */
64+ public float x1;
65+
66+ /**
67+ * The Y coordinate of the start point
68+ * of the cubic curve segment.
69+ * @since 1.2
70+ * @serial
71+ */
72+ public float y1;
73+
74+ /**
75+ * The X coordinate of the first control point
76+ * of the cubic curve segment.
77+ * @since 1.2
78+ * @serial
79+ */
80+ public float ctrlx1;
81+
82+ /**
83+ * The Y coordinate of the first control point
84+ * of the cubic curve segment.
85+ * @since 1.2
86+ * @serial
87+ */
88+ public float ctrly1;
89+
90+ /**
91+ * The X coordinate of the second control point
92+ * of the cubic curve segment.
93+ * @since 1.2
94+ * @serial
95+ */
96+ public float ctrlx2;
97+
98+ /**
99+ * The Y coordinate of the second control point
100+ * of the cubic curve segment.
101+ * @since 1.2
102+ * @serial
103+ */
104+ public float ctrly2;
105+
106+ /**
107+ * The X coordinate of the end point
108+ * of the cubic curve segment.
109+ * @since 1.2
110+ * @serial
111+ */
112+ public float x2;
113+
114+ /**
115+ * The Y coordinate of the end point
116+ * of the cubic curve segment.
117+ * @since 1.2
118+ * @serial
119+ */
120+ public float y2;
121+
122+ /**
123+ * Constructs and initializes a CubicCurve with coordinates
124+ * (0, 0, 0, 0, 0, 0, 0, 0).
125+ * @since 1.2
126+ */
127+ public Float() {
128+ }
129+
130+ /**
131+ * Constructs and initializes a {@code CubicCurve2D} from
132+ * the specified {@code float} coordinates.
133+ *
134+ * @param x1 the X coordinate for the start point
135+ * of the resulting {@code CubicCurve2D}
136+ * @param y1 the Y coordinate for the start point
137+ * of the resulting {@code CubicCurve2D}
138+ * @param ctrlx1 the X coordinate for the first control point
139+ * of the resulting {@code CubicCurve2D}
140+ * @param ctrly1 the Y coordinate for the first control point
141+ * of the resulting {@code CubicCurve2D}
142+ * @param ctrlx2 the X coordinate for the second control point
143+ * of the resulting {@code CubicCurve2D}
144+ * @param ctrly2 the Y coordinate for the second control point
145+ * of the resulting {@code CubicCurve2D}
146+ * @param x2 the X coordinate for the end point
147+ * of the resulting {@code CubicCurve2D}
148+ * @param y2 the Y coordinate for the end point
149+ * of the resulting {@code CubicCurve2D}
150+ * @since 1.2
151+ */
152+ public Float(float x1, float y1,
153+ float ctrlx1, float ctrly1,
154+ float ctrlx2, float ctrly2,
155+ float x2, float y2)
156+ {
157+ setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
158+ }
159+
160+ /**
161+ * {@inheritDoc}
162+ * @since 1.2
163+ */
164+ public double getX1() {
165+ return (double) x1;
166+ }
167+
168+ /**
169+ * {@inheritDoc}
170+ * @since 1.2
171+ */
172+ public double getY1() {
173+ return (double) y1;
174+ }
175+
176+ /**
177+ * {@inheritDoc}
178+ * @since 1.2
179+ */
180+ public Point2D getP1() {
181+ return new Point2D.Float(x1, y1);
182+ }
183+
184+ /**
185+ * {@inheritDoc}
186+ * @since 1.2
187+ */
188+ public double getCtrlX1() {
189+ return (double) ctrlx1;
190+ }
191+
192+ /**
193+ * {@inheritDoc}
194+ * @since 1.2
195+ */
196+ public double getCtrlY1() {
197+ return (double) ctrly1;
198+ }
199+
200+ /**
201+ * {@inheritDoc}
202+ * @since 1.2
203+ */
204+ public Point2D getCtrlP1() {
205+ return new Point2D.Float(ctrlx1, ctrly1);
206+ }
207+
208+ /**
209+ * {@inheritDoc}
210+ * @since 1.2
211+ */
212+ public double getCtrlX2() {
213+ return (double) ctrlx2;
214+ }
215+
216+ /**
217+ * {@inheritDoc}
218+ * @since 1.2
219+ */
220+ public double getCtrlY2() {
221+ return (double) ctrly2;
222+ }
223+
224+ /**
225+ * {@inheritDoc}
226+ * @since 1.2
227+ */
228+ public Point2D getCtrlP2() {
229+ return new Point2D.Float(ctrlx2, ctrly2);
230+ }
231+
232+ /**
233+ * {@inheritDoc}
234+ * @since 1.2
235+ */
236+ public double getX2() {
237+ return (double) x2;
238+ }
239+
240+ /**
241+ * {@inheritDoc}
242+ * @since 1.2
243+ */
244+ public double getY2() {
245+ return (double) y2;
246+ }
247+
248+ /**
249+ * {@inheritDoc}
250+ * @since 1.2
251+ */
252+ public Point2D getP2() {
253+ return new Point2D.Float(x2, y2);
254+ }
255+
256+ /**
257+ * {@inheritDoc}
258+ * @since 1.2
259+ */
260+ public void setCurve(double x1, double y1,
261+ double ctrlx1, double ctrly1,
262+ double ctrlx2, double ctrly2,
263+ double x2, double y2)
264+ {
265+ this.x1 = (float) x1;
266+ this.y1 = (float) y1;
267+ this.ctrlx1 = (float) ctrlx1;
268+ this.ctrly1 = (float) ctrly1;
269+ this.ctrlx2 = (float) ctrlx2;
270+ this.ctrly2 = (float) ctrly2;
271+ this.x2 = (float) x2;
272+ this.y2 = (float) y2;
273+ }
274+
275+ /**
276+ * Sets the location of the end points and control points
277+ * of this curve to the specified {@code float} coordinates.
278+ *
279+ * @param x1 the X coordinate used to set the start point
280+ * of this {@code CubicCurve2D}
281+ * @param y1 the Y coordinate used to set the start point
282+ * of this {@code CubicCurve2D}
283+ * @param ctrlx1 the X coordinate used to set the first control point
284+ * of this {@code CubicCurve2D}
285+ * @param ctrly1 the Y coordinate used to set the first control point
286+ * of this {@code CubicCurve2D}
287+ * @param ctrlx2 the X coordinate used to set the second control point
288+ * of this {@code CubicCurve2D}
289+ * @param ctrly2 the Y coordinate used to set the second control point
290+ * of this {@code CubicCurve2D}
291+ * @param x2 the X coordinate used to set the end point
292+ * of this {@code CubicCurve2D}
293+ * @param y2 the Y coordinate used to set the end point
294+ * of this {@code CubicCurve2D}
295+ * @since 1.2
296+ */
297+ public void setCurve(float x1, float y1,
298+ float ctrlx1, float ctrly1,
299+ float ctrlx2, float ctrly2,
300+ float x2, float y2)
301+ {
302+ this.x1 = x1;
303+ this.y1 = y1;
304+ this.ctrlx1 = ctrlx1;
305+ this.ctrly1 = ctrly1;
306+ this.ctrlx2 = ctrlx2;
307+ this.ctrly2 = ctrly2;
308+ this.x2 = x2;
309+ this.y2 = y2;
310+ }
311+
312+ /**
313+ * {@inheritDoc}
314+ * @since 1.2
315+ */
316+ public Rectangle2D getBounds2D() {
317+ float left = Math.min(Math.min(x1, x2),
318+ Math.min(ctrlx1, ctrlx2));
319+ float top = Math.min(Math.min(y1, y2),
320+ Math.min(ctrly1, ctrly2));
321+ float right = Math.max(Math.max(x1, x2),
322+ Math.max(ctrlx1, ctrlx2));
323+ float bottom = Math.max(Math.max(y1, y2),
324+ Math.max(ctrly1, ctrly2));
325+ return new Rectangle2D.Float(left, top,
326+ right - left, bottom - top);
327+ }
328+
329+ /*
330+ * JDK 1.6 serialVersionUID
331+ */
332+ private static final long serialVersionUID = -1272015596714244385L;
333+ }
334+
335+ /**
336+ * A cubic parametric curve segment specified with
337+ * {@code double} coordinates.
338+ * @since 1.2
339+ */
340+ public static class Double extends CubicCurve2D implements Serializable {
341+ /**
342+ * The X coordinate of the start point
343+ * of the cubic curve segment.
344+ * @since 1.2
345+ * @serial
346+ */
347+ public double x1;
348+
349+ /**
350+ * The Y coordinate of the start point
351+ * of the cubic curve segment.
352+ * @since 1.2
353+ * @serial
354+ */
355+ public double y1;
356+
357+ /**
358+ * The X coordinate of the first control point
359+ * of the cubic curve segment.
360+ * @since 1.2
361+ * @serial
362+ */
363+ public double ctrlx1;
364+
365+ /**
366+ * The Y coordinate of the first control point
367+ * of the cubic curve segment.
368+ * @since 1.2
369+ * @serial
370+ */
371+ public double ctrly1;
372+
373+ /**
374+ * The X coordinate of the second control point
375+ * of the cubic curve segment.
376+ * @since 1.2
377+ * @serial
378+ */
379+ public double ctrlx2;
380+
381+ /**
382+ * The Y coordinate of the second control point
383+ * of the cubic curve segment.
384+ * @since 1.2
385+ * @serial
386+ */
387+ public double ctrly2;
388+
389+ /**
390+ * The X coordinate of the end point
391+ * of the cubic curve segment.
392+ * @since 1.2
393+ * @serial
394+ */
395+ public double x2;
396+
397+ /**
398+ * The Y coordinate of the end point
399+ * of the cubic curve segment.
400+ * @since 1.2
401+ * @serial
402+ */
403+ public double y2;
404+
405+ /**
406+ * Constructs and initializes a CubicCurve with coordinates
407+ * (0, 0, 0, 0, 0, 0, 0, 0).
408+ * @since 1.2
409+ */
410+ public Double() {
411+ }
412+
413+ /**
414+ * Constructs and initializes a {@code CubicCurve2D} from
415+ * the specified {@code double} coordinates.
416+ *
417+ * @param x1 the X coordinate for the start point
418+ * of the resulting {@code CubicCurve2D}
419+ * @param y1 the Y coordinate for the start point
420+ * of the resulting {@code CubicCurve2D}
421+ * @param ctrlx1 the X coordinate for the first control point
422+ * of the resulting {@code CubicCurve2D}
423+ * @param ctrly1 the Y coordinate for the first control point
424+ * of the resulting {@code CubicCurve2D}
425+ * @param ctrlx2 the X coordinate for the second control point
426+ * of the resulting {@code CubicCurve2D}
427+ * @param ctrly2 the Y coordinate for the second control point
428+ * of the resulting {@code CubicCurve2D}
429+ * @param x2 the X coordinate for the end point
430+ * of the resulting {@code CubicCurve2D}
431+ * @param y2 the Y coordinate for the end point
432+ * of the resulting {@code CubicCurve2D}
433+ * @since 1.2
434+ */
435+ public Double(double x1, double y1,
436+ double ctrlx1, double ctrly1,
437+ double ctrlx2, double ctrly2,
438+ double x2, double y2)
439+ {
440+ setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
441+ }
442+
443+ /**
444+ * {@inheritDoc}
445+ * @since 1.2
446+ */
447+ public double getX1() {
448+ return x1;
449+ }
450+
451+ /**
452+ * {@inheritDoc}
453+ * @since 1.2
454+ */
455+ public double getY1() {
456+ return y1;
457+ }
458+
459+ /**
460+ * {@inheritDoc}
461+ * @since 1.2
462+ */
463+ public Point2D getP1() {
464+ return new Point2D.Double(x1, y1);
465+ }
466+
467+ /**
468+ * {@inheritDoc}
469+ * @since 1.2
470+ */
471+ public double getCtrlX1() {
472+ return ctrlx1;
473+ }
474+
475+ /**
476+ * {@inheritDoc}
477+ * @since 1.2
478+ */
479+ public double getCtrlY1() {
480+ return ctrly1;
481+ }
482+
483+ /**
484+ * {@inheritDoc}
485+ * @since 1.2
486+ */
487+ public Point2D getCtrlP1() {
488+ return new Point2D.Double(ctrlx1, ctrly1);
489+ }
490+
491+ /**
492+ * {@inheritDoc}
493+ * @since 1.2
494+ */
495+ public double getCtrlX2() {
496+ return ctrlx2;
497+ }
498+
499+ /**
500+ * {@inheritDoc}
501+ * @since 1.2
502+ */
503+ public double getCtrlY2() {
504+ return ctrly2;
505+ }
506+
507+ /**
508+ * {@inheritDoc}
509+ * @since 1.2
510+ */
511+ public Point2D getCtrlP2() {
512+ return new Point2D.Double(ctrlx2, ctrly2);
513+ }
514+
515+ /**
516+ * {@inheritDoc}
517+ * @since 1.2
518+ */
519+ public double getX2() {
520+ return x2;
521+ }
522+
523+ /**
524+ * {@inheritDoc}
525+ * @since 1.2
526+ */
527+ public double getY2() {
528+ return y2;
529+ }
530+
531+ /**
532+ * {@inheritDoc}
533+ * @since 1.2
534+ */
535+ public Point2D getP2() {
536+ return new Point2D.Double(x2, y2);
537+ }
538+
539+ /**
540+ * {@inheritDoc}
541+ * @since 1.2
542+ */
543+ public void setCurve(double x1, double y1,
544+ double ctrlx1, double ctrly1,
545+ double ctrlx2, double ctrly2,
546+ double x2, double y2)
547+ {
548+ this.x1 = x1;
549+ this.y1 = y1;
550+ this.ctrlx1 = ctrlx1;
551+ this.ctrly1 = ctrly1;
552+ this.ctrlx2 = ctrlx2;
553+ this.ctrly2 = ctrly2;
554+ this.x2 = x2;
555+ this.y2 = y2;
556+ }
557+
558+ /**
559+ * {@inheritDoc}
560+ * @since 1.2
561+ */
562+ public Rectangle2D getBounds2D() {
563+ double left = Math.min(Math.min(x1, x2),
564+ Math.min(ctrlx1, ctrlx2));
565+ double top = Math.min(Math.min(y1, y2),
566+ Math.min(ctrly1, ctrly2));
567+ double right = Math.max(Math.max(x1, x2),
568+ Math.max(ctrlx1, ctrlx2));
569+ double bottom = Math.max(Math.max(y1, y2),
570+ Math.max(ctrly1, ctrly2));
571+ return new Rectangle2D.Double(left, top,
572+ right - left, bottom - top);
573+ }
574+
575+ /*
576+ * JDK 1.6 serialVersionUID
577+ */
578+ private static final long serialVersionUID = -4202960122839707295L;
579+ }
580+
581+ /**
582+ * This is an abstract class that cannot be instantiated directly.
583+ * Type-specific implementation subclasses are available for
584+ * instantiation and provide a number of formats for storing
585+ * the information necessary to satisfy the various accessor
586+ * methods below.
587+ *
588+ * @see java.awt.geom.CubicCurve2D.Float
589+ * @see java.awt.geom.CubicCurve2D.Double
590+ * @since 1.2
591+ */
592+ protected CubicCurve2D() {
593+ }
594+
595+ /**
596+ * Returns the X coordinate of the start point in double precision.
597+ * @return the X coordinate of the start point of the
598+ * {@code CubicCurve2D}.
599+ * @since 1.2
600+ */
601+ public abstract double getX1();
602+
603+ /**
604+ * Returns the Y coordinate of the start point in double precision.
605+ * @return the Y coordinate of the start point of the
606+ * {@code CubicCurve2D}.
607+ * @since 1.2
608+ */
609+ public abstract double getY1();
610+
611+ /**
612+ * Returns the start point.
613+ * @return a {@code Point2D} that is the start point of
614+ * the {@code CubicCurve2D}.
615+ * @since 1.2
616+ */
617+ public abstract Point2D getP1();
618+
619+ /**
620+ * Returns the X coordinate of the first control point in double precision.
621+ * @return the X coordinate of the first control point of the
622+ * {@code CubicCurve2D}.
623+ * @since 1.2
624+ */
625+ public abstract double getCtrlX1();
626+
627+ /**
628+ * Returns the Y coordinate of the first control point in double precision.
629+ * @return the Y coordinate of the first control point of the
630+ * {@code CubicCurve2D}.
631+ * @since 1.2
632+ */
633+ public abstract double getCtrlY1();
634+
635+ /**
636+ * Returns the first control point.
637+ * @return a {@code Point2D} that is the first control point of
638+ * the {@code CubicCurve2D}.
639+ * @since 1.2
640+ */
641+ public abstract Point2D getCtrlP1();
642+
643+ /**
644+ * Returns the X coordinate of the second control point
645+ * in double precision.
646+ * @return the X coordinate of the second control point of the
647+ * {@code CubicCurve2D}.
648+ * @since 1.2
649+ */
650+ public abstract double getCtrlX2();
651+
652+ /**
653+ * Returns the Y coordinate of the second control point
654+ * in double precision.
655+ * @return the Y coordinate of the second control point of the
656+ * {@code CubicCurve2D}.
657+ * @since 1.2
658+ */
659+ public abstract double getCtrlY2();
660+
661+ /**
662+ * Returns the second control point.
663+ * @return a {@code Point2D} that is the second control point of
664+ * the {@code CubicCurve2D}.
665+ * @since 1.2
666+ */
667+ public abstract Point2D getCtrlP2();
668+
669+ /**
670+ * Returns the X coordinate of the end point in double precision.
671+ * @return the X coordinate of the end point of the
672+ * {@code CubicCurve2D}.
673+ * @since 1.2
674+ */
675+ public abstract double getX2();
676+
677+ /**
678+ * Returns the Y coordinate of the end point in double precision.
679+ * @return the Y coordinate of the end point of the
680+ * {@code CubicCurve2D}.
681+ * @since 1.2
682+ */
683+ public abstract double getY2();
684+
685+ /**
686+ * Returns the end point.
687+ * @return a {@code Point2D} that is the end point of
688+ * the {@code CubicCurve2D}.
689+ * @since 1.2
690+ */
691+ public abstract Point2D getP2();
692+
693+ /**
694+ * Sets the location of the end points and control points of this curve
695+ * to the specified double coordinates.
696+ *
697+ * @param x1 the X coordinate used to set the start point
698+ * of this {@code CubicCurve2D}
699+ * @param y1 the Y coordinate used to set the start point
700+ * of this {@code CubicCurve2D}
701+ * @param ctrlx1 the X coordinate used to set the first control point
702+ * of this {@code CubicCurve2D}
703+ * @param ctrly1 the Y coordinate used to set the first control point
704+ * of this {@code CubicCurve2D}
705+ * @param ctrlx2 the X coordinate used to set the second control point
706+ * of this {@code CubicCurve2D}
707+ * @param ctrly2 the Y coordinate used to set the second control point
708+ * of this {@code CubicCurve2D}
709+ * @param x2 the X coordinate used to set the end point
710+ * of this {@code CubicCurve2D}
711+ * @param y2 the Y coordinate used to set the end point
712+ * of this {@code CubicCurve2D}
713+ * @since 1.2
714+ */
715+ public abstract void setCurve(double x1, double y1,
716+ double ctrlx1, double ctrly1,
717+ double ctrlx2, double ctrly2,
718+ double x2, double y2);
719+
720+ /**
721+ * Sets the location of the end points and control points of this curve
722+ * to the double coordinates at the specified offset in the specified
723+ * array.
724+ * @param coords a double array containing coordinates
725+ * @param offset the index of <code>coords</code> from which to begin
726+ * setting the end points and control points of this curve
727+ * to the coordinates contained in <code>coords</code>
728+ * @since 1.2
729+ */
730+ public void setCurve(double[] coords, int offset) {
731+ setCurve(coords[offset + 0], coords[offset + 1],
732+ coords[offset + 2], coords[offset + 3],
733+ coords[offset + 4], coords[offset + 5],
734+ coords[offset + 6], coords[offset + 7]);
735+ }
736+
737+ /**
738+ * Sets the location of the end points and control points of this curve
739+ * to the specified <code>Point2D</code> coordinates.
740+ * @param p1 the first specified <code>Point2D</code> used to set the
741+ * start point of this curve
742+ * @param cp1 the second specified <code>Point2D</code> used to set the
743+ * first control point of this curve
744+ * @param cp2 the third specified <code>Point2D</code> used to set the
745+ * second control point of this curve
746+ * @param p2 the fourth specified <code>Point2D</code> used to set the
747+ * end point of this curve
748+ * @since 1.2
749+ */
750+ public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
751+ setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
752+ cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
753+ }
754+
755+ /**
756+ * Sets the location of the end points and control points of this curve
757+ * to the coordinates of the <code>Point2D</code> objects at the specified
758+ * offset in the specified array.
759+ * @param pts an array of <code>Point2D</code> objects
760+ * @param offset the index of <code>pts</code> from which to begin setting
761+ * the end points and control points of this curve to the
762+ * points contained in <code>pts</code>
763+ * @since 1.2
764+ */
765+ public void setCurve(Point2D[] pts, int offset) {
766+ setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
767+ pts[offset + 1].getX(), pts[offset + 1].getY(),
768+ pts[offset + 2].getX(), pts[offset + 2].getY(),
769+ pts[offset + 3].getX(), pts[offset + 3].getY());
770+ }
771+
772+ /**
773+ * Sets the location of the end points and control points of this curve
774+ * to the same as those in the specified <code>CubicCurve2D</code>.
775+ * @param c the specified <code>CubicCurve2D</code>
776+ * @since 1.2
777+ */
778+ public void setCurve(CubicCurve2D c) {
779+ setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
780+ c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
781+ }
782+
783+ /**
784+ * Returns the square of the flatness of the cubic curve specified
785+ * by the indicated control points. The flatness is the maximum distance
786+ * of a control point from the line connecting the end points.
787+ *
788+ * @param x1 the X coordinate that specifies the start point
789+ * of a {@code CubicCurve2D}
790+ * @param y1 the Y coordinate that specifies the start point
791+ * of a {@code CubicCurve2D}
792+ * @param ctrlx1 the X coordinate that specifies the first control point
793+ * of a {@code CubicCurve2D}
794+ * @param ctrly1 the Y coordinate that specifies the first control point
795+ * of a {@code CubicCurve2D}
796+ * @param ctrlx2 the X coordinate that specifies the second control point
797+ * of a {@code CubicCurve2D}
798+ * @param ctrly2 the Y coordinate that specifies the second control point
799+ * of a {@code CubicCurve2D}
800+ * @param x2 the X coordinate that specifies the end point
801+ * of a {@code CubicCurve2D}
802+ * @param y2 the Y coordinate that specifies the end point
803+ * of a {@code CubicCurve2D}
804+ * @return the square of the flatness of the {@code CubicCurve2D}
805+ * represented by the specified coordinates.
806+ * @since 1.2
807+ */
808+ public static double getFlatnessSq(double x1, double y1,
809+ double ctrlx1, double ctrly1,
810+ double ctrlx2, double ctrly2,
811+ double x2, double y2) {
812+ return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1),
813+ Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2));
814+
815+ }
816+
817+ /**
818+ * Returns the flatness of the cubic curve specified
819+ * by the indicated control points. The flatness is the maximum distance
820+ * of a control point from the line connecting the end points.
821+ *
822+ * @param x1 the X coordinate that specifies the start point
823+ * of a {@code CubicCurve2D}
824+ * @param y1 the Y coordinate that specifies the start point
825+ * of a {@code CubicCurve2D}
826+ * @param ctrlx1 the X coordinate that specifies the first control point
827+ * of a {@code CubicCurve2D}
828+ * @param ctrly1 the Y coordinate that specifies the first control point
829+ * of a {@code CubicCurve2D}
830+ * @param ctrlx2 the X coordinate that specifies the second control point
831+ * of a {@code CubicCurve2D}
832+ * @param ctrly2 the Y coordinate that specifies the second control point
833+ * of a {@code CubicCurve2D}
834+ * @param x2 the X coordinate that specifies the end point
835+ * of a {@code CubicCurve2D}
836+ * @param y2 the Y coordinate that specifies the end point
837+ * of a {@code CubicCurve2D}
838+ * @return the flatness of the {@code CubicCurve2D}
839+ * represented by the specified coordinates.
840+ * @since 1.2
841+ */
842+ public static double getFlatness(double x1, double y1,
843+ double ctrlx1, double ctrly1,
844+ double ctrlx2, double ctrly2,
845+ double x2, double y2) {
846+ return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1,
847+ ctrlx2, ctrly2, x2, y2));
848+ }
849+
850+ /**
851+ * Returns the square of the flatness of the cubic curve specified
852+ * by the control points stored in the indicated array at the
853+ * indicated index. The flatness is the maximum distance
854+ * of a control point from the line connecting the end points.
855+ * @param coords an array containing coordinates
856+ * @param offset the index of <code>coords</code> from which to begin
857+ * getting the end points and control points of the curve
858+ * @return the square of the flatness of the <code>CubicCurve2D</code>
859+ * specified by the coordinates in <code>coords</code> at
860+ * the specified offset.
861+ * @since 1.2
862+ */
863+ public static double getFlatnessSq(double coords[], int offset) {
864+ return getFlatnessSq(coords[offset + 0], coords[offset + 1],
865+ coords[offset + 2], coords[offset + 3],
866+ coords[offset + 4], coords[offset + 5],
867+ coords[offset + 6], coords[offset + 7]);
868+ }
869+
870+ /**
871+ * Returns the flatness of the cubic curve specified
872+ * by the control points stored in the indicated array at the
873+ * indicated index. The flatness is the maximum distance
874+ * of a control point from the line connecting the end points.
875+ * @param coords an array containing coordinates
876+ * @param offset the index of <code>coords</code> from which to begin
877+ * getting the end points and control points of the curve
878+ * @return the flatness of the <code>CubicCurve2D</code>
879+ * specified by the coordinates in <code>coords</code> at
880+ * the specified offset.
881+ * @since 1.2
882+ */
883+ public static double getFlatness(double coords[], int offset) {
884+ return getFlatness(coords[offset + 0], coords[offset + 1],
885+ coords[offset + 2], coords[offset + 3],
886+ coords[offset + 4], coords[offset + 5],
887+ coords[offset + 6], coords[offset + 7]);
888+ }
889+
890+ /**
891+ * Returns the square of the flatness of this curve. The flatness is the
892+ * maximum distance of a control point from the line connecting the
893+ * end points.
894+ * @return the square of the flatness of this curve.
895+ * @since 1.2
896+ */
897+ public double getFlatnessSq() {
898+ return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
899+ getCtrlX2(), getCtrlY2(), getX2(), getY2());
900+ }
901+
902+ /**
903+ * Returns the flatness of this curve. The flatness is the
904+ * maximum distance of a control point from the line connecting the
905+ * end points.
906+ * @return the flatness of this curve.
907+ * @since 1.2
908+ */
909+ public double getFlatness() {
910+ return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
911+ getCtrlX2(), getCtrlY2(), getX2(), getY2());
912+ }
913+
914+ /**
915+ * Subdivides this cubic curve and stores the resulting two
916+ * subdivided curves into the left and right curve parameters.
917+ * Either or both of the left and right objects may be the same
918+ * as this object or null.
919+ * @param left the cubic curve object for storing for the left or
920+ * first half of the subdivided curve
921+ * @param right the cubic curve object for storing for the right or
922+ * second half of the subdivided curve
923+ * @since 1.2
924+ */
925+ public void subdivide(CubicCurve2D left, CubicCurve2D right) {
926+ subdivide(this, left, right);
927+ }
928+
929+ /**
930+ * Subdivides the cubic curve specified by the <code>src</code> parameter
931+ * and stores the resulting two subdivided curves into the
932+ * <code>left</code> and <code>right</code> curve parameters.
933+ * Either or both of the <code>left</code> and <code>right</code> objects
934+ * may be the same as the <code>src</code> object or <code>null</code>.
935+ * @param src the cubic curve to be subdivided
936+ * @param left the cubic curve object for storing the left or
937+ * first half of the subdivided curve
938+ * @param right the cubic curve object for storing the right or
939+ * second half of the subdivided curve
940+ * @since 1.2
941+ */
942+ public static void subdivide(CubicCurve2D src,
943+ CubicCurve2D left,
944+ CubicCurve2D right) {
945+ double x1 = src.getX1();
946+ double y1 = src.getY1();
947+ double ctrlx1 = src.getCtrlX1();
948+ double ctrly1 = src.getCtrlY1();
949+ double ctrlx2 = src.getCtrlX2();
950+ double ctrly2 = src.getCtrlY2();
951+ double x2 = src.getX2();
952+ double y2 = src.getY2();
953+ double centerx = (ctrlx1 + ctrlx2) / 2.0;
954+ double centery = (ctrly1 + ctrly2) / 2.0;
955+ ctrlx1 = (x1 + ctrlx1) / 2.0;
956+ ctrly1 = (y1 + ctrly1) / 2.0;
957+ ctrlx2 = (x2 + ctrlx2) / 2.0;
958+ ctrly2 = (y2 + ctrly2) / 2.0;
959+ double ctrlx12 = (ctrlx1 + centerx) / 2.0;
960+ double ctrly12 = (ctrly1 + centery) / 2.0;
961+ double ctrlx21 = (ctrlx2 + centerx) / 2.0;
962+ double ctrly21 = (ctrly2 + centery) / 2.0;
963+ centerx = (ctrlx12 + ctrlx21) / 2.0;
964+ centery = (ctrly12 + ctrly21) / 2.0;
965+ if (left != null) {
966+ left.setCurve(x1, y1, ctrlx1, ctrly1,
967+ ctrlx12, ctrly12, centerx, centery);
968+ }
969+ if (right != null) {
970+ right.setCurve(centerx, centery, ctrlx21, ctrly21,
971+ ctrlx2, ctrly2, x2, y2);
972+ }
973+ }
974+
975+ /**
976+ * Subdivides the cubic curve specified by the coordinates
977+ * stored in the <code>src</code> array at indices <code>srcoff</code>
978+ * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
979+ * resulting two subdivided curves into the two result arrays at the
980+ * corresponding indices.
981+ * Either or both of the <code>left</code> and <code>right</code>
982+ * arrays may be <code>null</code> or a reference to the same array
983+ * as the <code>src</code> array.
984+ * Note that the last point in the first subdivided curve is the
985+ * same as the first point in the second subdivided curve. Thus,
986+ * it is possible to pass the same array for <code>left</code>
987+ * and <code>right</code> and to use offsets, such as <code>rightoff</code>
988+ * equals (<code>leftoff</code> + 6), in order
989+ * to avoid allocating extra storage for this common point.
990+ * @param src the array holding the coordinates for the source curve
991+ * @param srcoff the offset into the array of the beginning of the
992+ * the 6 source coordinates
993+ * @param left the array for storing the coordinates for the first
994+ * half of the subdivided curve
995+ * @param leftoff the offset into the array of the beginning of the
996+ * the 6 left coordinates
997+ * @param right the array for storing the coordinates for the second
998+ * half of the subdivided curve
999+ * @param rightoff the offset into the array of the beginning of the
1000+ * the 6 right coordinates
1001+ * @since 1.2
1002+ */
1003+ public static void subdivide(double src[], int srcoff,
1004+ double left[], int leftoff,
1005+ double right[], int rightoff) {
1006+ double x1 = src[srcoff + 0];
1007+ double y1 = src[srcoff + 1];
1008+ double ctrlx1 = src[srcoff + 2];
1009+ double ctrly1 = src[srcoff + 3];
1010+ double ctrlx2 = src[srcoff + 4];
1011+ double ctrly2 = src[srcoff + 5];
1012+ double x2 = src[srcoff + 6];
1013+ double y2 = src[srcoff + 7];
1014+ if (left != null) {
1015+ left[leftoff + 0] = x1;
1016+ left[leftoff + 1] = y1;
1017+ }
1018+ if (right != null) {
1019+ right[rightoff + 6] = x2;
1020+ right[rightoff + 7] = y2;
1021+ }
1022+ x1 = (x1 + ctrlx1) / 2.0;
1023+ y1 = (y1 + ctrly1) / 2.0;
1024+ x2 = (x2 + ctrlx2) / 2.0;
1025+ y2 = (y2 + ctrly2) / 2.0;
1026+ double centerx = (ctrlx1 + ctrlx2) / 2.0;
1027+ double centery = (ctrly1 + ctrly2) / 2.0;
1028+ ctrlx1 = (x1 + centerx) / 2.0;
1029+ ctrly1 = (y1 + centery) / 2.0;
1030+ ctrlx2 = (x2 + centerx) / 2.0;
1031+ ctrly2 = (y2 + centery) / 2.0;
1032+ centerx = (ctrlx1 + ctrlx2) / 2.0;
1033+ centery = (ctrly1 + ctrly2) / 2.0;
1034+ if (left != null) {
1035+ left[leftoff + 2] = x1;
1036+ left[leftoff + 3] = y1;
1037+ left[leftoff + 4] = ctrlx1;
1038+ left[leftoff + 5] = ctrly1;
1039+ left[leftoff + 6] = centerx;
1040+ left[leftoff + 7] = centery;
1041+ }
1042+ if (right != null) {
1043+ right[rightoff + 0] = centerx;
1044+ right[rightoff + 1] = centery;
1045+ right[rightoff + 2] = ctrlx2;
1046+ right[rightoff + 3] = ctrly2;
1047+ right[rightoff + 4] = x2;
1048+ right[rightoff + 5] = y2;
1049+ }
1050+ }
1051+
1052+ /**
1053+ * Solves the cubic whose coefficients are in the <code>eqn</code>
1054+ * array and places the non-complex roots back into the same array,
1055+ * returning the number of roots. The solved cubic is represented
1056+ * by the equation:
1057+ * <pre>
1058+ * eqn = {c, b, a, d}
1059+ * dx^3 + ax^2 + bx + c = 0
1060+ * </pre>
1061+ * A return value of -1 is used to distinguish a constant equation
1062+ * that might be always 0 or never 0 from an equation that has no
1063+ * zeroes.
1064+ * @param eqn an array containing coefficients for a cubic
1065+ * @return the number of roots, or -1 if the equation is a constant.
1066+ * @since 1.2
1067+ */
1068+ public static int solveCubic(double eqn[]) {
1069+ return solveCubic(eqn, eqn);
1070+ }
1071+
1072+ /**
1073+ * Solve the cubic whose coefficients are in the <code>eqn</code>
1074+ * array and place the non-complex roots into the <code>res</code>
1075+ * array, returning the number of roots.
1076+ * The cubic solved is represented by the equation:
1077+ * eqn = {c, b, a, d}
1078+ * dx^3 + ax^2 + bx + c = 0
1079+ * A return value of -1 is used to distinguish a constant equation,
1080+ * which may be always 0 or never 0, from an equation which has no
1081+ * zeroes.
1082+ * @param eqn the specified array of coefficients to use to solve
1083+ * the cubic equation
1084+ * @param res the array that contains the non-complex roots
1085+ * resulting from the solution of the cubic equation
1086+ * @return the number of roots, or -1 if the equation is a constant
1087+ * @since 1.3
1088+ */
1089+ public static int solveCubic(double eqn[], double res[]) {
1090+ // From Graphics Gems:
1091+ // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
1092+ final double d = eqn[3];
1093+ if (d == 0) {
1094+ return QuadCurve2D.solveQuadratic(eqn, res);
1095+ }
1096+
1097+ /* normal form: x^3 + Ax^2 + Bx + C = 0 */
1098+ final double A = eqn[2] / d;
1099+ final double B = eqn[1] / d;
1100+ final double C = eqn[0] / d;
1101+
1102+
1103+ // substitute x = y - A/3 to eliminate quadratic term:
1104+ // x^3 +Px + Q = 0
1105+ //
1106+ // Since we actually need P/3 and Q/2 for all of the
1107+ // calculations that follow, we will calculate
1108+ // p = P/3
1109+ // q = Q/2
1110+ // instead and use those values for simplicity of the code.
1111+ double sq_A = A * A;
1112+ double p = 1.0/3 * (-1.0/3 * sq_A + B);
1113+ double q = 1.0/2 * (2.0/27 * A * sq_A - 1.0/3 * A * B + C);
1114+
1115+ /* use Cardano's formula */
1116+
1117+ double cb_p = p * p * p;
1118+ double D = q * q + cb_p;
1119+
1120+ final double sub = 1.0/3 * A;
1121+
1122+ int num;
1123+ if (D < 0) { /* Casus irreducibilis: three real solutions */
1124+ // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
1125+ double phi = 1.0/3 * Math.acos(-q / Math.sqrt(-cb_p));
1126+ double t = 2 * Math.sqrt(-p);
1127+
1128+ if (res == eqn) {
1129+ eqn = Arrays.copyOf(eqn, 4);
1130+ }
1131+
1132+ res[ 0 ] = ( t * Math.cos(phi));
1133+ res[ 1 ] = (-t * Math.cos(phi + Math.PI / 3));
1134+ res[ 2 ] = (-t * Math.cos(phi - Math.PI / 3));
1135+ num = 3;
1136+
1137+ for (int i = 0; i < num; ++i) {
1138+ res[ i ] -= sub;
1139+ }
1140+
1141+ } else {
1142+ // Please see the comment in fixRoots marked 'XXX' before changing
1143+ // any of the code in this case.
1144+ double sqrt_D = Math.sqrt(D);
1145+ double u = Math.cbrt(sqrt_D - q);
1146+ double v = - Math.cbrt(sqrt_D + q);
1147+ double uv = u+v;
1148+
1149+ num = 1;
1150+
1151+ double err = 1200000000*ulp(abs(uv) + abs(sub));
1152+ if (iszero(D, err) || within(u, v, err)) {
1153+ if (res == eqn) {
1154+ eqn = Arrays.copyOf(eqn, 4);
1155+ }
1156+ res[1] = -(uv / 2) - sub;
1157+ num = 2;
1158+ }
1159+ // this must be done after the potential Arrays.copyOf
1160+ res[ 0 ] = uv - sub;
1161+ }
1162+
1163+ if (num > 1) { // num == 3 || num == 2
1164+ num = fixRoots(eqn, res, num);
1165+ }
1166+ if (num > 2 && (res[2] == res[1] || res[2] == res[0])) {
1167+ num--;
1168+ }
1169+ if (num > 1 && res[1] == res[0]) {
1170+ res[1] = res[--num]; // Copies res[2] to res[1] if needed
1171+ }
1172+ return num;
1173+ }
1174+
1175+ // preconditions: eqn != res && eqn[3] != 0 && num > 1
1176+ // This method tries to improve the accuracy of the roots of eqn (which
1177+ // should be in res). It also might eliminate roots in res if it decideds
1178+ // that they're not real roots. It will not check for roots that the
1179+ // computation of res might have missed, so this method should only be
1180+ // used when the roots in res have been computed using an algorithm
1181+ // that never underestimates the number of roots (such as solveCubic above)
1182+ private static int fixRoots(double[] eqn, double[] res, int num) {
1183+ double[] intervals = {eqn[1], 2*eqn[2], 3*eqn[3]};
1184+ int critCount = QuadCurve2D.solveQuadratic(intervals, intervals);
1185+ if (critCount == 2 && intervals[0] == intervals[1]) {
1186+ critCount--;
1187+ }
1188+ if (critCount == 2 && intervals[0] > intervals[1]) {
1189+ double tmp = intervals[0];
1190+ intervals[0] = intervals[1];
1191+ intervals[1] = tmp;
1192+ }
1193+
1194+ // below we use critCount to possibly filter out roots that shouldn't
1195+ // have been computed. We require that eqn[3] != 0, so eqn is a proper
1196+ // cubic, which means that its limits at -/+inf are -/+inf or +/-inf.
1197+ // Therefore, if critCount==2, the curve is shaped like a sideways S,
1198+ // and it could have 1-3 roots. If critCount==0 it is monotonic, and
1199+ // if critCount==1 it is monotonic with a single point where it is
1200+ // flat. In the last 2 cases there can only be 1 root. So in cases
1201+ // where num > 1 but critCount < 2, we eliminate all roots in res
1202+ // except one.
1203+
1204+ if (num == 3) {
1205+ double xe = getRootUpperBound(eqn);
1206+ double x0 = -xe;
1207+
1208+ Arrays.sort(res, 0, num);
1209+ if (critCount == 2) {
1210+ // this just tries to improve the accuracy of the computed
1211+ // roots using Newton's method.
1212+ res[0] = refineRootWithHint(eqn, x0, intervals[0], res[0]);
1213+ res[1] = refineRootWithHint(eqn, intervals[0], intervals[1], res[1]);
1214+ res[2] = refineRootWithHint(eqn, intervals[1], xe, res[2]);
1215+ return 3;
1216+ } else if (critCount == 1) {
1217+ // we only need fx0 and fxe for the sign of the polynomial
1218+ // at -inf and +inf respectively, so we don't need to do
1219+ // fx0 = solveEqn(eqn, 3, x0); fxe = solveEqn(eqn, 3, xe)
1220+ double fxe = eqn[3];
1221+ double fx0 = -fxe;
1222+
1223+ double x1 = intervals[0];
1224+ double fx1 = solveEqn(eqn, 3, x1);
1225+
1226+ // if critCount == 1 or critCount == 0, but num == 3 then
1227+ // something has gone wrong. This branch and the one below
1228+ // would ideally never execute, but if they do we can't know
1229+ // which of the computed roots is closest to the real root;
1230+ // therefore, we can't use refineRootWithHint. But even if
1231+ // we did know, being here most likely means that the
1232+ // curve is very flat close to two of the computed roots
1233+ // (or maybe even all three). This might make Newton's method
1234+ // fail altogether, which would be a pain to detect and fix.
1235+ // This is why we use a very stable bisection method.
1236+ if (oppositeSigns(fx0, fx1)) {
1237+ res[0] = bisectRootWithHint(eqn, x0, x1, res[0]);
1238+ } else if (oppositeSigns(fx1, fxe)) {
1239+ res[0] = bisectRootWithHint(eqn, x1, xe, res[2]);
1240+ } else /* fx1 must be 0 */ {
1241+ res[0] = x1;
1242+ }
1243+ // return 1
1244+ } else if (critCount == 0) {
1245+ res[0] = bisectRootWithHint(eqn, x0, xe, res[1]);
1246+ // return 1
1247+ }
1248+ } else if (num == 2 && critCount == 2) {
1249+ // XXX: here we assume that res[0] has better accuracy than res[1].
1250+ // This is true because this method is only used from solveCubic
1251+ // which puts in res[0] the root that it would compute anyway even
1252+ // if num==1. If this method is ever used from any other method, or
1253+ // if the solveCubic implementation changes, this assumption should
1254+ // be reevaluated, and the choice of goodRoot might have to become
1255+ // goodRoot = (abs(eqn'(res[0])) > abs(eqn'(res[1]))) ? res[0] : res[1]
1256+ // where eqn' is the derivative of eqn.
1257+ double goodRoot = res[0];
1258+ double badRoot = res[1];
1259+ double x1 = intervals[0];
1260+ double x2 = intervals[1];
1261+ // If a cubic curve really has 2 roots, one of those roots must be
1262+ // at a critical point. That can't be goodRoot, so we compute x to
1263+ // be the farthest critical point from goodRoot. If there are two
1264+ // roots, x must be the second one, so we evaluate eqn at x, and if
1265+ // it is zero (or close enough) we put x in res[1] (or badRoot, if
1266+ // |solveEqn(eqn, 3, badRoot)| < |solveEqn(eqn, 3, x)| but this
1267+ // shouldn't happen often).
1268+ double x = abs(x1 - goodRoot) > abs(x2 - goodRoot) ? x1 : x2;
1269+ double fx = solveEqn(eqn, 3, x);
1270+
1271+ if (iszero(fx, 10000000*ulp(x))) {
1272+ double badRootVal = solveEqn(eqn, 3, badRoot);
1273+ res[1] = abs(badRootVal) < abs(fx) ? badRoot : x;
1274+ return 2;
1275+ }
1276+ } // else there can only be one root - goodRoot, and it is already in res[0]
1277+
1278+ return 1;
1279+ }
1280+
1281+ // use newton's method.
1282+ private static double refineRootWithHint(double[] eqn, double min, double max, double t) {
1283+ if (!inInterval(t, min, max)) {
1284+ return t;
1285+ }
1286+ double[] deriv = {eqn[1], 2*eqn[2], 3*eqn[3]};
1287+ double origt = t;
1288+ for (int i = 0; i < 3; i++) {
1289+ double slope = solveEqn(deriv, 2, t);
1290+ double y = solveEqn(eqn, 3, t);
1291+ double delta = - (y / slope);
1292+ double newt = t + delta;
1293+
1294+ if (slope == 0 || y == 0 || t == newt) {
1295+ break;
1296+ }
1297+
1298+ t = newt;
1299+ }
1300+ if (within(t, origt, 1000*ulp(origt)) && inInterval(t, min, max)) {
1301+ return t;
1302+ }
1303+ return origt;
1304+ }
1305+
1306+ private static double bisectRootWithHint(double[] eqn, double x0, double xe, double hint) {
1307+ double delta1 = Math.min(abs(hint - x0) / 64, 0.0625);
1308+ double delta2 = Math.min(abs(hint - xe) / 64, 0.0625);
1309+ double x02 = hint - delta1;
1310+ double xe2 = hint + delta2;
1311+ double fx02 = solveEqn(eqn, 3, x02);
1312+ double fxe2 = solveEqn(eqn, 3, xe2);
1313+ while (oppositeSigns(fx02, fxe2)) {
1314+ if (x02 >= xe2) {
1315+ return x02;
1316+ }
1317+ x0 = x02;
1318+ xe = xe2;
1319+ delta1 /= 64;
1320+ delta2 /= 64;
1321+ x02 = hint - delta1;
1322+ xe2 = hint + delta2;
1323+ fx02 = solveEqn(eqn, 3, x02);
1324+ fxe2 = solveEqn(eqn, 3, xe2);
1325+ }
1326+ if (fx02 == 0) {
1327+ return x02;
1328+ }
1329+ if (fxe2 == 0) {
1330+ return xe2;
1331+ }
1332+
1333+ return bisectRoot(eqn, x0, xe);
1334+ }
1335+
1336+ private static double bisectRoot(double[] eqn, double x0, double xe) {
1337+ double fx0 = solveEqn(eqn, 3, x0);
1338+ double m = x0 + (xe - x0) / 2;
1339+ while (m != x0 && m != xe) {
1340+ double fm = solveEqn(eqn, 3, m);
1341+ if (fm == 0) {
1342+ return m;
1343+ }
1344+ if (oppositeSigns(fx0, fm)) {
1345+ xe = m;
1346+ } else {
1347+ fx0 = fm;
1348+ x0 = m;
1349+ }
1350+ m = x0 + (xe-x0)/2;
1351+ }
1352+ return m;
1353+ }
1354+
1355+ private static boolean inInterval(double t, double min, double max) {
1356+ return min <= t && t <= max;
1357+ }
1358+
1359+ private static boolean within(double x, double y, double err) {
1360+ double d = y - x;
1361+ return (d <= err && d >= -err);
1362+ }
1363+
1364+ private static boolean iszero(double x, double err) {
1365+ return within(x, 0, err);
1366+ }
1367+
1368+ private static boolean oppositeSigns(double x1, double x2) {
1369+ return (x1 < 0 && x2 > 0) || (x1 > 0 && x2 < 0);
1370+ }
1371+
1372+ private static double solveEqn(double eqn[], int order, double t) {
1373+ double v = eqn[order];
1374+ while (--order >= 0) {
1375+ v = v * t + eqn[order];
1376+ }
1377+ return v;
1378+ }
1379+
1380+ /*
1381+ * Computes M+1 where M is an upper bound for all the roots in of eqn.
1382+ * See: http://en.wikipedia.org/wiki/Sturm%27s_theorem#Applications.
1383+ * The above link doesn't contain a proof, but I [dlila] proved it myself
1384+ * so the result is reliable. The proof isn't difficult, but it's a bit
1385+ * long to include here.
1386+ * Precondition: eqn must represent a cubic polynomial
1387+ */
1388+ private static double getRootUpperBound(double[] eqn) {
1389+ double d = eqn[3];
1390+ double a = eqn[2];
1391+ double b = eqn[1];
1392+ double c = eqn[0];
1393+
1394+ double M = 1 + max(max(abs(a), abs(b)), abs(c)) / abs(d);
1395+ M += ulp(M) + 1;
1396+ return M;
1397+ }
1398+
1399+
1400+ /**
1401+ * {@inheritDoc}
1402+ * @since 1.2
1403+ */
1404+ public boolean contains(double x, double y) {
1405+ if (!(x * 0.0 + y * 0.0 == 0.0)) {
1406+ /* Either x or y was infinite or NaN.
1407+ * A NaN always produces a negative response to any test
1408+ * and Infinity values cannot be "inside" any path so
1409+ * they should return false as well.
1410+ */
1411+ return false;
1412+ }
1413+ // We count the "Y" crossings to determine if the point is
1414+ // inside the curve bounded by its closing line.
1415+ double x1 = getX1();
1416+ double y1 = getY1();
1417+ double x2 = getX2();
1418+ double y2 = getY2();
1419+ int crossings =
1420+ (Curve.pointCrossingsForLine(x, y, x1, y1, x2, y2) +
1421+ Curve.pointCrossingsForCubic(x, y,
1422+ x1, y1,
1423+ getCtrlX1(), getCtrlY1(),
1424+ getCtrlX2(), getCtrlY2(),
1425+ x2, y2, 0));
1426+ return ((crossings & 1) == 1);
1427+ }
1428+
1429+ /**
1430+ * {@inheritDoc}
1431+ * @since 1.2
1432+ */
1433+ public boolean contains(Point2D p) {
1434+ return contains(p.getX(), p.getY());
1435+ }
1436+
1437+ /**
1438+ * {@inheritDoc}
1439+ * @since 1.2
1440+ */
1441+ public boolean intersects(double x, double y, double w, double h) {
1442+ // Trivially reject non-existant rectangles
1443+ if (w <= 0 || h <= 0) {
1444+ return false;
1445+ }
1446+
1447+ int numCrossings = rectCrossings(x, y, w, h);
1448+ // the intended return value is
1449+ // numCrossings != 0 || numCrossings == Curve.RECT_INTERSECTS
1450+ // but if (numCrossings != 0) numCrossings == INTERSECTS won't matter
1451+ // and if !(numCrossings != 0) then numCrossings == 0, so
1452+ // numCrossings != RECT_INTERSECT
1453+ return numCrossings != 0;
1454+ }
1455+
1456+ /**
1457+ * {@inheritDoc}
1458+ * @since 1.2
1459+ */
1460+ public boolean intersects(Rectangle2D r) {
1461+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1462+ }
1463+
1464+ /**
1465+ * {@inheritDoc}
1466+ * @since 1.2
1467+ */
1468+ public boolean contains(double x, double y, double w, double h) {
1469+ if (w <= 0 || h <= 0) {
1470+ return false;
1471+ }
1472+
1473+ int numCrossings = rectCrossings(x, y, w, h);
1474+ return !(numCrossings == 0 || numCrossings == Curve.RECT_INTERSECTS);
1475+ }
1476+
1477+ private int rectCrossings(double x, double y, double w, double h) {
1478+ int crossings = 0;
1479+ if (!(getX1() == getX2() && getY1() == getY2())) {
1480+ crossings = Curve.rectCrossingsForLine(crossings,
1481+ x, y,
1482+ x+w, y+h,
1483+ getX1(), getY1(),
1484+ getX2(), getY2());
1485+ if (crossings == Curve.RECT_INTERSECTS) {
1486+ return crossings;
1487+ }
1488+ }
1489+ // we call this with the curve's direction reversed, because we wanted
1490+ // to call rectCrossingsForLine first, because it's cheaper.
1491+ return Curve.rectCrossingsForCubic(crossings,
1492+ x, y,
1493+ x+w, y+h,
1494+ getX2(), getY2(),
1495+ getCtrlX2(), getCtrlY2(),
1496+ getCtrlX1(), getCtrlY1(),
1497+ getX1(), getY1(), 0);
1498+ }
1499+
1500+ /**
1501+ * {@inheritDoc}
1502+ * @since 1.2
1503+ */
1504+ public boolean contains(Rectangle2D r) {
1505+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1506+ }
1507+
1508+ /**
1509+ * {@inheritDoc}
1510+ * @since 1.2
1511+ */
1512+ public Rectangle getBounds() {
1513+ return getBounds2D().getBounds();
1514+ }
1515+
1516+ /**
1517+ * Returns an iteration object that defines the boundary of the
1518+ * shape.
1519+ * The iterator for this class is not multi-threaded safe,
1520+ * which means that this <code>CubicCurve2D</code> class does not
1521+ * guarantee that modifications to the geometry of this
1522+ * <code>CubicCurve2D</code> object do not affect any iterations of
1523+ * that geometry that are already in process.
1524+ * @param at an optional <code>AffineTransform</code> to be applied to the
1525+ * coordinates as they are returned in the iteration, or <code>null</code>
1526+ * if untransformed coordinates are desired
1527+ * @return the <code>PathIterator</code> object that returns the
1528+ * geometry of the outline of this <code>CubicCurve2D</code>, one
1529+ * segment at a time.
1530+ * @since 1.2
1531+ */
1532+ public PathIterator getPathIterator(AffineTransform at) {
1533+ return new CubicIterator(this, at);
1534+ }
1535+
1536+ /**
1537+ * Return an iteration object that defines the boundary of the
1538+ * flattened shape.
1539+ * The iterator for this class is not multi-threaded safe,
1540+ * which means that this <code>CubicCurve2D</code> class does not
1541+ * guarantee that modifications to the geometry of this
1542+ * <code>CubicCurve2D</code> object do not affect any iterations of
1543+ * that geometry that are already in process.
1544+ * @param at an optional <code>AffineTransform</code> to be applied to the
1545+ * coordinates as they are returned in the iteration, or <code>null</code>
1546+ * if untransformed coordinates are desired
1547+ * @param flatness the maximum amount that the control points
1548+ * for a given curve can vary from colinear before a subdivided
1549+ * curve is replaced by a straight line connecting the end points
1550+ * @return the <code>PathIterator</code> object that returns the
1551+ * geometry of the outline of this <code>CubicCurve2D</code>,
1552+ * one segment at a time.
1553+ * @since 1.2
1554+ */
1555+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
1556+ return new FlatteningPathIterator(getPathIterator(at), flatness);
1557+ }
1558+
1559+ /**
1560+ * Creates a new object of the same class as this object.
1561+ *
1562+ * @return a clone of this instance.
1563+ * @exception OutOfMemoryError if there is not enough memory.
1564+ * @see java.lang.Cloneable
1565+ * @since 1.2
1566+ */
1567+ public Object clone() {
1568+ try {
1569+ return super.clone();
1570+ } catch (CloneNotSupportedException e) {
1571+ // this shouldn't happen, since we are Cloneable
1572+ throw new InternalError();
1573+ }
1574+ }
1575+}
java/pkg/java/awt/geom/CubicIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/CubicIterator.java+156−0
@@ -0,0 +1,156 @@
1+/*
2+ * Copyright (c) 1997, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of a cubic curve
32+ * segment through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class CubicIterator implements PathIterator {
37+ CubicCurve2D cubic;
38+ AffineTransform affine;
39+ int index;
40+
41+ CubicIterator(CubicCurve2D q, AffineTransform at) {
42+ this.cubic = q;
43+ this.affine = at;
44+ }
45+
46+ /**
47+ * Return the winding rule for determining the insideness of the
48+ * path.
49+ * @see #WIND_EVEN_ODD
50+ * @see #WIND_NON_ZERO
51+ */
52+ public int getWindingRule() {
53+ return WIND_NON_ZERO;
54+ }
55+
56+ /**
57+ * Tests if there are more points to read.
58+ * @return true if there are more points to read
59+ */
60+ public boolean isDone() {
61+ return (index > 1);
62+ }
63+
64+ /**
65+ * Moves the iterator to the next segment of the path forwards
66+ * along the primary direction of traversal as long as there are
67+ * more points in that direction.
68+ */
69+ public void next() {
70+ index++;
71+ }
72+
73+ /**
74+ * Returns the coordinates and type of the current path segment in
75+ * the iteration.
76+ * The return value is the path segment type:
77+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
78+ * A float array of length 6 must be passed in and may be used to
79+ * store the coordinates of the point(s).
80+ * Each point is stored as a pair of float x,y coordinates.
81+ * SEG_MOVETO and SEG_LINETO types will return one point,
82+ * SEG_QUADTO will return two points,
83+ * SEG_CUBICTO will return 3 points
84+ * and SEG_CLOSE will not return any points.
85+ * @see #SEG_MOVETO
86+ * @see #SEG_LINETO
87+ * @see #SEG_QUADTO
88+ * @see #SEG_CUBICTO
89+ * @see #SEG_CLOSE
90+ */
91+ public int currentSegment(float[] coords) {
92+ if (isDone()) {
93+ throw new NoSuchElementException("cubic iterator iterator out of bounds");
94+ }
95+ int type;
96+ if (index == 0) {
97+ coords[0] = (float) cubic.getX1();
98+ coords[1] = (float) cubic.getY1();
99+ type = SEG_MOVETO;
100+ } else {
101+ coords[0] = (float) cubic.getCtrlX1();
102+ coords[1] = (float) cubic.getCtrlY1();
103+ coords[2] = (float) cubic.getCtrlX2();
104+ coords[3] = (float) cubic.getCtrlY2();
105+ coords[4] = (float) cubic.getX2();
106+ coords[5] = (float) cubic.getY2();
107+ type = SEG_CUBICTO;
108+ }
109+ if (affine != null) {
110+ affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 3);
111+ }
112+ return type;
113+ }
114+
115+ /**
116+ * Returns the coordinates and type of the current path segment in
117+ * the iteration.
118+ * The return value is the path segment type:
119+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
120+ * A double array of length 6 must be passed in and may be used to
121+ * store the coordinates of the point(s).
122+ * Each point is stored as a pair of double x,y coordinates.
123+ * SEG_MOVETO and SEG_LINETO types will return one point,
124+ * SEG_QUADTO will return two points,
125+ * SEG_CUBICTO will return 3 points
126+ * and SEG_CLOSE will not return any points.
127+ * @see #SEG_MOVETO
128+ * @see #SEG_LINETO
129+ * @see #SEG_QUADTO
130+ * @see #SEG_CUBICTO
131+ * @see #SEG_CLOSE
132+ */
133+ public int currentSegment(double[] coords) {
134+ if (isDone()) {
135+ throw new NoSuchElementException("cubic iterator iterator out of bounds");
136+ }
137+ int type;
138+ if (index == 0) {
139+ coords[0] = cubic.getX1();
140+ coords[1] = cubic.getY1();
141+ type = SEG_MOVETO;
142+ } else {
143+ coords[0] = cubic.getCtrlX1();
144+ coords[1] = cubic.getCtrlY1();
145+ coords[2] = cubic.getCtrlX2();
146+ coords[3] = cubic.getCtrlY2();
147+ coords[4] = cubic.getX2();
148+ coords[5] = cubic.getY2();
149+ type = SEG_CUBICTO;
150+ }
151+ if (affine != null) {
152+ affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 3);
153+ }
154+ return type;
155+ }
156+}
java/pkg/java/awt/geom/Dimension2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Dimension2D.java+114−0
@@ -0,0 +1,114 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+/**
29+ * The <code>Dimension2D</code> class is to encapsulate a width
30+ * and a height dimension.
31+ * <p>
32+ * This class is only the abstract superclass for all objects that
33+ * store a 2D dimension.
34+ * The actual storage representation of the sizes is left to
35+ * the subclass.
36+ *
37+ * @author Jim Graham
38+ * @since 1.2
39+ */
40+public abstract class Dimension2D implements Cloneable {
41+
42+ /**
43+ * This is an abstract class that cannot be instantiated directly.
44+ * Type-specific implementation subclasses are available for
45+ * instantiation and provide a number of formats for storing
46+ * the information necessary to satisfy the various accessor
47+ * methods below.
48+ *
49+ * @see java.awt.Dimension
50+ * @since 1.2
51+ */
52+ protected Dimension2D() {
53+ }
54+
55+ /**
56+ * Returns the width of this <code>Dimension</code> in double
57+ * precision.
58+ * @return the width of this <code>Dimension</code>.
59+ * @since 1.2
60+ */
61+ public abstract double getWidth();
62+
63+ /**
64+ * Returns the height of this <code>Dimension</code> in double
65+ * precision.
66+ * @return the height of this <code>Dimension</code>.
67+ * @since 1.2
68+ */
69+ public abstract double getHeight();
70+
71+ /**
72+ * Sets the size of this <code>Dimension</code> object to the
73+ * specified width and height.
74+ * This method is included for completeness, to parallel the
75+ * {@link java.awt.Component#getSize getSize} method of
76+ * {@link java.awt.Component}.
77+ * @param width the new width for the <code>Dimension</code>
78+ * object
79+ * @param height the new height for the <code>Dimension</code>
80+ * object
81+ * @since 1.2
82+ */
83+ public abstract void setSize(double width, double height);
84+
85+ /**
86+ * Sets the size of this <code>Dimension2D</code> object to
87+ * match the specified size.
88+ * This method is included for completeness, to parallel the
89+ * <code>getSize</code> method of <code>Component</code>.
90+ * @param d the new size for the <code>Dimension2D</code>
91+ * object
92+ * @since 1.2
93+ */
94+ public void setSize(Dimension2D d) {
95+ setSize(d.getWidth(), d.getHeight());
96+ }
97+
98+ /**
99+ * Creates a new object of the same class as this object.
100+ *
101+ * @return a clone of this instance.
102+ * @exception OutOfMemoryError if there is not enough memory.
103+ * @see java.lang.Cloneable
104+ * @since 1.2
105+ */
106+ public Object clone() {
107+ try {
108+ return super.clone();
109+ } catch (CloneNotSupportedException e) {
110+ // this shouldn't happen, since we are Cloneable
111+ throw new InternalError();
112+ }
113+ }
114+}
java/pkg/java/awt/geom/Ellipse2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Ellipse2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Ellipse2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Ellipse2D.java+464−0
@@ -0,0 +1,464 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.io.Serializable;
29+
30+/**
31+ * The <code>Ellipse2D</code> class describes an ellipse that is defined
32+ * by a framing rectangle.
33+ * <p>
34+ * This class is only the abstract superclass for all objects which
35+ * store a 2D ellipse.
36+ * The actual storage representation of the coordinates is left to
37+ * the subclass.
38+ *
39+ * @author Jim Graham
40+ * @since 1.2
41+ */
42+public abstract class Ellipse2D extends RectangularShape {
43+
44+ /**
45+ * The <code>Float</code> class defines an ellipse specified
46+ * in <code>float</code> precision.
47+ * @since 1.2
48+ */
49+ public static class Float extends Ellipse2D implements Serializable {
50+ /**
51+ * The X coordinate of the upper-left corner of the
52+ * framing rectangle of this {@code Ellipse2D}.
53+ * @since 1.2
54+ * @serial
55+ */
56+ public float x;
57+
58+ /**
59+ * The Y coordinate of the upper-left corner of the
60+ * framing rectangle of this {@code Ellipse2D}.
61+ * @since 1.2
62+ * @serial
63+ */
64+ public float y;
65+
66+ /**
67+ * The overall width of this <code>Ellipse2D</code>.
68+ * @since 1.2
69+ * @serial
70+ */
71+ public float width;
72+
73+ /**
74+ * The overall height of this <code>Ellipse2D</code>.
75+ * @since 1.2
76+ * @serial
77+ */
78+ public float height;
79+
80+ /**
81+ * Constructs a new <code>Ellipse2D</code>, initialized to
82+ * location (0,&nbsp;0) and size (0,&nbsp;0).
83+ * @since 1.2
84+ */
85+ public Float() {
86+ }
87+
88+ /**
89+ * Constructs and initializes an <code>Ellipse2D</code> from the
90+ * specified coordinates.
91+ *
92+ * @param x the X coordinate of the upper-left corner
93+ * of the framing rectangle
94+ * @param y the Y coordinate of the upper-left corner
95+ * of the framing rectangle
96+ * @param w the width of the framing rectangle
97+ * @param h the height of the framing rectangle
98+ * @since 1.2
99+ */
100+ public Float(float x, float y, float w, float h) {
101+ setFrame(x, y, w, h);
102+ }
103+
104+ /**
105+ * {@inheritDoc}
106+ * @since 1.2
107+ */
108+ public double getX() {
109+ return (double) x;
110+ }
111+
112+ /**
113+ * {@inheritDoc}
114+ * @since 1.2
115+ */
116+ public double getY() {
117+ return (double) y;
118+ }
119+
120+ /**
121+ * {@inheritDoc}
122+ * @since 1.2
123+ */
124+ public double getWidth() {
125+ return (double) width;
126+ }
127+
128+ /**
129+ * {@inheritDoc}
130+ * @since 1.2
131+ */
132+ public double getHeight() {
133+ return (double) height;
134+ }
135+
136+ /**
137+ * {@inheritDoc}
138+ * @since 1.2
139+ */
140+ public boolean isEmpty() {
141+ return (width <= 0.0 || height <= 0.0);
142+ }
143+
144+ /**
145+ * Sets the location and size of the framing rectangle of this
146+ * <code>Shape</code> to the specified rectangular values.
147+ *
148+ * @param x the X coordinate of the upper-left corner of the
149+ * specified rectangular shape
150+ * @param y the Y coordinate of the upper-left corner of the
151+ * specified rectangular shape
152+ * @param w the width of the specified rectangular shape
153+ * @param h the height of the specified rectangular shape
154+ * @since 1.2
155+ */
156+ public void setFrame(float x, float y, float w, float h) {
157+ this.x = x;
158+ this.y = y;
159+ this.width = w;
160+ this.height = h;
161+ }
162+
163+ /**
164+ * {@inheritDoc}
165+ * @since 1.2
166+ */
167+ public void setFrame(double x, double y, double w, double h) {
168+ this.x = (float) x;
169+ this.y = (float) y;
170+ this.width = (float) w;
171+ this.height = (float) h;
172+ }
173+
174+ /**
175+ * {@inheritDoc}
176+ * @since 1.2
177+ */
178+ public Rectangle2D getBounds2D() {
179+ return new Rectangle2D.Float(x, y, width, height);
180+ }
181+
182+ /*
183+ * JDK 1.6 serialVersionUID
184+ */
185+ private static final long serialVersionUID = -6633761252372475977L;
186+ }
187+
188+ /**
189+ * The <code>Double</code> class defines an ellipse specified
190+ * in <code>double</code> precision.
191+ * @since 1.2
192+ */
193+ public static class Double extends Ellipse2D implements Serializable {
194+ /**
195+ * The X coordinate of the upper-left corner of the
196+ * framing rectangle of this {@code Ellipse2D}.
197+ * @since 1.2
198+ * @serial
199+ */
200+ public double x;
201+
202+ /**
203+ * The Y coordinate of the upper-left corner of the
204+ * framing rectangle of this {@code Ellipse2D}.
205+ * @since 1.2
206+ * @serial
207+ */
208+ public double y;
209+
210+ /**
211+ * The overall width of this <code>Ellipse2D</code>.
212+ * @since 1.2
213+ * @serial
214+ */
215+ public double width;
216+
217+ /**
218+ * The overall height of the <code>Ellipse2D</code>.
219+ * @since 1.2
220+ * @serial
221+ */
222+ public double height;
223+
224+ /**
225+ * Constructs a new <code>Ellipse2D</code>, initialized to
226+ * location (0,&nbsp;0) and size (0,&nbsp;0).
227+ * @since 1.2
228+ */
229+ public Double() {
230+ }
231+
232+ /**
233+ * Constructs and initializes an <code>Ellipse2D</code> from the
234+ * specified coordinates.
235+ *
236+ * @param x the X coordinate of the upper-left corner
237+ * of the framing rectangle
238+ * @param y the Y coordinate of the upper-left corner
239+ * of the framing rectangle
240+ * @param w the width of the framing rectangle
241+ * @param h the height of the framing rectangle
242+ * @since 1.2
243+ */
244+ public Double(double x, double y, double w, double h) {
245+ setFrame(x, y, w, h);
246+ }
247+
248+ /**
249+ * {@inheritDoc}
250+ * @since 1.2
251+ */
252+ public double getX() {
253+ return x;
254+ }
255+
256+ /**
257+ * {@inheritDoc}
258+ * @since 1.2
259+ */
260+ public double getY() {
261+ return y;
262+ }
263+
264+ /**
265+ * {@inheritDoc}
266+ * @since 1.2
267+ */
268+ public double getWidth() {
269+ return width;
270+ }
271+
272+ /**
273+ * {@inheritDoc}
274+ * @since 1.2
275+ */
276+ public double getHeight() {
277+ return height;
278+ }
279+
280+ /**
281+ * {@inheritDoc}
282+ * @since 1.2
283+ */
284+ public boolean isEmpty() {
285+ return (width <= 0.0 || height <= 0.0);
286+ }
287+
288+ /**
289+ * {@inheritDoc}
290+ * @since 1.2
291+ */
292+ public void setFrame(double x, double y, double w, double h) {
293+ this.x = x;
294+ this.y = y;
295+ this.width = w;
296+ this.height = h;
297+ }
298+
299+ /**
300+ * {@inheritDoc}
301+ * @since 1.2
302+ */
303+ public Rectangle2D getBounds2D() {
304+ return new Rectangle2D.Double(x, y, width, height);
305+ }
306+
307+ /*
308+ * JDK 1.6 serialVersionUID
309+ */
310+ private static final long serialVersionUID = 5555464816372320683L;
311+ }
312+
313+ /**
314+ * This is an abstract class that cannot be instantiated directly.
315+ * Type-specific implementation subclasses are available for
316+ * instantiation and provide a number of formats for storing
317+ * the information necessary to satisfy the various accessor
318+ * methods below.
319+ *
320+ * @see java.awt.geom.Ellipse2D.Float
321+ * @see java.awt.geom.Ellipse2D.Double
322+ * @since 1.2
323+ */
324+ protected Ellipse2D() {
325+ }
326+
327+ /**
328+ * {@inheritDoc}
329+ * @since 1.2
330+ */
331+ public boolean contains(double x, double y) {
332+ // Normalize the coordinates compared to the ellipse
333+ // having a center at 0,0 and a radius of 0.5.
334+ double ellw = getWidth();
335+ if (ellw <= 0.0) {
336+ return false;
337+ }
338+ double normx = (x - getX()) / ellw - 0.5;
339+ double ellh = getHeight();
340+ if (ellh <= 0.0) {
341+ return false;
342+ }
343+ double normy = (y - getY()) / ellh - 0.5;
344+ return (normx * normx + normy * normy) < 0.25;
345+ }
346+
347+ /**
348+ * {@inheritDoc}
349+ * @since 1.2
350+ */
351+ public boolean intersects(double x, double y, double w, double h) {
352+ if (w <= 0.0 || h <= 0.0) {
353+ return false;
354+ }
355+ // Normalize the rectangular coordinates compared to the ellipse
356+ // having a center at 0,0 and a radius of 0.5.
357+ double ellw = getWidth();
358+ if (ellw <= 0.0) {
359+ return false;
360+ }
361+ double normx0 = (x - getX()) / ellw - 0.5;
362+ double normx1 = normx0 + w / ellw;
363+ double ellh = getHeight();
364+ if (ellh <= 0.0) {
365+ return false;
366+ }
367+ double normy0 = (y - getY()) / ellh - 0.5;
368+ double normy1 = normy0 + h / ellh;
369+ // find nearest x (left edge, right edge, 0.0)
370+ // find nearest y (top edge, bottom edge, 0.0)
371+ // if nearest x,y is inside circle of radius 0.5, then intersects
372+ double nearx, neary;
373+ if (normx0 > 0.0) {
374+ // center to left of X extents
375+ nearx = normx0;
376+ } else if (normx1 < 0.0) {
377+ // center to right of X extents
378+ nearx = normx1;
379+ } else {
380+ nearx = 0.0;
381+ }
382+ if (normy0 > 0.0) {
383+ // center above Y extents
384+ neary = normy0;
385+ } else if (normy1 < 0.0) {
386+ // center below Y extents
387+ neary = normy1;
388+ } else {
389+ neary = 0.0;
390+ }
391+ return (nearx * nearx + neary * neary) < 0.25;
392+ }
393+
394+ /**
395+ * {@inheritDoc}
396+ * @since 1.2
397+ */
398+ public boolean contains(double x, double y, double w, double h) {
399+ return (contains(x, y) &&
400+ contains(x + w, y) &&
401+ contains(x, y + h) &&
402+ contains(x + w, y + h));
403+ }
404+
405+ /**
406+ * Returns an iteration object that defines the boundary of this
407+ * <code>Ellipse2D</code>.
408+ * The iterator for this class is multi-threaded safe, which means
409+ * that this <code>Ellipse2D</code> class guarantees that
410+ * modifications to the geometry of this <code>Ellipse2D</code>
411+ * object do not affect any iterations of that geometry that
412+ * are already in process.
413+ * @param at an optional <code>AffineTransform</code> to be applied to
414+ * the coordinates as they are returned in the iteration, or
415+ * <code>null</code> if untransformed coordinates are desired
416+ * @return the <code>PathIterator</code> object that returns the
417+ * geometry of the outline of this <code>Ellipse2D</code>,
418+ * one segment at a time.
419+ * @since 1.2
420+ */
421+ public PathIterator getPathIterator(AffineTransform at) {
422+ return new EllipseIterator(this, at);
423+ }
424+
425+ /**
426+ * Returns the hashcode for this <code>Ellipse2D</code>.
427+ * @return the hashcode for this <code>Ellipse2D</code>.
428+ * @since 1.6
429+ */
430+ public int hashCode() {
431+ long bits = java.lang.Double.doubleToLongBits(getX());
432+ bits += java.lang.Double.doubleToLongBits(getY()) * 37;
433+ bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
434+ bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
435+ return (((int) bits) ^ ((int) (bits >> 32)));
436+ }
437+
438+ /**
439+ * Determines whether or not the specified <code>Object</code> is
440+ * equal to this <code>Ellipse2D</code>. The specified
441+ * <code>Object</code> is equal to this <code>Ellipse2D</code>
442+ * if it is an instance of <code>Ellipse2D</code> and if its
443+ * location and size are the same as this <code>Ellipse2D</code>.
444+ * @param obj an <code>Object</code> to be compared with this
445+ * <code>Ellipse2D</code>.
446+ * @return <code>true</code> if <code>obj</code> is an instance
447+ * of <code>Ellipse2D</code> and has the same values;
448+ * <code>false</code> otherwise.
449+ * @since 1.6
450+ */
451+ public boolean equals(Object obj) {
452+ if (obj == this) {
453+ return true;
454+ }
455+ if (obj instanceof Ellipse2D) {
456+ Ellipse2D e2d = (Ellipse2D) obj;
457+ return ((getX() == e2d.getX()) &&
458+ (getY() == e2d.getY()) &&
459+ (getWidth() == e2d.getWidth()) &&
460+ (getHeight() == e2d.getHeight()));
461+ }
462+ return false;
463+ }
464+}
java/pkg/java/awt/geom/EllipseIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/EllipseIterator.java+189−0
@@ -0,0 +1,189 @@
1+/*
2+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of an ellipse
32+ * through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class EllipseIterator implements PathIterator {
37+ double x, y, w, h;
38+ AffineTransform affine;
39+ int index;
40+
41+ EllipseIterator(Ellipse2D e, AffineTransform at) {
42+ this.x = e.getX();
43+ this.y = e.getY();
44+ this.w = e.getWidth();
45+ this.h = e.getHeight();
46+ this.affine = at;
47+ if (w < 0 || h < 0) {
48+ index = 6;
49+ }
50+ }
51+
52+ /**
53+ * Return the winding rule for determining the insideness of the
54+ * path.
55+ * @see #WIND_EVEN_ODD
56+ * @see #WIND_NON_ZERO
57+ */
58+ public int getWindingRule() {
59+ return WIND_NON_ZERO;
60+ }
61+
62+ /**
63+ * Tests if there are more points to read.
64+ * @return true if there are more points to read
65+ */
66+ public boolean isDone() {
67+ return index > 5;
68+ }
69+
70+ /**
71+ * Moves the iterator to the next segment of the path forwards
72+ * along the primary direction of traversal as long as there are
73+ * more points in that direction.
74+ */
75+ public void next() {
76+ index++;
77+ }
78+
79+ // ArcIterator.btan(Math.PI/2)
80+ public static final double CtrlVal = 0.5522847498307933;
81+
82+ /*
83+ * ctrlpts contains the control points for a set of 4 cubic
84+ * bezier curves that approximate a circle of radius 0.5
85+ * centered at 0.5, 0.5
86+ */
87+ private static final double pcv = 0.5 + CtrlVal * 0.5;
88+ private static final double ncv = 0.5 - CtrlVal * 0.5;
89+ private static double ctrlpts[][] = {
90+ { 1.0, pcv, pcv, 1.0, 0.5, 1.0 },
91+ { ncv, 1.0, 0.0, pcv, 0.0, 0.5 },
92+ { 0.0, ncv, ncv, 0.0, 0.5, 0.0 },
93+ { pcv, 0.0, 1.0, ncv, 1.0, 0.5 }
94+ };
95+
96+ /**
97+ * Returns the coordinates and type of the current path segment in
98+ * the iteration.
99+ * The return value is the path segment type:
100+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
101+ * A float array of length 6 must be passed in and may be used to
102+ * store the coordinates of the point(s).
103+ * Each point is stored as a pair of float x,y coordinates.
104+ * SEG_MOVETO and SEG_LINETO types will return one point,
105+ * SEG_QUADTO will return two points,
106+ * SEG_CUBICTO will return 3 points
107+ * and SEG_CLOSE will not return any points.
108+ * @see #SEG_MOVETO
109+ * @see #SEG_LINETO
110+ * @see #SEG_QUADTO
111+ * @see #SEG_CUBICTO
112+ * @see #SEG_CLOSE
113+ */
114+ public int currentSegment(float[] coords) {
115+ if (isDone()) {
116+ throw new NoSuchElementException("ellipse iterator out of bounds");
117+ }
118+ if (index == 5) {
119+ return SEG_CLOSE;
120+ }
121+ if (index == 0) {
122+ double ctrls[] = ctrlpts[3];
123+ coords[0] = (float) (x + ctrls[4] * w);
124+ coords[1] = (float) (y + ctrls[5] * h);
125+ if (affine != null) {
126+ affine.transform(coords, 0, coords, 0, 1);
127+ }
128+ return SEG_MOVETO;
129+ }
130+ double ctrls[] = ctrlpts[index - 1];
131+ coords[0] = (float) (x + ctrls[0] * w);
132+ coords[1] = (float) (y + ctrls[1] * h);
133+ coords[2] = (float) (x + ctrls[2] * w);
134+ coords[3] = (float) (y + ctrls[3] * h);
135+ coords[4] = (float) (x + ctrls[4] * w);
136+ coords[5] = (float) (y + ctrls[5] * h);
137+ if (affine != null) {
138+ affine.transform(coords, 0, coords, 0, 3);
139+ }
140+ return SEG_CUBICTO;
141+ }
142+
143+ /**
144+ * Returns the coordinates and type of the current path segment in
145+ * the iteration.
146+ * The return value is the path segment type:
147+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
148+ * A double array of length 6 must be passed in and may be used to
149+ * store the coordinates of the point(s).
150+ * Each point is stored as a pair of double x,y coordinates.
151+ * SEG_MOVETO and SEG_LINETO types will return one point,
152+ * SEG_QUADTO will return two points,
153+ * SEG_CUBICTO will return 3 points
154+ * and SEG_CLOSE will not return any points.
155+ * @see #SEG_MOVETO
156+ * @see #SEG_LINETO
157+ * @see #SEG_QUADTO
158+ * @see #SEG_CUBICTO
159+ * @see #SEG_CLOSE
160+ */
161+ public int currentSegment(double[] coords) {
162+ if (isDone()) {
163+ throw new NoSuchElementException("ellipse iterator out of bounds");
164+ }
165+ if (index == 5) {
166+ return SEG_CLOSE;
167+ }
168+ if (index == 0) {
169+ double ctrls[] = ctrlpts[3];
170+ coords[0] = x + ctrls[4] * w;
171+ coords[1] = y + ctrls[5] * h;
172+ if (affine != null) {
173+ affine.transform(coords, 0, coords, 0, 1);
174+ }
175+ return SEG_MOVETO;
176+ }
177+ double ctrls[] = ctrlpts[index - 1];
178+ coords[0] = x + ctrls[0] * w;
179+ coords[1] = y + ctrls[1] * h;
180+ coords[2] = x + ctrls[2] * w;
181+ coords[3] = y + ctrls[3] * h;
182+ coords[4] = x + ctrls[4] * w;
183+ coords[5] = y + ctrls[5] * h;
184+ if (affine != null) {
185+ affine.transform(coords, 0, coords, 0, 3);
186+ }
187+ return SEG_CUBICTO;
188+ }
189+}
java/pkg/java/awt/geom/FlatteningPathIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/FlatteningPathIterator.java+395−0
@@ -0,0 +1,395 @@
1+/*
2+ * Copyright (c) 1997, 1998, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * The <code>FlatteningPathIterator</code> class returns a flattened view of
32+ * another {@link PathIterator} object. Other {@link java.awt.Shape Shape}
33+ * classes can use this class to provide flattening behavior for their paths
34+ * without having to perform the interpolation calculations themselves.
35+ *
36+ * @author Jim Graham
37+ */
38+public class FlatteningPathIterator implements PathIterator {
39+ static final int GROW_SIZE = 24; // Multiple of cubic & quad curve size
40+
41+ PathIterator src; // The source iterator
42+
43+ double squareflat; // Square of the flatness parameter
44+ // for testing against squared lengths
45+
46+ int limit; // Maximum number of recursion levels
47+
48+ double hold[] = new double[14]; // The cache of interpolated coords
49+ // Note that this must be long enough
50+ // to store a full cubic segment and
51+ // a relative cubic segment to avoid
52+ // aliasing when copying the coords
53+ // of a curve to the end of the array.
54+ // This is also serendipitously equal
55+ // to the size of a full quad segment
56+ // and 2 relative quad segments.
57+
58+ double curx, cury; // The ending x,y of the last segment
59+
60+ double movx, movy; // The x,y of the last move segment
61+
62+ int holdType; // The type of the curve being held
63+ // for interpolation
64+
65+ int holdEnd; // The index of the last curve segment
66+ // being held for interpolation
67+
68+ int holdIndex; // The index of the curve segment
69+ // that was last interpolated. This
70+ // is the curve segment ready to be
71+ // returned in the next call to
72+ // currentSegment().
73+
74+ int levels[]; // The recursion level at which
75+ // each curve being held in storage
76+ // was generated.
77+
78+ int levelIndex; // The index of the entry in the
79+ // levels array of the curve segment
80+ // at the holdIndex
81+
82+ boolean done; // True when iteration is done
83+
84+ /**
85+ * Constructs a new <code>FlatteningPathIterator</code> object that
86+ * flattens a path as it iterates over it. The iterator does not
87+ * subdivide any curve read from the source iterator to more than
88+ * 10 levels of subdivision which yields a maximum of 1024 line
89+ * segments per curve.
90+ * @param src the original unflattened path being iterated over
91+ * @param flatness the maximum allowable distance between the
92+ * control points and the flattened curve
93+ */
94+ public FlatteningPathIterator(PathIterator src, double flatness) {
95+ this(src, flatness, 10);
96+ }
97+
98+ /**
99+ * Constructs a new <code>FlatteningPathIterator</code> object
100+ * that flattens a path as it iterates over it.
101+ * The <code>limit</code> parameter allows you to control the
102+ * maximum number of recursive subdivisions that the iterator
103+ * can make before it assumes that the curve is flat enough
104+ * without measuring against the <code>flatness</code> parameter.
105+ * The flattened iteration therefore never generates more than
106+ * a maximum of <code>(2^limit)</code> line segments per curve.
107+ * @param src the original unflattened path being iterated over
108+ * @param flatness the maximum allowable distance between the
109+ * control points and the flattened curve
110+ * @param limit the maximum number of recursive subdivisions
111+ * allowed for any curved segment
112+ * @exception <code>IllegalArgumentException</code> if
113+ * <code>flatness</code> or <code>limit</code>
114+ * is less than zero
115+ */
116+ public FlatteningPathIterator(PathIterator src, double flatness,
117+ int limit) {
118+ if (flatness < 0.0) {
119+ throw new IllegalArgumentException("flatness must be >= 0");
120+ }
121+ if (limit < 0) {
122+ throw new IllegalArgumentException("limit must be >= 0");
123+ }
124+ this.src = src;
125+ this.squareflat = flatness * flatness;
126+ this.limit = limit;
127+ this.levels = new int[limit + 1];
128+ // prime the first path segment
129+ next(false);
130+ }
131+
132+ /**
133+ * Returns the flatness of this iterator.
134+ * @return the flatness of this <code>FlatteningPathIterator</code>.
135+ */
136+ public double getFlatness() {
137+ return Math.sqrt(squareflat);
138+ }
139+
140+ /**
141+ * Returns the recursion limit of this iterator.
142+ * @return the recursion limit of this
143+ * <code>FlatteningPathIterator</code>.
144+ */
145+ public int getRecursionLimit() {
146+ return limit;
147+ }
148+
149+ /**
150+ * Returns the winding rule for determining the interior of the
151+ * path.
152+ * @return the winding rule of the original unflattened path being
153+ * iterated over.
154+ * @see PathIterator#WIND_EVEN_ODD
155+ * @see PathIterator#WIND_NON_ZERO
156+ */
157+ public int getWindingRule() {
158+ return src.getWindingRule();
159+ }
160+
161+ /**
162+ * Tests if the iteration is complete.
163+ * @return <code>true</code> if all the segments have
164+ * been read; <code>false</code> otherwise.
165+ */
166+ public boolean isDone() {
167+ return done;
168+ }
169+
170+ /*
171+ * Ensures that the hold array can hold up to (want) more values.
172+ * It is currently holding (hold.length - holdIndex) values.
173+ */
174+ void ensureHoldCapacity(int want) {
175+ if (holdIndex - want < 0) {
176+ int have = hold.length - holdIndex;
177+ int newsize = hold.length + GROW_SIZE;
178+ double newhold[] = new double[newsize];
179+ System.arraycopy(hold, holdIndex,
180+ newhold, holdIndex + GROW_SIZE,
181+ have);
182+ hold = newhold;
183+ holdIndex += GROW_SIZE;
184+ holdEnd += GROW_SIZE;
185+ }
186+ }
187+
188+ /**
189+ * Moves the iterator to the next segment of the path forwards
190+ * along the primary direction of traversal as long as there are
191+ * more points in that direction.
192+ */
193+ public void next() {
194+ next(true);
195+ }
196+
197+ private void next(boolean doNext) {
198+ int level;
199+
200+ if (holdIndex >= holdEnd) {
201+ if (doNext) {
202+ src.next();
203+ }
204+ if (src.isDone()) {
205+ done = true;
206+ return;
207+ }
208+ holdType = src.currentSegment(hold);
209+ levelIndex = 0;
210+ levels[0] = 0;
211+ }
212+
213+ switch (holdType) {
214+ case SEG_MOVETO:
215+ case SEG_LINETO:
216+ curx = hold[0];
217+ cury = hold[1];
218+ if (holdType == SEG_MOVETO) {
219+ movx = curx;
220+ movy = cury;
221+ }
222+ holdIndex = 0;
223+ holdEnd = 0;
224+ break;
225+ case SEG_CLOSE:
226+ curx = movx;
227+ cury = movy;
228+ holdIndex = 0;
229+ holdEnd = 0;
230+ break;
231+ case SEG_QUADTO:
232+ if (holdIndex >= holdEnd) {
233+ // Move the coordinates to the end of the array.
234+ holdIndex = hold.length - 6;
235+ holdEnd = hold.length - 2;
236+ hold[holdIndex + 0] = curx;
237+ hold[holdIndex + 1] = cury;
238+ hold[holdIndex + 2] = hold[0];
239+ hold[holdIndex + 3] = hold[1];
240+ hold[holdIndex + 4] = curx = hold[2];
241+ hold[holdIndex + 5] = cury = hold[3];
242+ }
243+
244+ level = levels[levelIndex];
245+ while (level < limit) {
246+ if (QuadCurve2D.getFlatnessSq(hold, holdIndex) < squareflat) {
247+ break;
248+ }
249+
250+ ensureHoldCapacity(4);
251+ QuadCurve2D.subdivide(hold, holdIndex,
252+ hold, holdIndex - 4,
253+ hold, holdIndex);
254+ holdIndex -= 4;
255+
256+ // Now that we have subdivided, we have constructed
257+ // two curves of one depth lower than the original
258+ // curve. One of those curves is in the place of
259+ // the former curve and one of them is in the next
260+ // set of held coordinate slots. We now set both
261+ // curves level values to the next higher level.
262+ level++;
263+ levels[levelIndex] = level;
264+ levelIndex++;
265+ levels[levelIndex] = level;
266+ }
267+
268+ // This curve segment is flat enough, or it is too deep
269+ // in recursion levels to try to flatten any more. The
270+ // two coordinates at holdIndex+4 and holdIndex+5 now
271+ // contain the endpoint of the curve which can be the
272+ // endpoint of an approximating line segment.
273+ holdIndex += 4;
274+ levelIndex--;
275+ break;
276+ case SEG_CUBICTO:
277+ if (holdIndex >= holdEnd) {
278+ // Move the coordinates to the end of the array.
279+ holdIndex = hold.length - 8;
280+ holdEnd = hold.length - 2;
281+ hold[holdIndex + 0] = curx;
282+ hold[holdIndex + 1] = cury;
283+ hold[holdIndex + 2] = hold[0];
284+ hold[holdIndex + 3] = hold[1];
285+ hold[holdIndex + 4] = hold[2];
286+ hold[holdIndex + 5] = hold[3];
287+ hold[holdIndex + 6] = curx = hold[4];
288+ hold[holdIndex + 7] = cury = hold[5];
289+ }
290+
291+ level = levels[levelIndex];
292+ while (level < limit) {
293+ if (CubicCurve2D.getFlatnessSq(hold, holdIndex) < squareflat) {
294+ break;
295+ }
296+
297+ ensureHoldCapacity(6);
298+ CubicCurve2D.subdivide(hold, holdIndex,
299+ hold, holdIndex - 6,
300+ hold, holdIndex);
301+ holdIndex -= 6;
302+
303+ // Now that we have subdivided, we have constructed
304+ // two curves of one depth lower than the original
305+ // curve. One of those curves is in the place of
306+ // the former curve and one of them is in the next
307+ // set of held coordinate slots. We now set both
308+ // curves level values to the next higher level.
309+ level++;
310+ levels[levelIndex] = level;
311+ levelIndex++;
312+ levels[levelIndex] = level;
313+ }
314+
315+ // This curve segment is flat enough, or it is too deep
316+ // in recursion levels to try to flatten any more. The
317+ // two coordinates at holdIndex+6 and holdIndex+7 now
318+ // contain the endpoint of the curve which can be the
319+ // endpoint of an approximating line segment.
320+ holdIndex += 6;
321+ levelIndex--;
322+ break;
323+ }
324+ }
325+
326+ /**
327+ * Returns the coordinates and type of the current path segment in
328+ * the iteration.
329+ * The return value is the path segment type:
330+ * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
331+ * A float array of length 6 must be passed in and can be used to
332+ * store the coordinates of the point(s).
333+ * Each point is stored as a pair of float x,y coordinates.
334+ * SEG_MOVETO and SEG_LINETO types return one point,
335+ * and SEG_CLOSE does not return any points.
336+ * @param coords an array that holds the data returned from
337+ * this method
338+ * @return the path segment type of the current path segment.
339+ * @exception <code>NoSuchElementException</code> if there
340+ * are no more elements in the flattening path to be
341+ * returned.
342+ * @see PathIterator#SEG_MOVETO
343+ * @see PathIterator#SEG_LINETO
344+ * @see PathIterator#SEG_CLOSE
345+ */
346+ public int currentSegment(float[] coords) {
347+ if (isDone()) {
348+ throw new NoSuchElementException("flattening iterator out of bounds");
349+ }
350+ int type = holdType;
351+ if (type != SEG_CLOSE) {
352+ coords[0] = (float) hold[holdIndex + 0];
353+ coords[1] = (float) hold[holdIndex + 1];
354+ if (type != SEG_MOVETO) {
355+ type = SEG_LINETO;
356+ }
357+ }
358+ return type;
359+ }
360+
361+ /**
362+ * Returns the coordinates and type of the current path segment in
363+ * the iteration.
364+ * The return value is the path segment type:
365+ * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
366+ * A double array of length 6 must be passed in and can be used to
367+ * store the coordinates of the point(s).
368+ * Each point is stored as a pair of double x,y coordinates.
369+ * SEG_MOVETO and SEG_LINETO types return one point,
370+ * and SEG_CLOSE does not return any points.
371+ * @param coords an array that holds the data returned from
372+ * this method
373+ * @return the path segment type of the current path segment.
374+ * @exception <code>NoSuchElementException</code> if there
375+ * are no more elements in the flattening path to be
376+ * returned.
377+ * @see PathIterator#SEG_MOVETO
378+ * @see PathIterator#SEG_LINETO
379+ * @see PathIterator#SEG_CLOSE
380+ */
381+ public int currentSegment(double[] coords) {
382+ if (isDone()) {
383+ throw new NoSuchElementException("flattening iterator out of bounds");
384+ }
385+ int type = holdType;
386+ if (type != SEG_CLOSE) {
387+ coords[0] = hold[holdIndex + 0];
388+ coords[1] = hold[holdIndex + 1];
389+ if (type != SEG_MOVETO) {
390+ type = SEG_LINETO;
391+ }
392+ }
393+ return type;
394+ }
395+}
java/pkg/java/awt/geom/GeneralPath.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/GeneralPath.java+127−0
@@ -0,0 +1,127 @@
1+/*
2+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+
30+/**
31+ * The {@code GeneralPath} class represents a geometric path
32+ * constructed from straight lines, and quadratic and cubic
33+ * (B&eacute;zier) curves. It can contain multiple subpaths.
34+ * <p>
35+ * {@code GeneralPath} is a legacy final class which exactly
36+ * implements the behavior of its superclass {@link Path2D.Float}.
37+ * Together with {@link Path2D.Double}, the {@link Path2D} classes
38+ * provide full implementations of a general geometric path that
39+ * support all of the functionality of the {@link Shape} and
40+ * {@link PathIterator} interfaces with the ability to explicitly
41+ * select different levels of internal coordinate precision.
42+ * <p>
43+ * Use {@code Path2D.Float} (or this legacy {@code GeneralPath}
44+ * subclass) when dealing with data that can be represented
45+ * and used with floating point precision. Use {@code Path2D.Double}
46+ * for data that requires the accuracy or range of double precision.
47+ *
48+ * @author Jim Graham
49+ * @since 1.2
50+ */
51+public final class GeneralPath extends Path2D.Float {
52+ /**
53+ * Constructs a new empty single precision {@code GeneralPath} object
54+ * with a default winding rule of {@link #WIND_NON_ZERO}.
55+ *
56+ * @since 1.2
57+ */
58+ public GeneralPath() {
59+ super(WIND_NON_ZERO, INIT_SIZE);
60+ }
61+
62+ /**
63+ * Constructs a new <code>GeneralPath</code> object with the specified
64+ * winding rule to control operations that require the interior of the
65+ * path to be defined.
66+ *
67+ * @param rule the winding rule
68+ * @see #WIND_EVEN_ODD
69+ * @see #WIND_NON_ZERO
70+ * @since 1.2
71+ */
72+ public GeneralPath(int rule) {
73+ super(rule, INIT_SIZE);
74+ }
75+
76+ /**
77+ * Constructs a new <code>GeneralPath</code> object with the specified
78+ * winding rule and the specified initial capacity to store path
79+ * coordinates.
80+ * This number is an initial guess as to how many path segments
81+ * will be added to the path, but the storage is expanded as
82+ * needed to store whatever path segments are added.
83+ *
84+ * @param rule the winding rule
85+ * @param initialCapacity the estimate for the number of path segments
86+ * in the path
87+ * @see #WIND_EVEN_ODD
88+ * @see #WIND_NON_ZERO
89+ * @since 1.2
90+ */
91+ public GeneralPath(int rule, int initialCapacity) {
92+ super(rule, initialCapacity);
93+ }
94+
95+ /**
96+ * Constructs a new <code>GeneralPath</code> object from an arbitrary
97+ * {@link Shape} object.
98+ * All of the initial geometry and the winding rule for this path are
99+ * taken from the specified <code>Shape</code> object.
100+ *
101+ * @param s the specified <code>Shape</code> object
102+ * @since 1.2
103+ */
104+ public GeneralPath(Shape s) {
105+ super(s, null);
106+ }
107+
108+ GeneralPath(int windingRule,
109+ byte[] pointTypes,
110+ int numTypes,
111+ float[] pointCoords,
112+ int numCoords)
113+ {
114+ // used to construct from native
115+
116+ this.windingRule = windingRule;
117+ this.pointTypes = pointTypes;
118+ this.numTypes = numTypes;
119+ this.floatCoords = pointCoords;
120+ this.numCoords = numCoords;
121+ }
122+
123+ /*
124+ * JDK 1.6 serialVersionUID
125+ */
126+ private static final long serialVersionUID = -8327096662768731142L;
127+}
java/pkg/java/awt/geom/IllegalPathStateException.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/IllegalPathStateException.java+56−0
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (c) 1997, 1999, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+/**
29+ * The <code>IllegalPathStateException</code> represents an
30+ * exception that is thrown if an operation is performed on a path
31+ * that is in an illegal state with respect to the particular
32+ * operation being performed, such as appending a path segment
33+ * to a {@link GeneralPath} without an initial moveto.
34+ *
35+ */
36+
37+public class IllegalPathStateException extends RuntimeException {
38+ /**
39+ * Constructs an <code>IllegalPathStateException</code> with no
40+ * detail message.
41+ *
42+ * @since 1.2
43+ */
44+ public IllegalPathStateException() {
45+ }
46+
47+ /**
48+ * Constructs an <code>IllegalPathStateException</code> with the
49+ * specified detail message.
50+ * @param s the detail message
51+ * @since 1.2
52+ */
53+ public IllegalPathStateException(String s) {
54+ super (s);
55+ }
56+}
java/pkg/java/awt/geom/Line2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Line2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Line2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Line2D.java+1128−0
@@ -0,0 +1,1128 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.awt.Rectangle;
30+import java.io.Serializable;
31+
32+/**
33+ * This <code>Line2D</code> represents a line segment in {@code (x,y)}
34+ * coordinate space. This class, like all of the Java 2D API, uses a
35+ * default coordinate system called <i>user space</i> in which the y-axis
36+ * values increase downward and x-axis values increase to the right. For
37+ * more information on the user space coordinate system, see the
38+ * <a href="http://java.sun.com/j2se/1.3/docs/guide/2d/spec/j2d-intro.fm2.html#61857">
39+ * Coordinate Systems</a> section of the Java 2D Programmer's Guide.
40+ * <p>
41+ * This class is only the abstract superclass for all objects that
42+ * store a 2D line segment.
43+ * The actual storage representation of the coordinates is left to
44+ * the subclass.
45+ *
46+ * @author Jim Graham
47+ * @since 1.2
48+ */
49+public abstract class Line2D implements Shape, Cloneable {
50+
51+ /**
52+ * A line segment specified with float coordinates.
53+ * @since 1.2
54+ */
55+ public static class Float extends Line2D implements Serializable {
56+ /**
57+ * The X coordinate of the start point of the line segment.
58+ * @since 1.2
59+ * @serial
60+ */
61+ public float x1;
62+
63+ /**
64+ * The Y coordinate of the start point of the line segment.
65+ * @since 1.2
66+ * @serial
67+ */
68+ public float y1;
69+
70+ /**
71+ * The X coordinate of the end point of the line segment.
72+ * @since 1.2
73+ * @serial
74+ */
75+ public float x2;
76+
77+ /**
78+ * The Y coordinate of the end point of the line segment.
79+ * @since 1.2
80+ * @serial
81+ */
82+ public float y2;
83+
84+ /**
85+ * Constructs and initializes a Line with coordinates (0, 0) -> (0, 0).
86+ * @since 1.2
87+ */
88+ public Float() {
89+ }
90+
91+ /**
92+ * Constructs and initializes a Line from the specified coordinates.
93+ * @param x1 the X coordinate of the start point
94+ * @param y1 the Y coordinate of the start point
95+ * @param x2 the X coordinate of the end point
96+ * @param y2 the Y coordinate of the end point
97+ * @since 1.2
98+ */
99+ public Float(float x1, float y1, float x2, float y2) {
100+ setLine(x1, y1, x2, y2);
101+ }
102+
103+ /**
104+ * Constructs and initializes a <code>Line2D</code> from the
105+ * specified <code>Point2D</code> objects.
106+ * @param p1 the start <code>Point2D</code> of this line segment
107+ * @param p2 the end <code>Point2D</code> of this line segment
108+ * @since 1.2
109+ */
110+ public Float(Point2D p1, Point2D p2) {
111+ setLine(p1, p2);
112+ }
113+
114+ /**
115+ * {@inheritDoc}
116+ * @since 1.2
117+ */
118+ public double getX1() {
119+ return (double) x1;
120+ }
121+
122+ /**
123+ * {@inheritDoc}
124+ * @since 1.2
125+ */
126+ public double getY1() {
127+ return (double) y1;
128+ }
129+
130+ /**
131+ * {@inheritDoc}
132+ * @since 1.2
133+ */
134+ public Point2D getP1() {
135+ return new Point2D.Float(x1, y1);
136+ }
137+
138+ /**
139+ * {@inheritDoc}
140+ * @since 1.2
141+ */
142+ public double getX2() {
143+ return (double) x2;
144+ }
145+
146+ /**
147+ * {@inheritDoc}
148+ * @since 1.2
149+ */
150+ public double getY2() {
151+ return (double) y2;
152+ }
153+
154+ /**
155+ * {@inheritDoc}
156+ * @since 1.2
157+ */
158+ public Point2D getP2() {
159+ return new Point2D.Float(x2, y2);
160+ }
161+
162+ /**
163+ * {@inheritDoc}
164+ * @since 1.2
165+ */
166+ public void setLine(double x1, double y1, double x2, double y2) {
167+ this.x1 = (float) x1;
168+ this.y1 = (float) y1;
169+ this.x2 = (float) x2;
170+ this.y2 = (float) y2;
171+ }
172+
173+ /**
174+ * Sets the location of the end points of this <code>Line2D</code>
175+ * to the specified float coordinates.
176+ * @param x1 the X coordinate of the start point
177+ * @param y1 the Y coordinate of the start point
178+ * @param x2 the X coordinate of the end point
179+ * @param y2 the Y coordinate of the end point
180+ * @since 1.2
181+ */
182+ public void setLine(float x1, float y1, float x2, float y2) {
183+ this.x1 = x1;
184+ this.y1 = y1;
185+ this.x2 = x2;
186+ this.y2 = y2;
187+ }
188+
189+ /**
190+ * {@inheritDoc}
191+ * @since 1.2
192+ */
193+ public Rectangle2D getBounds2D() {
194+ float x, y, w, h;
195+ if (x1 < x2) {
196+ x = x1;
197+ w = x2 - x1;
198+ } else {
199+ x = x2;
200+ w = x1 - x2;
201+ }
202+ if (y1 < y2) {
203+ y = y1;
204+ h = y2 - y1;
205+ } else {
206+ y = y2;
207+ h = y1 - y2;
208+ }
209+ return new Rectangle2D.Float(x, y, w, h);
210+ }
211+
212+ /*
213+ * JDK 1.6 serialVersionUID
214+ */
215+ private static final long serialVersionUID = 6161772511649436349L;
216+ }
217+
218+ /**
219+ * A line segment specified with double coordinates.
220+ * @since 1.2
221+ */
222+ public static class Double extends Line2D implements Serializable {
223+ /**
224+ * The X coordinate of the start point of the line segment.
225+ * @since 1.2
226+ * @serial
227+ */
228+ public double x1;
229+
230+ /**
231+ * The Y coordinate of the start point of the line segment.
232+ * @since 1.2
233+ * @serial
234+ */
235+ public double y1;
236+
237+ /**
238+ * The X coordinate of the end point of the line segment.
239+ * @since 1.2
240+ * @serial
241+ */
242+ public double x2;
243+
244+ /**
245+ * The Y coordinate of the end point of the line segment.
246+ * @since 1.2
247+ * @serial
248+ */
249+ public double y2;
250+
251+ /**
252+ * Constructs and initializes a Line with coordinates (0, 0) -> (0, 0).
253+ * @since 1.2
254+ */
255+ public Double() {
256+ }
257+
258+ /**
259+ * Constructs and initializes a <code>Line2D</code> from the
260+ * specified coordinates.
261+ * @param x1 the X coordinate of the start point
262+ * @param y1 the Y coordinate of the start point
263+ * @param x2 the X coordinate of the end point
264+ * @param y2 the Y coordinate of the end point
265+ * @since 1.2
266+ */
267+ public Double(double x1, double y1, double x2, double y2) {
268+ setLine(x1, y1, x2, y2);
269+ }
270+
271+ /**
272+ * Constructs and initializes a <code>Line2D</code> from the
273+ * specified <code>Point2D</code> objects.
274+ * @param p1 the start <code>Point2D</code> of this line segment
275+ * @param p2 the end <code>Point2D</code> of this line segment
276+ * @since 1.2
277+ */
278+ public Double(Point2D p1, Point2D p2) {
279+ setLine(p1, p2);
280+ }
281+
282+ /**
283+ * {@inheritDoc}
284+ * @since 1.2
285+ */
286+ public double getX1() {
287+ return x1;
288+ }
289+
290+ /**
291+ * {@inheritDoc}
292+ * @since 1.2
293+ */
294+ public double getY1() {
295+ return y1;
296+ }
297+
298+ /**
299+ * {@inheritDoc}
300+ * @since 1.2
301+ */
302+ public Point2D getP1() {
303+ return new Point2D.Double(x1, y1);
304+ }
305+
306+ /**
307+ * {@inheritDoc}
308+ * @since 1.2
309+ */
310+ public double getX2() {
311+ return x2;
312+ }
313+
314+ /**
315+ * {@inheritDoc}
316+ * @since 1.2
317+ */
318+ public double getY2() {
319+ return y2;
320+ }
321+
322+ /**
323+ * {@inheritDoc}
324+ * @since 1.2
325+ */
326+ public Point2D getP2() {
327+ return new Point2D.Double(x2, y2);
328+ }
329+
330+ /**
331+ * {@inheritDoc}
332+ * @since 1.2
333+ */
334+ public void setLine(double x1, double y1, double x2, double y2) {
335+ this.x1 = x1;
336+ this.y1 = y1;
337+ this.x2 = x2;
338+ this.y2 = y2;
339+ }
340+
341+ /**
342+ * {@inheritDoc}
343+ * @since 1.2
344+ */
345+ public Rectangle2D getBounds2D() {
346+ double x, y, w, h;
347+ if (x1 < x2) {
348+ x = x1;
349+ w = x2 - x1;
350+ } else {
351+ x = x2;
352+ w = x1 - x2;
353+ }
354+ if (y1 < y2) {
355+ y = y1;
356+ h = y2 - y1;
357+ } else {
358+ y = y2;
359+ h = y1 - y2;
360+ }
361+ return new Rectangle2D.Double(x, y, w, h);
362+ }
363+
364+ /*
365+ * JDK 1.6 serialVersionUID
366+ */
367+ private static final long serialVersionUID = 7979627399746467499L;
368+ }
369+
370+ /**
371+ * This is an abstract class that cannot be instantiated directly.
372+ * Type-specific implementation subclasses are available for
373+ * instantiation and provide a number of formats for storing
374+ * the information necessary to satisfy the various accessory
375+ * methods below.
376+ *
377+ * @see java.awt.geom.Line2D.Float
378+ * @see java.awt.geom.Line2D.Double
379+ * @since 1.2
380+ */
381+ protected Line2D() {
382+ }
383+
384+ /**
385+ * Returns the X coordinate of the start point in double precision.
386+ * @return the X coordinate of the start point of this
387+ * {@code Line2D} object.
388+ * @since 1.2
389+ */
390+ public abstract double getX1();
391+
392+ /**
393+ * Returns the Y coordinate of the start point in double precision.
394+ * @return the Y coordinate of the start point of this
395+ * {@code Line2D} object.
396+ * @since 1.2
397+ */
398+ public abstract double getY1();
399+
400+ /**
401+ * Returns the start <code>Point2D</code> of this <code>Line2D</code>.
402+ * @return the start <code>Point2D</code> of this <code>Line2D</code>.
403+ * @since 1.2
404+ */
405+ public abstract Point2D getP1();
406+
407+ /**
408+ * Returns the X coordinate of the end point in double precision.
409+ * @return the X coordinate of the end point of this
410+ * {@code Line2D} object.
411+ * @since 1.2
412+ */
413+ public abstract double getX2();
414+
415+ /**
416+ * Returns the Y coordinate of the end point in double precision.
417+ * @return the Y coordinate of the end point of this
418+ * {@code Line2D} object.
419+ * @since 1.2
420+ */
421+ public abstract double getY2();
422+
423+ /**
424+ * Returns the end <code>Point2D</code> of this <code>Line2D</code>.
425+ * @return the end <code>Point2D</code> of this <code>Line2D</code>.
426+ * @since 1.2
427+ */
428+ public abstract Point2D getP2();
429+
430+ /**
431+ * Sets the location of the end points of this <code>Line2D</code> to
432+ * the specified double coordinates.
433+ * @param x1 the X coordinate of the start point
434+ * @param y1 the Y coordinate of the start point
435+ * @param x2 the X coordinate of the end point
436+ * @param y2 the Y coordinate of the end point
437+ * @since 1.2
438+ */
439+ public abstract void setLine(double x1, double y1, double x2, double y2);
440+
441+ /**
442+ * Sets the location of the end points of this <code>Line2D</code> to
443+ * the specified <code>Point2D</code> coordinates.
444+ * @param p1 the start <code>Point2D</code> of the line segment
445+ * @param p2 the end <code>Point2D</code> of the line segment
446+ * @since 1.2
447+ */
448+ public void setLine(Point2D p1, Point2D p2) {
449+ setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
450+ }
451+
452+ /**
453+ * Sets the location of the end points of this <code>Line2D</code> to
454+ * the same as those end points of the specified <code>Line2D</code>.
455+ * @param l the specified <code>Line2D</code>
456+ * @since 1.2
457+ */
458+ public void setLine(Line2D l) {
459+ setLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
460+ }
461+
462+ /**
463+ * Returns an indicator of where the specified point
464+ * {@code (px,py)} lies with respect to the line segment from
465+ * {@code (x1,y1)} to {@code (x2,y2)}.
466+ * The return value can be either 1, -1, or 0 and indicates
467+ * in which direction the specified line must pivot around its
468+ * first end point, {@code (x1,y1)}, in order to point at the
469+ * specified point {@code (px,py)}.
470+ * <p>A return value of 1 indicates that the line segment must
471+ * turn in the direction that takes the positive X axis towards
472+ * the negative Y axis. In the default coordinate system used by
473+ * Java 2D, this direction is counterclockwise.
474+ * <p>A return value of -1 indicates that the line segment must
475+ * turn in the direction that takes the positive X axis towards
476+ * the positive Y axis. In the default coordinate system, this
477+ * direction is clockwise.
478+ * <p>A return value of 0 indicates that the point lies
479+ * exactly on the line segment. Note that an indicator value
480+ * of 0 is rare and not useful for determining colinearity
481+ * because of floating point rounding issues.
482+ * <p>If the point is colinear with the line segment, but
483+ * not between the end points, then the value will be -1 if the point
484+ * lies "beyond {@code (x1,y1)}" or 1 if the point lies
485+ * "beyond {@code (x2,y2)}".
486+ *
487+ * @param x1 the X coordinate of the start point of the
488+ * specified line segment
489+ * @param y1 the Y coordinate of the start point of the
490+ * specified line segment
491+ * @param x2 the X coordinate of the end point of the
492+ * specified line segment
493+ * @param y2 the Y coordinate of the end point of the
494+ * specified line segment
495+ * @param px the X coordinate of the specified point to be
496+ * compared with the specified line segment
497+ * @param py the Y coordinate of the specified point to be
498+ * compared with the specified line segment
499+ * @return an integer that indicates the position of the third specified
500+ * coordinates with respect to the line segment formed
501+ * by the first two specified coordinates.
502+ * @since 1.2
503+ */
504+ public static int relativeCCW(double x1, double y1,
505+ double x2, double y2,
506+ double px, double py)
507+ {
508+ x2 -= x1;
509+ y2 -= y1;
510+ px -= x1;
511+ py -= y1;
512+ double ccw = px * y2 - py * x2;
513+ if (ccw == 0.0) {
514+ // The point is colinear, classify based on which side of
515+ // the segment the point falls on. We can calculate a
516+ // relative value using the projection of px,py onto the
517+ // segment - a negative value indicates the point projects
518+ // outside of the segment in the direction of the particular
519+ // endpoint used as the origin for the projection.
520+ ccw = px * x2 + py * y2;
521+ if (ccw > 0.0) {
522+ // Reverse the projection to be relative to the original x2,y2
523+ // x2 and y2 are simply negated.
524+ // px and py need to have (x2 - x1) or (y2 - y1) subtracted
525+ // from them (based on the original values)
526+ // Since we really want to get a positive answer when the
527+ // point is "beyond (x2,y2)", then we want to calculate
528+ // the inverse anyway - thus we leave x2 & y2 negated.
529+ px -= x2;
530+ py -= y2;
531+ ccw = px * x2 + py * y2;
532+ if (ccw < 0.0) {
533+ ccw = 0.0;
534+ }
535+ }
536+ }
537+ return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
538+ }
539+
540+ /**
541+ * Returns an indicator of where the specified point
542+ * {@code (px,py)} lies with respect to this line segment.
543+ * See the method comments of
544+ * {@link #relativeCCW(double, double, double, double, double, double)}
545+ * to interpret the return value.
546+ * @param px the X coordinate of the specified point
547+ * to be compared with this <code>Line2D</code>
548+ * @param py the Y coordinate of the specified point
549+ * to be compared with this <code>Line2D</code>
550+ * @return an integer that indicates the position of the specified
551+ * coordinates with respect to this <code>Line2D</code>
552+ * @see #relativeCCW(double, double, double, double, double, double)
553+ * @since 1.2
554+ */
555+ public int relativeCCW(double px, double py) {
556+ return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py);
557+ }
558+
559+ /**
560+ * Returns an indicator of where the specified <code>Point2D</code>
561+ * lies with respect to this line segment.
562+ * See the method comments of
563+ * {@link #relativeCCW(double, double, double, double, double, double)}
564+ * to interpret the return value.
565+ * @param p the specified <code>Point2D</code> to be compared
566+ * with this <code>Line2D</code>
567+ * @return an integer that indicates the position of the specified
568+ * <code>Point2D</code> with respect to this <code>Line2D</code>
569+ * @see #relativeCCW(double, double, double, double, double, double)
570+ * @since 1.2
571+ */
572+ public int relativeCCW(Point2D p) {
573+ return relativeCCW(getX1(), getY1(), getX2(), getY2(),
574+ p.getX(), p.getY());
575+ }
576+
577+ /**
578+ * Tests if the line segment from {@code (x1,y1)} to
579+ * {@code (x2,y2)} intersects the line segment from {@code (x3,y3)}
580+ * to {@code (x4,y4)}.
581+ *
582+ * @param x1 the X coordinate of the start point of the first
583+ * specified line segment
584+ * @param y1 the Y coordinate of the start point of the first
585+ * specified line segment
586+ * @param x2 the X coordinate of the end point of the first
587+ * specified line segment
588+ * @param y2 the Y coordinate of the end point of the first
589+ * specified line segment
590+ * @param x3 the X coordinate of the start point of the second
591+ * specified line segment
592+ * @param y3 the Y coordinate of the start point of the second
593+ * specified line segment
594+ * @param x4 the X coordinate of the end point of the second
595+ * specified line segment
596+ * @param y4 the Y coordinate of the end point of the second
597+ * specified line segment
598+ * @return <code>true</code> if the first specified line segment
599+ * and the second specified line segment intersect
600+ * each other; <code>false</code> otherwise.
601+ * @since 1.2
602+ */
603+ public static boolean linesIntersect(double x1, double y1,
604+ double x2, double y2,
605+ double x3, double y3,
606+ double x4, double y4)
607+ {
608+ return ((relativeCCW(x1, y1, x2, y2, x3, y3) *
609+ relativeCCW(x1, y1, x2, y2, x4, y4) <= 0)
610+ && (relativeCCW(x3, y3, x4, y4, x1, y1) *
611+ relativeCCW(x3, y3, x4, y4, x2, y2) <= 0));
612+ }
613+
614+ /**
615+ * Tests if the line segment from {@code (x1,y1)} to
616+ * {@code (x2,y2)} intersects this line segment.
617+ *
618+ * @param x1 the X coordinate of the start point of the
619+ * specified line segment
620+ * @param y1 the Y coordinate of the start point of the
621+ * specified line segment
622+ * @param x2 the X coordinate of the end point of the
623+ * specified line segment
624+ * @param y2 the Y coordinate of the end point of the
625+ * specified line segment
626+ * @return <true> if this line segment and the specified line segment
627+ * intersect each other; <code>false</code> otherwise.
628+ * @since 1.2
629+ */
630+ public boolean intersectsLine(double x1, double y1, double x2, double y2) {
631+ return linesIntersect(x1, y1, x2, y2,
632+ getX1(), getY1(), getX2(), getY2());
633+ }
634+
635+ /**
636+ * Tests if the specified line segment intersects this line segment.
637+ * @param l the specified <code>Line2D</code>
638+ * @return <code>true</code> if this line segment and the specified line
639+ * segment intersect each other;
640+ * <code>false</code> otherwise.
641+ * @since 1.2
642+ */
643+ public boolean intersectsLine(Line2D l) {
644+ return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(),
645+ getX1(), getY1(), getX2(), getY2());
646+ }
647+
648+ /**
649+ * Returns the square of the distance from a point to a line segment.
650+ * The distance measured is the distance between the specified
651+ * point and the closest point between the specified end points.
652+ * If the specified point intersects the line segment in between the
653+ * end points, this method returns 0.0.
654+ *
655+ * @param x1 the X coordinate of the start point of the
656+ * specified line segment
657+ * @param y1 the Y coordinate of the start point of the
658+ * specified line segment
659+ * @param x2 the X coordinate of the end point of the
660+ * specified line segment
661+ * @param y2 the Y coordinate of the end point of the
662+ * specified line segment
663+ * @param px the X coordinate of the specified point being
664+ * measured against the specified line segment
665+ * @param py the Y coordinate of the specified point being
666+ * measured against the specified line segment
667+ * @return a double value that is the square of the distance from the
668+ * specified point to the specified line segment.
669+ * @see #ptLineDistSq(double, double, double, double, double, double)
670+ * @since 1.2
671+ */
672+ public static double ptSegDistSq(double x1, double y1,
673+ double x2, double y2,
674+ double px, double py)
675+ {
676+ // Adjust vectors relative to x1,y1
677+ // x2,y2 becomes relative vector from x1,y1 to end of segment
678+ x2 -= x1;
679+ y2 -= y1;
680+ // px,py becomes relative vector from x1,y1 to test point
681+ px -= x1;
682+ py -= y1;
683+ double dotprod = px * x2 + py * y2;
684+ double projlenSq;
685+ if (dotprod <= 0.0) {
686+ // px,py is on the side of x1,y1 away from x2,y2
687+ // distance to segment is length of px,py vector
688+ // "length of its (clipped) projection" is now 0.0
689+ projlenSq = 0.0;
690+ } else {
691+ // switch to backwards vectors relative to x2,y2
692+ // x2,y2 are already the negative of x1,y1=>x2,y2
693+ // to get px,py to be the negative of px,py=>x2,y2
694+ // the dot product of two negated vectors is the same
695+ // as the dot product of the two normal vectors
696+ px = x2 - px;
697+ py = y2 - py;
698+ dotprod = px * x2 + py * y2;
699+ if (dotprod <= 0.0) {
700+ // px,py is on the side of x2,y2 away from x1,y1
701+ // distance to segment is length of (backwards) px,py vector
702+ // "length of its (clipped) projection" is now 0.0
703+ projlenSq = 0.0;
704+ } else {
705+ // px,py is between x1,y1 and x2,y2
706+ // dotprod is the length of the px,py vector
707+ // projected on the x2,y2=>x1,y1 vector times the
708+ // length of the x2,y2=>x1,y1 vector
709+ projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
710+ }
711+ }
712+ // Distance to line is now the length of the relative point
713+ // vector minus the length of its projection onto the line
714+ // (which is zero if the projection falls outside the range
715+ // of the line segment).
716+ double lenSq = px * px + py * py - projlenSq;
717+ if (lenSq < 0) {
718+ lenSq = 0;
719+ }
720+ return lenSq;
721+ }
722+
723+ /**
724+ * Returns the distance from a point to a line segment.
725+ * The distance measured is the distance between the specified
726+ * point and the closest point between the specified end points.
727+ * If the specified point intersects the line segment in between the
728+ * end points, this method returns 0.0.
729+ *
730+ * @param x1 the X coordinate of the start point of the
731+ * specified line segment
732+ * @param y1 the Y coordinate of the start point of the
733+ * specified line segment
734+ * @param x2 the X coordinate of the end point of the
735+ * specified line segment
736+ * @param y2 the Y coordinate of the end point of the
737+ * specified line segment
738+ * @param px the X coordinate of the specified point being
739+ * measured against the specified line segment
740+ * @param py the Y coordinate of the specified point being
741+ * measured against the specified line segment
742+ * @return a double value that is the distance from the specified point
743+ * to the specified line segment.
744+ * @see #ptLineDist(double, double, double, double, double, double)
745+ * @since 1.2
746+ */
747+ public static double ptSegDist(double x1, double y1,
748+ double x2, double y2,
749+ double px, double py)
750+ {
751+ return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py));
752+ }
753+
754+ /**
755+ * Returns the square of the distance from a point to this line segment.
756+ * The distance measured is the distance between the specified
757+ * point and the closest point between the current line's end points.
758+ * If the specified point intersects the line segment in between the
759+ * end points, this method returns 0.0.
760+ *
761+ * @param px the X coordinate of the specified point being
762+ * measured against this line segment
763+ * @param py the Y coordinate of the specified point being
764+ * measured against this line segment
765+ * @return a double value that is the square of the distance from the
766+ * specified point to the current line segment.
767+ * @see #ptLineDistSq(double, double)
768+ * @since 1.2
769+ */
770+ public double ptSegDistSq(double px, double py) {
771+ return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
772+ }
773+
774+ /**
775+ * Returns the square of the distance from a <code>Point2D</code> to
776+ * this line segment.
777+ * The distance measured is the distance between the specified
778+ * point and the closest point between the current line's end points.
779+ * If the specified point intersects the line segment in between the
780+ * end points, this method returns 0.0.
781+ * @param pt the specified <code>Point2D</code> being measured against
782+ * this line segment.
783+ * @return a double value that is the square of the distance from the
784+ * specified <code>Point2D</code> to the current
785+ * line segment.
786+ * @see #ptLineDistSq(Point2D)
787+ * @since 1.2
788+ */
789+ public double ptSegDistSq(Point2D pt) {
790+ return ptSegDistSq(getX1(), getY1(), getX2(), getY2(),
791+ pt.getX(), pt.getY());
792+ }
793+
794+ /**
795+ * Returns the distance from a point to this line segment.
796+ * The distance measured is the distance between the specified
797+ * point and the closest point between the current line's end points.
798+ * If the specified point intersects the line segment in between the
799+ * end points, this method returns 0.0.
800+ *
801+ * @param px the X coordinate of the specified point being
802+ * measured against this line segment
803+ * @param py the Y coordinate of the specified point being
804+ * measured against this line segment
805+ * @return a double value that is the distance from the specified
806+ * point to the current line segment.
807+ * @see #ptLineDist(double, double)
808+ * @since 1.2
809+ */
810+ public double ptSegDist(double px, double py) {
811+ return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py);
812+ }
813+
814+ /**
815+ * Returns the distance from a <code>Point2D</code> to this line
816+ * segment.
817+ * The distance measured is the distance between the specified
818+ * point and the closest point between the current line's end points.
819+ * If the specified point intersects the line segment in between the
820+ * end points, this method returns 0.0.
821+ * @param pt the specified <code>Point2D</code> being measured
822+ * against this line segment
823+ * @return a double value that is the distance from the specified
824+ * <code>Point2D</code> to the current line
825+ * segment.
826+ * @see #ptLineDist(Point2D)
827+ * @since 1.2
828+ */
829+ public double ptSegDist(Point2D pt) {
830+ return ptSegDist(getX1(), getY1(), getX2(), getY2(),
831+ pt.getX(), pt.getY());
832+ }
833+
834+ /**
835+ * Returns the square of the distance from a point to a line.
836+ * The distance measured is the distance between the specified
837+ * point and the closest point on the infinitely-extended line
838+ * defined by the specified coordinates. If the specified point
839+ * intersects the line, this method returns 0.0.
840+ *
841+ * @param x1 the X coordinate of the start point of the specified line
842+ * @param y1 the Y coordinate of the start point of the specified line
843+ * @param x2 the X coordinate of the end point of the specified line
844+ * @param y2 the Y coordinate of the end point of the specified line
845+ * @param px the X coordinate of the specified point being
846+ * measured against the specified line
847+ * @param py the Y coordinate of the specified point being
848+ * measured against the specified line
849+ * @return a double value that is the square of the distance from the
850+ * specified point to the specified line.
851+ * @see #ptSegDistSq(double, double, double, double, double, double)
852+ * @since 1.2
853+ */
854+ public static double ptLineDistSq(double x1, double y1,
855+ double x2, double y2,
856+ double px, double py)
857+ {
858+ // Adjust vectors relative to x1,y1
859+ // x2,y2 becomes relative vector from x1,y1 to end of segment
860+ x2 -= x1;
861+ y2 -= y1;
862+ // px,py becomes relative vector from x1,y1 to test point
863+ px -= x1;
864+ py -= y1;
865+ double dotprod = px * x2 + py * y2;
866+ // dotprod is the length of the px,py vector
867+ // projected on the x1,y1=>x2,y2 vector times the
868+ // length of the x1,y1=>x2,y2 vector
869+ double projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
870+ // Distance to line is now the length of the relative point
871+ // vector minus the length of its projection onto the line
872+ double lenSq = px * px + py * py - projlenSq;
873+ if (lenSq < 0) {
874+ lenSq = 0;
875+ }
876+ return lenSq;
877+ }
878+
879+ /**
880+ * Returns the distance from a point to a line.
881+ * The distance measured is the distance between the specified
882+ * point and the closest point on the infinitely-extended line
883+ * defined by the specified coordinates. If the specified point
884+ * intersects the line, this method returns 0.0.
885+ *
886+ * @param x1 the X coordinate of the start point of the specified line
887+ * @param y1 the Y coordinate of the start point of the specified line
888+ * @param x2 the X coordinate of the end point of the specified line
889+ * @param y2 the Y coordinate of the end point of the specified line
890+ * @param px the X coordinate of the specified point being
891+ * measured against the specified line
892+ * @param py the Y coordinate of the specified point being
893+ * measured against the specified line
894+ * @return a double value that is the distance from the specified
895+ * point to the specified line.
896+ * @see #ptSegDist(double, double, double, double, double, double)
897+ * @since 1.2
898+ */
899+ public static double ptLineDist(double x1, double y1,
900+ double x2, double y2,
901+ double px, double py)
902+ {
903+ return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py));
904+ }
905+
906+ /**
907+ * Returns the square of the distance from a point to this line.
908+ * The distance measured is the distance between the specified
909+ * point and the closest point on the infinitely-extended line
910+ * defined by this <code>Line2D</code>. If the specified point
911+ * intersects the line, this method returns 0.0.
912+ *
913+ * @param px the X coordinate of the specified point being
914+ * measured against this line
915+ * @param py the Y coordinate of the specified point being
916+ * measured against this line
917+ * @return a double value that is the square of the distance from a
918+ * specified point to the current line.
919+ * @see #ptSegDistSq(double, double)
920+ * @since 1.2
921+ */
922+ public double ptLineDistSq(double px, double py) {
923+ return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
924+ }
925+
926+ /**
927+ * Returns the square of the distance from a specified
928+ * <code>Point2D</code> to this line.
929+ * The distance measured is the distance between the specified
930+ * point and the closest point on the infinitely-extended line
931+ * defined by this <code>Line2D</code>. If the specified point
932+ * intersects the line, this method returns 0.0.
933+ * @param pt the specified <code>Point2D</code> being measured
934+ * against this line
935+ * @return a double value that is the square of the distance from a
936+ * specified <code>Point2D</code> to the current
937+ * line.
938+ * @see #ptSegDistSq(Point2D)
939+ * @since 1.2
940+ */
941+ public double ptLineDistSq(Point2D pt) {
942+ return ptLineDistSq(getX1(), getY1(), getX2(), getY2(),
943+ pt.getX(), pt.getY());
944+ }
945+
946+ /**
947+ * Returns the distance from a point to this line.
948+ * The distance measured is the distance between the specified
949+ * point and the closest point on the infinitely-extended line
950+ * defined by this <code>Line2D</code>. If the specified point
951+ * intersects the line, this method returns 0.0.
952+ *
953+ * @param px the X coordinate of the specified point being
954+ * measured against this line
955+ * @param py the Y coordinate of the specified point being
956+ * measured against this line
957+ * @return a double value that is the distance from a specified point
958+ * to the current line.
959+ * @see #ptSegDist(double, double)
960+ * @since 1.2
961+ */
962+ public double ptLineDist(double px, double py) {
963+ return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py);
964+ }
965+
966+ /**
967+ * Returns the distance from a <code>Point2D</code> to this line.
968+ * The distance measured is the distance between the specified
969+ * point and the closest point on the infinitely-extended line
970+ * defined by this <code>Line2D</code>. If the specified point
971+ * intersects the line, this method returns 0.0.
972+ * @param pt the specified <code>Point2D</code> being measured
973+ * @return a double value that is the distance from a specified
974+ * <code>Point2D</code> to the current line.
975+ * @see #ptSegDist(Point2D)
976+ * @since 1.2
977+ */
978+ public double ptLineDist(Point2D pt) {
979+ return ptLineDist(getX1(), getY1(), getX2(), getY2(),
980+ pt.getX(), pt.getY());
981+ }
982+
983+ /**
984+ * Tests if a specified coordinate is inside the boundary of this
985+ * <code>Line2D</code>. This method is required to implement the
986+ * {@link Shape} interface, but in the case of <code>Line2D</code>
987+ * objects it always returns <code>false</code> since a line contains
988+ * no area.
989+ * @param x the X coordinate of the specified point to be tested
990+ * @param y the Y coordinate of the specified point to be tested
991+ * @return <code>false</code> because a <code>Line2D</code> contains
992+ * no area.
993+ * @since 1.2
994+ */
995+ public boolean contains(double x, double y) {
996+ return false;
997+ }
998+
999+ /**
1000+ * Tests if a given <code>Point2D</code> is inside the boundary of
1001+ * this <code>Line2D</code>.
1002+ * This method is required to implement the {@link Shape} interface,
1003+ * but in the case of <code>Line2D</code> objects it always returns
1004+ * <code>false</code> since a line contains no area.
1005+ * @param p the specified <code>Point2D</code> to be tested
1006+ * @return <code>false</code> because a <code>Line2D</code> contains
1007+ * no area.
1008+ * @since 1.2
1009+ */
1010+ public boolean contains(Point2D p) {
1011+ return false;
1012+ }
1013+
1014+ /**
1015+ * {@inheritDoc}
1016+ * @since 1.2
1017+ */
1018+ public boolean intersects(double x, double y, double w, double h) {
1019+ return intersects(new Rectangle2D.Double(x, y, w, h));
1020+ }
1021+
1022+ /**
1023+ * {@inheritDoc}
1024+ * @since 1.2
1025+ */
1026+ public boolean intersects(Rectangle2D r) {
1027+ return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
1028+ }
1029+
1030+ /**
1031+ * Tests if the interior of this <code>Line2D</code> entirely contains
1032+ * the specified set of rectangular coordinates.
1033+ * This method is required to implement the <code>Shape</code> interface,
1034+ * but in the case of <code>Line2D</code> objects it always returns
1035+ * false since a line contains no area.
1036+ * @param x the X coordinate of the upper-left corner of the
1037+ * specified rectangular area
1038+ * @param y the Y coordinate of the upper-left corner of the
1039+ * specified rectangular area
1040+ * @param w the width of the specified rectangular area
1041+ * @param h the height of the specified rectangular area
1042+ * @return <code>false</code> because a <code>Line2D</code> contains
1043+ * no area.
1044+ * @since 1.2
1045+ */
1046+ public boolean contains(double x, double y, double w, double h) {
1047+ return false;
1048+ }
1049+
1050+ /**
1051+ * Tests if the interior of this <code>Line2D</code> entirely contains
1052+ * the specified <code>Rectangle2D</code>.
1053+ * This method is required to implement the <code>Shape</code> interface,
1054+ * but in the case of <code>Line2D</code> objects it always returns
1055+ * <code>false</code> since a line contains no area.
1056+ * @param r the specified <code>Rectangle2D</code> to be tested
1057+ * @return <code>false</code> because a <code>Line2D</code> contains
1058+ * no area.
1059+ * @since 1.2
1060+ */
1061+ public boolean contains(Rectangle2D r) {
1062+ return false;
1063+ }
1064+
1065+ /**
1066+ * {@inheritDoc}
1067+ * @since 1.2
1068+ */
1069+ public Rectangle getBounds() {
1070+ return getBounds2D().getBounds();
1071+ }
1072+
1073+ /**
1074+ * Returns an iteration object that defines the boundary of this
1075+ * <code>Line2D</code>.
1076+ * The iterator for this class is not multi-threaded safe,
1077+ * which means that this <code>Line2D</code> class does not
1078+ * guarantee that modifications to the geometry of this
1079+ * <code>Line2D</code> object do not affect any iterations of that
1080+ * geometry that are already in process.
1081+ * @param at the specified {@link AffineTransform}
1082+ * @return a {@link PathIterator} that defines the boundary of this
1083+ * <code>Line2D</code>.
1084+ * @since 1.2
1085+ */
1086+ public PathIterator getPathIterator(AffineTransform at) {
1087+ return new LineIterator(this, at);
1088+ }
1089+
1090+ /**
1091+ * Returns an iteration object that defines the boundary of this
1092+ * flattened <code>Line2D</code>.
1093+ * The iterator for this class is not multi-threaded safe,
1094+ * which means that this <code>Line2D</code> class does not
1095+ * guarantee that modifications to the geometry of this
1096+ * <code>Line2D</code> object do not affect any iterations of that
1097+ * geometry that are already in process.
1098+ * @param at the specified <code>AffineTransform</code>
1099+ * @param flatness the maximum amount that the control points for a
1100+ * given curve can vary from colinear before a subdivided
1101+ * curve is replaced by a straight line connecting the
1102+ * end points. Since a <code>Line2D</code> object is
1103+ * always flat, this parameter is ignored.
1104+ * @return a <code>PathIterator</code> that defines the boundary of the
1105+ * flattened <code>Line2D</code>
1106+ * @since 1.2
1107+ */
1108+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
1109+ return new LineIterator(this, at);
1110+ }
1111+
1112+ /**
1113+ * Creates a new object of the same class as this object.
1114+ *
1115+ * @return a clone of this instance.
1116+ * @exception OutOfMemoryError if there is not enough memory.
1117+ * @see java.lang.Cloneable
1118+ * @since 1.2
1119+ */
1120+ public Object clone() {
1121+ try {
1122+ return super.clone();
1123+ } catch (CloneNotSupportedException e) {
1124+ // this shouldn't happen, since we are Cloneable
1125+ throw new InternalError();
1126+ }
1127+ }
1128+}
java/pkg/java/awt/geom/LineIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/LineIterator.java+148−0
@@ -0,0 +1,148 @@
1+/*
2+ * Copyright (c) 1997, 1999, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of a line segment
32+ * through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class LineIterator implements PathIterator {
37+ Line2D line;
38+ AffineTransform affine;
39+ int index;
40+
41+ LineIterator(Line2D l, AffineTransform at) {
42+ this.line = l;
43+ this.affine = at;
44+ }
45+
46+ /**
47+ * Return the winding rule for determining the insideness of the
48+ * path.
49+ * @see #WIND_EVEN_ODD
50+ * @see #WIND_NON_ZERO
51+ */
52+ public int getWindingRule() {
53+ return WIND_NON_ZERO;
54+ }
55+
56+ /**
57+ * Tests if there are more points to read.
58+ * @return true if there are more points to read
59+ */
60+ public boolean isDone() {
61+ return (index > 1);
62+ }
63+
64+ /**
65+ * Moves the iterator to the next segment of the path forwards
66+ * along the primary direction of traversal as long as there are
67+ * more points in that direction.
68+ */
69+ public void next() {
70+ index++;
71+ }
72+
73+ /**
74+ * Returns the coordinates and type of the current path segment in
75+ * the iteration.
76+ * The return value is the path segment type:
77+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
78+ * A float array of length 6 must be passed in and may be used to
79+ * store the coordinates of the point(s).
80+ * Each point is stored as a pair of float x,y coordinates.
81+ * SEG_MOVETO and SEG_LINETO types will return one point,
82+ * SEG_QUADTO will return two points,
83+ * SEG_CUBICTO will return 3 points
84+ * and SEG_CLOSE will not return any points.
85+ * @see #SEG_MOVETO
86+ * @see #SEG_LINETO
87+ * @see #SEG_QUADTO
88+ * @see #SEG_CUBICTO
89+ * @see #SEG_CLOSE
90+ */
91+ public int currentSegment(float[] coords) {
92+ if (isDone()) {
93+ throw new NoSuchElementException("line iterator out of bounds");
94+ }
95+ int type;
96+ if (index == 0) {
97+ coords[0] = (float) line.getX1();
98+ coords[1] = (float) line.getY1();
99+ type = SEG_MOVETO;
100+ } else {
101+ coords[0] = (float) line.getX2();
102+ coords[1] = (float) line.getY2();
103+ type = SEG_LINETO;
104+ }
105+ if (affine != null) {
106+ affine.transform(coords, 0, coords, 0, 1);
107+ }
108+ return type;
109+ }
110+
111+ /**
112+ * Returns the coordinates and type of the current path segment in
113+ * the iteration.
114+ * The return value is the path segment type:
115+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
116+ * A double array of length 6 must be passed in and may be used to
117+ * store the coordinates of the point(s).
118+ * Each point is stored as a pair of double x,y coordinates.
119+ * SEG_MOVETO and SEG_LINETO types will return one point,
120+ * SEG_QUADTO will return two points,
121+ * SEG_CUBICTO will return 3 points
122+ * and SEG_CLOSE will not return any points.
123+ * @see #SEG_MOVETO
124+ * @see #SEG_LINETO
125+ * @see #SEG_QUADTO
126+ * @see #SEG_CUBICTO
127+ * @see #SEG_CLOSE
128+ */
129+ public int currentSegment(double[] coords) {
130+ if (isDone()) {
131+ throw new NoSuchElementException("line iterator out of bounds");
132+ }
133+ int type;
134+ if (index == 0) {
135+ coords[0] = line.getX1();
136+ coords[1] = line.getY1();
137+ type = SEG_MOVETO;
138+ } else {
139+ coords[0] = line.getX2();
140+ coords[1] = line.getY2();
141+ type = SEG_LINETO;
142+ }
143+ if (affine != null) {
144+ affine.transform(coords, 0, coords, 0, 1);
145+ }
146+ return type;
147+ }
148+}
java/pkg/java/awt/geom/NoninvertibleTransformException.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/NoninvertibleTransformException.java+46−0
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (c) 1997, 1999, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+/**
29+ * The <code>NoninvertibleTransformException</code> class represents
30+ * an exception that is thrown if an operation is performed requiring
31+ * the inverse of an {@link AffineTransform} object but the
32+ * <code>AffineTransform</code> is in a non-invertible state.
33+ */
34+
35+public class NoninvertibleTransformException extends java.lang.Exception {
36+ /**
37+ * Constructs an instance of
38+ * <code>NoninvertibleTransformException</code>
39+ * with the specified detail message.
40+ * @param s the detail message
41+ * @since 1.2
42+ */
43+ public NoninvertibleTransformException(String s) {
44+ super (s);
45+ }
46+}
java/pkg/java/awt/geom/Path2D$Double$CopyIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D$Double$TxIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D$Float$CopyIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D$Float$TxIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D$Iterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Path2D.java+2595−0
@@ -0,0 +1,2595 @@
1+/*
2+ * Copyright (c) 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.awt.Rectangle;
30+import sun.awt.geom.Curve;
31+import java.io.Serializable;
32+import java.io.StreamCorruptedException;
33+import java.util.Arrays;
34+
35+/**
36+ * The {@code Path2D} class provides a simple, yet flexible
37+ * shape which represents an arbitrary geometric path.
38+ * It can fully represent any path which can be iterated by the
39+ * {@link PathIterator} interface including all of its segment
40+ * types and winding rules and it implements all of the
41+ * basic hit testing methods of the {@link Shape} interface.
42+ * <p>
43+ * Use {@link Path2D.Float} when dealing with data that can be represented
44+ * and used with floating point precision. Use {@link Path2D.Double}
45+ * for data that requires the accuracy or range of double precision.
46+ * <p>
47+ * {@code Path2D} provides exactly those facilities required for
48+ * basic construction and management of a geometric path and
49+ * implementation of the above interfaces with little added
50+ * interpretation.
51+ * If it is useful to manipulate the interiors of closed
52+ * geometric shapes beyond simple hit testing then the
53+ * {@link Area} class provides additional capabilities
54+ * specifically targeted at closed figures.
55+ * While both classes nominally implement the {@code Shape}
56+ * interface, they differ in purpose and together they provide
57+ * two useful views of a geometric shape where {@code Path2D}
58+ * deals primarily with a trajectory formed by path segments
59+ * and {@code Area} deals more with interpretation and manipulation
60+ * of enclosed regions of 2D geometric space.
61+ * <p>
62+ * The {@link PathIterator} interface has more detailed descriptions
63+ * of the types of segments that make up a path and the winding rules
64+ * that control how to determine which regions are inside or outside
65+ * the path.
66+ *
67+ * @author Jim Graham
68+ * @since 1.6
69+ */
70+public abstract class Path2D implements Shape, Cloneable {
71+ /**
72+ * An even-odd winding rule for determining the interior of
73+ * a path.
74+ *
75+ * @see PathIterator#WIND_EVEN_ODD
76+ * @since 1.6
77+ */
78+ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
79+
80+ /**
81+ * A non-zero winding rule for determining the interior of a
82+ * path.
83+ *
84+ * @see PathIterator#WIND_NON_ZERO
85+ * @since 1.6
86+ */
87+ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
88+
89+ // For code simplicity, copy these constants to our namespace
90+ // and cast them to byte constants for easy storage.
91+ private static final byte SEG_MOVETO = (byte) PathIterator.SEG_MOVETO;
92+ private static final byte SEG_LINETO = (byte) PathIterator.SEG_LINETO;
93+ private static final byte SEG_QUADTO = (byte) PathIterator.SEG_QUADTO;
94+ private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO;
95+ private static final byte SEG_CLOSE = (byte) PathIterator.SEG_CLOSE;
96+
97+ transient byte[] pointTypes;
98+ transient int numTypes;
99+ transient int numCoords;
100+ transient int windingRule;
101+
102+ static final int INIT_SIZE = 20;
103+ static final int EXPAND_MAX = 500;
104+
105+ /**
106+ * Constructs a new empty {@code Path2D} object.
107+ * It is assumed that the package sibling subclass that is
108+ * defaulting to this constructor will fill in all values.
109+ *
110+ * @since 1.6
111+ */
112+ /* private protected */
113+ Path2D() {
114+ }
115+
116+ /**
117+ * Constructs a new {@code Path2D} object from the given
118+ * specified initial values.
119+ * This method is only intended for internal use and should
120+ * not be made public if the other constructors for this class
121+ * are ever exposed.
122+ *
123+ * @param rule the winding rule
124+ * @param initialTypes the size to make the initial array to
125+ * store the path segment types
126+ * @since 1.6
127+ */
128+ /* private protected */
129+ Path2D(int rule, int initialTypes) {
130+ setWindingRule(rule);
131+ this.pointTypes = new byte[initialTypes];
132+ }
133+
134+ abstract float[] cloneCoordsFloat(AffineTransform at);
135+ abstract double[] cloneCoordsDouble(AffineTransform at);
136+ abstract void append(float x, float y);
137+ abstract void append(double x, double y);
138+ abstract Point2D getPoint(int coordindex);
139+ abstract void needRoom(boolean needMove, int newCoords);
140+ abstract int pointCrossings(double px, double py);
141+ abstract int rectCrossings(double rxmin, double rymin,
142+ double rxmax, double rymax);
143+
144+ /**
145+ * The {@code Float} class defines a geometric path with
146+ * coordinates stored in single precision floating point.
147+ *
148+ * @since 1.6
149+ */
150+ public static class Float extends Path2D implements Serializable {
151+ transient float floatCoords[];
152+
153+ /**
154+ * Constructs a new empty single precision {@code Path2D} object
155+ * with a default winding rule of {@link #WIND_NON_ZERO}.
156+ *
157+ * @since 1.6
158+ */
159+ public Float() {
160+ this(WIND_NON_ZERO, INIT_SIZE);
161+ }
162+
163+ /**
164+ * Constructs a new empty single precision {@code Path2D} object
165+ * with the specified winding rule to control operations that
166+ * require the interior of the path to be defined.
167+ *
168+ * @param rule the winding rule
169+ * @see #WIND_EVEN_ODD
170+ * @see #WIND_NON_ZERO
171+ * @since 1.6
172+ */
173+ public Float(int rule) {
174+ this(rule, INIT_SIZE);
175+ }
176+
177+ /**
178+ * Constructs a new empty single precision {@code Path2D} object
179+ * with the specified winding rule and the specified initial
180+ * capacity to store path segments.
181+ * This number is an initial guess as to how many path segments
182+ * will be added to the path, but the storage is expanded as
183+ * needed to store whatever path segments are added.
184+ *
185+ * @param rule the winding rule
186+ * @param initialCapacity the estimate for the number of path segments
187+ * in the path
188+ * @see #WIND_EVEN_ODD
189+ * @see #WIND_NON_ZERO
190+ * @since 1.6
191+ */
192+ public Float(int rule, int initialCapacity) {
193+ super(rule, initialCapacity);
194+ floatCoords = new float[initialCapacity * 2];
195+ }
196+
197+ /**
198+ * Constructs a new single precision {@code Path2D} object
199+ * from an arbitrary {@link Shape} object.
200+ * All of the initial geometry and the winding rule for this path are
201+ * taken from the specified {@code Shape} object.
202+ *
203+ * @param s the specified {@code Shape} object
204+ * @since 1.6
205+ */
206+ public Float(Shape s) {
207+ this(s, null);
208+ }
209+
210+ /**
211+ * Constructs a new single precision {@code Path2D} object
212+ * from an arbitrary {@link Shape} object, transformed by an
213+ * {@link AffineTransform} object.
214+ * All of the initial geometry and the winding rule for this path are
215+ * taken from the specified {@code Shape} object and transformed
216+ * by the specified {@code AffineTransform} object.
217+ *
218+ * @param s the specified {@code Shape} object
219+ * @param at the specified {@code AffineTransform} object
220+ * @since 1.6
221+ */
222+ public Float(Shape s, AffineTransform at) {
223+ if (s instanceof Path2D) {
224+ Path2D p2d = (Path2D) s;
225+ setWindingRule(p2d.windingRule);
226+ this.numTypes = p2d.numTypes;
227+ this.pointTypes = Arrays.copyOf(p2d.pointTypes,
228+ p2d.pointTypes.length);
229+ this.numCoords = p2d.numCoords;
230+ this.floatCoords = p2d.cloneCoordsFloat(at);
231+ } else {
232+ PathIterator pi = s.getPathIterator(at);
233+ setWindingRule(pi.getWindingRule());
234+ this.pointTypes = new byte[INIT_SIZE];
235+ this.floatCoords = new float[INIT_SIZE * 2];
236+ append(pi, false);
237+ }
238+ }
239+
240+ float[] cloneCoordsFloat(AffineTransform at) {
241+ float ret[];
242+ if (at == null) {
243+ ret = Arrays.copyOf(this.floatCoords, this.floatCoords.length);
244+ } else {
245+ ret = new float[floatCoords.length];
246+ at.transform(floatCoords, 0, ret, 0, numCoords / 2);
247+ }
248+ return ret;
249+ }
250+
251+ double[] cloneCoordsDouble(AffineTransform at) {
252+ double ret[] = new double[floatCoords.length];
253+ if (at == null) {
254+ for (int i = 0; i < numCoords; i++) {
255+ ret[i] = floatCoords[i];
256+ }
257+ } else {
258+ at.transform(floatCoords, 0, ret, 0, numCoords / 2);
259+ }
260+ return ret;
261+ }
262+
263+ void append(float x, float y) {
264+ floatCoords[numCoords++] = x;
265+ floatCoords[numCoords++] = y;
266+ }
267+
268+ void append(double x, double y) {
269+ floatCoords[numCoords++] = (float) x;
270+ floatCoords[numCoords++] = (float) y;
271+ }
272+
273+ Point2D getPoint(int coordindex) {
274+ return new Point2D.Float(floatCoords[coordindex],
275+ floatCoords[coordindex+1]);
276+ }
277+
278+ void needRoom(boolean needMove, int newCoords) {
279+ if (needMove && numTypes == 0) {
280+ throw new IllegalPathStateException("missing initial moveto "+
281+ "in path definition");
282+ }
283+ int size = pointTypes.length;
284+ if (numTypes >= size) {
285+ int grow = size;
286+ if (grow > EXPAND_MAX) {
287+ grow = EXPAND_MAX;
288+ }
289+ pointTypes = Arrays.copyOf(pointTypes, size+grow);
290+ }
291+ size = floatCoords.length;
292+ if (numCoords + newCoords > size) {
293+ int grow = size;
294+ if (grow > EXPAND_MAX * 2) {
295+ grow = EXPAND_MAX * 2;
296+ }
297+ if (grow < newCoords) {
298+ grow = newCoords;
299+ }
300+ floatCoords = Arrays.copyOf(floatCoords, size+grow);
301+ }
302+ }
303+
304+ /**
305+ * {@inheritDoc}
306+ * @since 1.6
307+ */
308+ public final synchronized void moveTo(double x, double y) {
309+ if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
310+ floatCoords[numCoords-2] = (float) x;
311+ floatCoords[numCoords-1] = (float) y;
312+ } else {
313+ needRoom(false, 2);
314+ pointTypes[numTypes++] = SEG_MOVETO;
315+ floatCoords[numCoords++] = (float) x;
316+ floatCoords[numCoords++] = (float) y;
317+ }
318+ }
319+
320+ /**
321+ * Adds a point to the path by moving to the specified
322+ * coordinates specified in float precision.
323+ * <p>
324+ * This method provides a single precision variant of
325+ * the double precision {@code moveTo()} method on the
326+ * base {@code Path2D} class.
327+ *
328+ * @param x the specified X coordinate
329+ * @param y the specified Y coordinate
330+ * @see Path2D#moveTo
331+ * @since 1.6
332+ */
333+ public final synchronized void moveTo(float x, float y) {
334+ if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
335+ floatCoords[numCoords-2] = x;
336+ floatCoords[numCoords-1] = y;
337+ } else {
338+ needRoom(false, 2);
339+ pointTypes[numTypes++] = SEG_MOVETO;
340+ floatCoords[numCoords++] = x;
341+ floatCoords[numCoords++] = y;
342+ }
343+ }
344+
345+ /**
346+ * {@inheritDoc}
347+ * @since 1.6
348+ */
349+ public final synchronized void lineTo(double x, double y) {
350+ needRoom(true, 2);
351+ pointTypes[numTypes++] = SEG_LINETO;
352+ floatCoords[numCoords++] = (float) x;
353+ floatCoords[numCoords++] = (float) y;
354+ }
355+
356+ /**
357+ * Adds a point to the path by drawing a straight line from the
358+ * current coordinates to the new specified coordinates
359+ * specified in float precision.
360+ * <p>
361+ * This method provides a single precision variant of
362+ * the double precision {@code lineTo()} method on the
363+ * base {@code Path2D} class.
364+ *
365+ * @param x the specified X coordinate
366+ * @param y the specified Y coordinate
367+ * @see Path2D#lineTo
368+ * @since 1.6
369+ */
370+ public final synchronized void lineTo(float x, float y) {
371+ needRoom(true, 2);
372+ pointTypes[numTypes++] = SEG_LINETO;
373+ floatCoords[numCoords++] = x;
374+ floatCoords[numCoords++] = y;
375+ }
376+
377+ /**
378+ * {@inheritDoc}
379+ * @since 1.6
380+ */
381+ public final synchronized void quadTo(double x1, double y1,
382+ double x2, double y2)
383+ {
384+ needRoom(true, 4);
385+ pointTypes[numTypes++] = SEG_QUADTO;
386+ floatCoords[numCoords++] = (float) x1;
387+ floatCoords[numCoords++] = (float) y1;
388+ floatCoords[numCoords++] = (float) x2;
389+ floatCoords[numCoords++] = (float) y2;
390+ }
391+
392+ /**
393+ * Adds a curved segment, defined by two new points, to the path by
394+ * drawing a Quadratic curve that intersects both the current
395+ * coordinates and the specified coordinates {@code (x2,y2)},
396+ * using the specified point {@code (x1,y1)} as a quadratic
397+ * parametric control point.
398+ * All coordinates are specified in float precision.
399+ * <p>
400+ * This method provides a single precision variant of
401+ * the double precision {@code quadTo()} method on the
402+ * base {@code Path2D} class.
403+ *
404+ * @param x1 the X coordinate of the quadratic control point
405+ * @param y1 the Y coordinate of the quadratic control point
406+ * @param x2 the X coordinate of the final end point
407+ * @param y2 the Y coordinate of the final end point
408+ * @see Path2D#quadTo
409+ * @since 1.6
410+ */
411+ public final synchronized void quadTo(float x1, float y1,
412+ float x2, float y2)
413+ {
414+ needRoom(true, 4);
415+ pointTypes[numTypes++] = SEG_QUADTO;
416+ floatCoords[numCoords++] = x1;
417+ floatCoords[numCoords++] = y1;
418+ floatCoords[numCoords++] = x2;
419+ floatCoords[numCoords++] = y2;
420+ }
421+
422+ /**
423+ * {@inheritDoc}
424+ * @since 1.6
425+ */
426+ public final synchronized void curveTo(double x1, double y1,
427+ double x2, double y2,
428+ double x3, double y3)
429+ {
430+ needRoom(true, 6);
431+ pointTypes[numTypes++] = SEG_CUBICTO;
432+ floatCoords[numCoords++] = (float) x1;
433+ floatCoords[numCoords++] = (float) y1;
434+ floatCoords[numCoords++] = (float) x2;
435+ floatCoords[numCoords++] = (float) y2;
436+ floatCoords[numCoords++] = (float) x3;
437+ floatCoords[numCoords++] = (float) y3;
438+ }
439+
440+ /**
441+ * Adds a curved segment, defined by three new points, to the path by
442+ * drawing a B&eacute;zier curve that intersects both the current
443+ * coordinates and the specified coordinates {@code (x3,y3)},
444+ * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
445+ * B&eacute;zier control points.
446+ * All coordinates are specified in float precision.
447+ * <p>
448+ * This method provides a single precision variant of
449+ * the double precision {@code curveTo()} method on the
450+ * base {@code Path2D} class.
451+ *
452+ * @param x1 the X coordinate of the first B&eacute;zier control point
453+ * @param y1 the Y coordinate of the first B&eacute;zier control point
454+ * @param x2 the X coordinate of the second B&eacute;zier control point
455+ * @param y2 the Y coordinate of the second B&eacute;zier control point
456+ * @param x3 the X coordinate of the final end point
457+ * @param y3 the Y coordinate of the final end point
458+ * @see Path2D#curveTo
459+ * @since 1.6
460+ */
461+ public final synchronized void curveTo(float x1, float y1,
462+ float x2, float y2,
463+ float x3, float y3)
464+ {
465+ needRoom(true, 6);
466+ pointTypes[numTypes++] = SEG_CUBICTO;
467+ floatCoords[numCoords++] = x1;
468+ floatCoords[numCoords++] = y1;
469+ floatCoords[numCoords++] = x2;
470+ floatCoords[numCoords++] = y2;
471+ floatCoords[numCoords++] = x3;
472+ floatCoords[numCoords++] = y3;
473+ }
474+
475+ int pointCrossings(double px, double py) {
476+ double movx, movy, curx, cury, endx, endy;
477+ float coords[] = floatCoords;
478+ curx = movx = coords[0];
479+ cury = movy = coords[1];
480+ int crossings = 0;
481+ int ci = 2;
482+ for (int i = 1; i < numTypes; i++) {
483+ switch (pointTypes[i]) {
484+ case PathIterator.SEG_MOVETO:
485+ if (cury != movy) {
486+ crossings +=
487+ Curve.pointCrossingsForLine(px, py,
488+ curx, cury,
489+ movx, movy);
490+ }
491+ movx = curx = coords[ci++];
492+ movy = cury = coords[ci++];
493+ break;
494+ case PathIterator.SEG_LINETO:
495+ crossings +=
496+ Curve.pointCrossingsForLine(px, py,
497+ curx, cury,
498+ endx = coords[ci++],
499+ endy = coords[ci++]);
500+ curx = endx;
501+ cury = endy;
502+ break;
503+ case PathIterator.SEG_QUADTO:
504+ crossings +=
505+ Curve.pointCrossingsForQuad(px, py,
506+ curx, cury,
507+ coords[ci++],
508+ coords[ci++],
509+ endx = coords[ci++],
510+ endy = coords[ci++],
511+ 0);
512+ curx = endx;
513+ cury = endy;
514+ break;
515+ case PathIterator.SEG_CUBICTO:
516+ crossings +=
517+ Curve.pointCrossingsForCubic(px, py,
518+ curx, cury,
519+ coords[ci++],
520+ coords[ci++],
521+ coords[ci++],
522+ coords[ci++],
523+ endx = coords[ci++],
524+ endy = coords[ci++],
525+ 0);
526+ curx = endx;
527+ cury = endy;
528+ break;
529+ case PathIterator.SEG_CLOSE:
530+ if (cury != movy) {
531+ crossings +=
532+ Curve.pointCrossingsForLine(px, py,
533+ curx, cury,
534+ movx, movy);
535+ }
536+ curx = movx;
537+ cury = movy;
538+ break;
539+ }
540+ }
541+ if (cury != movy) {
542+ crossings +=
543+ Curve.pointCrossingsForLine(px, py,
544+ curx, cury,
545+ movx, movy);
546+ }
547+ return crossings;
548+ }
549+
550+ int rectCrossings(double rxmin, double rymin,
551+ double rxmax, double rymax)
552+ {
553+ float coords[] = floatCoords;
554+ double curx, cury, movx, movy, endx, endy;
555+ curx = movx = coords[0];
556+ cury = movy = coords[1];
557+ int crossings = 0;
558+ int ci = 2;
559+ for (int i = 1;
560+ crossings != Curve.RECT_INTERSECTS && i < numTypes;
561+ i++)
562+ {
563+ switch (pointTypes[i]) {
564+ case PathIterator.SEG_MOVETO:
565+ if (curx != movx || cury != movy) {
566+ crossings =
567+ Curve.rectCrossingsForLine(crossings,
568+ rxmin, rymin,
569+ rxmax, rymax,
570+ curx, cury,
571+ movx, movy);
572+ }
573+ // Count should always be a multiple of 2 here.
574+ // assert((crossings & 1) != 0);
575+ movx = curx = coords[ci++];
576+ movy = cury = coords[ci++];
577+ break;
578+ case PathIterator.SEG_LINETO:
579+ crossings =
580+ Curve.rectCrossingsForLine(crossings,
581+ rxmin, rymin,
582+ rxmax, rymax,
583+ curx, cury,
584+ endx = coords[ci++],
585+ endy = coords[ci++]);
586+ curx = endx;
587+ cury = endy;
588+ break;
589+ case PathIterator.SEG_QUADTO:
590+ crossings =
591+ Curve.rectCrossingsForQuad(crossings,
592+ rxmin, rymin,
593+ rxmax, rymax,
594+ curx, cury,
595+ coords[ci++],
596+ coords[ci++],
597+ endx = coords[ci++],
598+ endy = coords[ci++],
599+ 0);
600+ curx = endx;
601+ cury = endy;
602+ break;
603+ case PathIterator.SEG_CUBICTO:
604+ crossings =
605+ Curve.rectCrossingsForCubic(crossings,
606+ rxmin, rymin,
607+ rxmax, rymax,
608+ curx, cury,
609+ coords[ci++],
610+ coords[ci++],
611+ coords[ci++],
612+ coords[ci++],
613+ endx = coords[ci++],
614+ endy = coords[ci++],
615+ 0);
616+ curx = endx;
617+ cury = endy;
618+ break;
619+ case PathIterator.SEG_CLOSE:
620+ if (curx != movx || cury != movy) {
621+ crossings =
622+ Curve.rectCrossingsForLine(crossings,
623+ rxmin, rymin,
624+ rxmax, rymax,
625+ curx, cury,
626+ movx, movy);
627+ }
628+ curx = movx;
629+ cury = movy;
630+ // Count should always be a multiple of 2 here.
631+ // assert((crossings & 1) != 0);
632+ break;
633+ }
634+ }
635+ if (crossings != Curve.RECT_INTERSECTS &&
636+ (curx != movx || cury != movy))
637+ {
638+ crossings =
639+ Curve.rectCrossingsForLine(crossings,
640+ rxmin, rymin,
641+ rxmax, rymax,
642+ curx, cury,
643+ movx, movy);
644+ }
645+ // Count should always be a multiple of 2 here.
646+ // assert((crossings & 1) != 0);
647+ return crossings;
648+ }
649+
650+ /**
651+ * {@inheritDoc}
652+ * @since 1.6
653+ */
654+ public final void append(PathIterator pi, boolean connect) {
655+ float coords[] = new float[6];
656+ while (!pi.isDone()) {
657+ switch (pi.currentSegment(coords)) {
658+ case SEG_MOVETO:
659+ if (!connect || numTypes < 1 || numCoords < 1) {
660+ moveTo(coords[0], coords[1]);
661+ break;
662+ }
663+ if (pointTypes[numTypes - 1] != SEG_CLOSE &&
664+ floatCoords[numCoords-2] == coords[0] &&
665+ floatCoords[numCoords-1] == coords[1])
666+ {
667+ // Collapse out initial moveto/lineto
668+ break;
669+ }
670+ // NO BREAK;
671+ case SEG_LINETO:
672+ lineTo(coords[0], coords[1]);
673+ break;
674+ case SEG_QUADTO:
675+ quadTo(coords[0], coords[1],
676+ coords[2], coords[3]);
677+ break;
678+ case SEG_CUBICTO:
679+ curveTo(coords[0], coords[1],
680+ coords[2], coords[3],
681+ coords[4], coords[5]);
682+ break;
683+ case SEG_CLOSE:
684+ closePath();
685+ break;
686+ }
687+ pi.next();
688+ connect = false;
689+ }
690+ }
691+
692+ /**
693+ * {@inheritDoc}
694+ * @since 1.6
695+ */
696+ public final void transform(AffineTransform at) {
697+ at.transform(floatCoords, 0, floatCoords, 0, numCoords / 2);
698+ }
699+
700+ /**
701+ * {@inheritDoc}
702+ * @since 1.6
703+ */
704+ public final synchronized Rectangle2D getBounds2D() {
705+ float x1, y1, x2, y2;
706+ int i = numCoords;
707+ if (i > 0) {
708+ y1 = y2 = floatCoords[--i];
709+ x1 = x2 = floatCoords[--i];
710+ while (i > 0) {
711+ float y = floatCoords[--i];
712+ float x = floatCoords[--i];
713+ if (x < x1) x1 = x;
714+ if (y < y1) y1 = y;
715+ if (x > x2) x2 = x;
716+ if (y > y2) y2 = y;
717+ }
718+ } else {
719+ x1 = y1 = x2 = y2 = 0.0f;
720+ }
721+ return new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1);
722+ }
723+
724+ /**
725+ * {@inheritDoc}
726+ * <p>
727+ * The iterator for this class is not multi-threaded safe,
728+ * which means that the {@code Path2D} class does not
729+ * guarantee that modifications to the geometry of this
730+ * {@code Path2D} object do not affect any iterations of
731+ * that geometry that are already in process.
732+ *
733+ * @since 1.6
734+ */
735+ public final PathIterator getPathIterator(AffineTransform at) {
736+ if (at == null) {
737+ return new CopyIterator(this);
738+ } else {
739+ return new TxIterator(this, at);
740+ }
741+ }
742+
743+ /**
744+ * Creates a new object of the same class as this object.
745+ *
746+ * @return a clone of this instance.
747+ * @exception OutOfMemoryError if there is not enough memory.
748+ * @see java.lang.Cloneable
749+ * @since 1.6
750+ */
751+ public final Object clone() {
752+ // Note: It would be nice to have this return Path2D
753+ // but one of our subclasses (GeneralPath) needs to
754+ // offer "public Object clone()" for backwards
755+ // compatibility so we cannot restrict it further.
756+ // REMIND: Can we do both somehow?
757+ if (this instanceof GeneralPath) {
758+ return new GeneralPath(this);
759+ } else {
760+ return new Path2D.Float(this);
761+ }
762+ }
763+
764+ /*
765+ * JDK 1.6 serialVersionUID
766+ */
767+ private static final long serialVersionUID = 6990832515060788886L;
768+
769+ /**
770+ * Writes the default serializable fields to the
771+ * {@code ObjectOutputStream} followed by an explicit
772+ * serialization of the path segments stored in this
773+ * path.
774+ *
775+ * @serialData
776+ * <a name="Path2DSerialData"><!-- --></a>
777+ * <ol>
778+ * <li>The default serializable fields.
779+ * There are no default serializable fields as of 1.6.
780+ * <li>followed by
781+ * a byte indicating the storage type of the original object
782+ * as a hint (SERIAL_STORAGE_FLT_ARRAY)
783+ * <li>followed by
784+ * an integer indicating the number of path segments to follow (NP)
785+ * or -1 to indicate an unknown number of path segments follows
786+ * <li>followed by
787+ * an integer indicating the total number of coordinates to follow (NC)
788+ * or -1 to indicate an unknown number of coordinates follows
789+ * (NC should always be even since coordinates always appear in pairs
790+ * representing an x,y pair)
791+ * <li>followed by
792+ * a byte indicating the winding rule
793+ * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
794+ * {@link #WIND_NON_ZERO WIND_NON_ZERO})
795+ * <li>followed by
796+ * NP (or unlimited if NP < 0) sets of values consisting of
797+ * a single byte indicating a path segment type
798+ * followed by one or more pairs of float or double
799+ * values representing the coordinates of the path segment
800+ * <li>followed by
801+ * a byte indicating the end of the path (SERIAL_PATH_END).
802+ * </ol>
803+ * <p>
804+ * The following byte value constants are used in the serialized form
805+ * of {@code Path2D} objects:
806+ * <table>
807+ * <tr>
808+ * <th>Constant Name</th>
809+ * <th>Byte Value</th>
810+ * <th>Followed by</th>
811+ * <th>Description</th>
812+ * </tr>
813+ * <tr>
814+ * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
815+ * <td>0x30</td>
816+ * <td></td>
817+ * <td>A hint that the original {@code Path2D} object stored
818+ * the coordinates in a Java array of floats.</td>
819+ * </tr>
820+ * <tr>
821+ * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
822+ * <td>0x31</td>
823+ * <td></td>
824+ * <td>A hint that the original {@code Path2D} object stored
825+ * the coordinates in a Java array of doubles.</td>
826+ * </tr>
827+ * <tr>
828+ * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
829+ * <td>0x40</td>
830+ * <td>2 floats</td>
831+ * <td>A {@link #moveTo moveTo} path segment follows.</td>
832+ * </tr>
833+ * <tr>
834+ * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
835+ * <td>0x41</td>
836+ * <td>2 floats</td>
837+ * <td>A {@link #lineTo lineTo} path segment follows.</td>
838+ * </tr>
839+ * <tr>
840+ * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
841+ * <td>0x42</td>
842+ * <td>4 floats</td>
843+ * <td>A {@link #quadTo quadTo} path segment follows.</td>
844+ * </tr>
845+ * <tr>
846+ * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
847+ * <td>0x43</td>
848+ * <td>6 floats</td>
849+ * <td>A {@link #curveTo curveTo} path segment follows.</td>
850+ * </tr>
851+ * <tr>
852+ * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
853+ * <td>0x50</td>
854+ * <td>2 doubles</td>
855+ * <td>A {@link #moveTo moveTo} path segment follows.</td>
856+ * </tr>
857+ * <tr>
858+ * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
859+ * <td>0x51</td>
860+ * <td>2 doubles</td>
861+ * <td>A {@link #lineTo lineTo} path segment follows.</td>
862+ * </tr>
863+ * <tr>
864+ * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
865+ * <td>0x52</td>
866+ * <td>4 doubles</td>
867+ * <td>A {@link #curveTo curveTo} path segment follows.</td>
868+ * </tr>
869+ * <tr>
870+ * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
871+ * <td>0x53</td>
872+ * <td>6 doubles</td>
873+ * <td>A {@link #curveTo curveTo} path segment follows.</td>
874+ * </tr>
875+ * <tr>
876+ * <td>{@code SERIAL_SEG_CLOSE}</td>
877+ * <td>0x60</td>
878+ * <td></td>
879+ * <td>A {@link #closePath closePath} path segment.</td>
880+ * </tr>
881+ * <tr>
882+ * <td>{@code SERIAL_PATH_END}</td>
883+ * <td>0x61</td>
884+ * <td></td>
885+ * <td>There are no more path segments following.</td>
886+ * </table>
887+ *
888+ * @since 1.6
889+ */
890+ private void writeObject(java.io.ObjectOutputStream s)
891+ throws java.io.IOException
892+ {
893+ super.writeObject(s, false);
894+ }
895+
896+ /**
897+ * Reads the default serializable fields from the
898+ * {@code ObjectInputStream} followed by an explicit
899+ * serialization of the path segments stored in this
900+ * path.
901+ * <p>
902+ * There are no default serializable fields as of 1.6.
903+ * <p>
904+ * The serial data for this object is described in the
905+ * writeObject method.
906+ *
907+ * @since 1.6
908+ */
909+ private void readObject(java.io.ObjectInputStream s)
910+ throws java.lang.ClassNotFoundException, java.io.IOException
911+ {
912+ super.readObject(s, false);
913+ }
914+
915+ static class CopyIterator extends Path2D.Iterator {
916+ float floatCoords[];
917+
918+ CopyIterator(Path2D.Float p2df) {
919+ super(p2df);
920+ this.floatCoords = p2df.floatCoords;
921+ }
922+
923+ public int currentSegment(float[] coords) {
924+ int type = path.pointTypes[typeIdx];
925+ int numCoords = curvecoords[type];
926+ if (numCoords > 0) {
927+ System.arraycopy(floatCoords, pointIdx,
928+ coords, 0, numCoords);
929+ }
930+ return type;
931+ }
932+
933+ public int currentSegment(double[] coords) {
934+ int type = path.pointTypes[typeIdx];
935+ int numCoords = curvecoords[type];
936+ if (numCoords > 0) {
937+ for (int i = 0; i < numCoords; i++) {
938+ coords[i] = floatCoords[pointIdx + i];
939+ }
940+ }
941+ return type;
942+ }
943+ }
944+
945+ static class TxIterator extends Path2D.Iterator {
946+ float floatCoords[];
947+ AffineTransform affine;
948+
949+ TxIterator(Path2D.Float p2df, AffineTransform at) {
950+ super(p2df);
951+ this.floatCoords = p2df.floatCoords;
952+ this.affine = at;
953+ }
954+
955+ public int currentSegment(float[] coords) {
956+ int type = path.pointTypes[typeIdx];
957+ int numCoords = curvecoords[type];
958+ if (numCoords > 0) {
959+ affine.transform(floatCoords, pointIdx,
960+ coords, 0, numCoords / 2);
961+ }
962+ return type;
963+ }
964+
965+ public int currentSegment(double[] coords) {
966+ int type = path.pointTypes[typeIdx];
967+ int numCoords = curvecoords[type];
968+ if (numCoords > 0) {
969+ affine.transform(floatCoords, pointIdx,
970+ coords, 0, numCoords / 2);
971+ }
972+ return type;
973+ }
974+ }
975+
976+ }
977+
978+ /**
979+ * The {@code Double} class defines a geometric path with
980+ * coordinates stored in double precision floating point.
981+ *
982+ * @since 1.6
983+ */
984+ public static class Double extends Path2D implements Serializable {
985+ transient double doubleCoords[];
986+
987+ /**
988+ * Constructs a new empty double precision {@code Path2D} object
989+ * with a default winding rule of {@link #WIND_NON_ZERO}.
990+ *
991+ * @since 1.6
992+ */
993+ public Double() {
994+ this(WIND_NON_ZERO, INIT_SIZE);
995+ }
996+
997+ /**
998+ * Constructs a new empty double precision {@code Path2D} object
999+ * with the specified winding rule to control operations that
1000+ * require the interior of the path to be defined.
1001+ *
1002+ * @param rule the winding rule
1003+ * @see #WIND_EVEN_ODD
1004+ * @see #WIND_NON_ZERO
1005+ * @since 1.6
1006+ */
1007+ public Double(int rule) {
1008+ this(rule, INIT_SIZE);
1009+ }
1010+
1011+ /**
1012+ * Constructs a new empty double precision {@code Path2D} object
1013+ * with the specified winding rule and the specified initial
1014+ * capacity to store path segments.
1015+ * This number is an initial guess as to how many path segments
1016+ * are in the path, but the storage is expanded as needed to store
1017+ * whatever path segments are added to this path.
1018+ *
1019+ * @param rule the winding rule
1020+ * @param initialCapacity the estimate for the number of path segments
1021+ * in the path
1022+ * @see #WIND_EVEN_ODD
1023+ * @see #WIND_NON_ZERO
1024+ * @since 1.6
1025+ */
1026+ public Double(int rule, int initialCapacity) {
1027+ super(rule, initialCapacity);
1028+ doubleCoords = new double[initialCapacity * 2];
1029+ }
1030+
1031+ /**
1032+ * Constructs a new double precision {@code Path2D} object
1033+ * from an arbitrary {@link Shape} object.
1034+ * All of the initial geometry and the winding rule for this path are
1035+ * taken from the specified {@code Shape} object.
1036+ *
1037+ * @param s the specified {@code Shape} object
1038+ * @since 1.6
1039+ */
1040+ public Double(Shape s) {
1041+ this(s, null);
1042+ }
1043+
1044+ /**
1045+ * Constructs a new double precision {@code Path2D} object
1046+ * from an arbitrary {@link Shape} object, transformed by an
1047+ * {@link AffineTransform} object.
1048+ * All of the initial geometry and the winding rule for this path are
1049+ * taken from the specified {@code Shape} object and transformed
1050+ * by the specified {@code AffineTransform} object.
1051+ *
1052+ * @param s the specified {@code Shape} object
1053+ * @param at the specified {@code AffineTransform} object
1054+ * @since 1.6
1055+ */
1056+ public Double(Shape s, AffineTransform at) {
1057+ if (s instanceof Path2D) {
1058+ Path2D p2d = (Path2D) s;
1059+ setWindingRule(p2d.windingRule);
1060+ this.numTypes = p2d.numTypes;
1061+ this.pointTypes = Arrays.copyOf(p2d.pointTypes,
1062+ p2d.pointTypes.length);
1063+ this.numCoords = p2d.numCoords;
1064+ this.doubleCoords = p2d.cloneCoordsDouble(at);
1065+ } else {
1066+ PathIterator pi = s.getPathIterator(at);
1067+ setWindingRule(pi.getWindingRule());
1068+ this.pointTypes = new byte[INIT_SIZE];
1069+ this.doubleCoords = new double[INIT_SIZE * 2];
1070+ append(pi, false);
1071+ }
1072+ }
1073+
1074+ float[] cloneCoordsFloat(AffineTransform at) {
1075+ float ret[] = new float[doubleCoords.length];
1076+ if (at == null) {
1077+ for (int i = 0; i < numCoords; i++) {
1078+ ret[i] = (float) doubleCoords[i];
1079+ }
1080+ } else {
1081+ at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1082+ }
1083+ return ret;
1084+ }
1085+
1086+ double[] cloneCoordsDouble(AffineTransform at) {
1087+ double ret[];
1088+ if (at == null) {
1089+ ret = Arrays.copyOf(this.doubleCoords,
1090+ this.doubleCoords.length);
1091+ } else {
1092+ ret = new double[doubleCoords.length];
1093+ at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1094+ }
1095+ return ret;
1096+ }
1097+
1098+ void append(float x, float y) {
1099+ doubleCoords[numCoords++] = x;
1100+ doubleCoords[numCoords++] = y;
1101+ }
1102+
1103+ void append(double x, double y) {
1104+ doubleCoords[numCoords++] = x;
1105+ doubleCoords[numCoords++] = y;
1106+ }
1107+
1108+ Point2D getPoint(int coordindex) {
1109+ return new Point2D.Double(doubleCoords[coordindex],
1110+ doubleCoords[coordindex+1]);
1111+ }
1112+
1113+ void needRoom(boolean needMove, int newCoords) {
1114+ if (needMove && numTypes == 0) {
1115+ throw new IllegalPathStateException("missing initial moveto "+
1116+ "in path definition");
1117+ }
1118+ int size = pointTypes.length;
1119+ if (numTypes >= size) {
1120+ int grow = size;
1121+ if (grow > EXPAND_MAX) {
1122+ grow = EXPAND_MAX;
1123+ }
1124+ pointTypes = Arrays.copyOf(pointTypes, size+grow);
1125+ }
1126+ size = doubleCoords.length;
1127+ if (numCoords + newCoords > size) {
1128+ int grow = size;
1129+ if (grow > EXPAND_MAX * 2) {
1130+ grow = EXPAND_MAX * 2;
1131+ }
1132+ if (grow < newCoords) {
1133+ grow = newCoords;
1134+ }
1135+ doubleCoords = Arrays.copyOf(doubleCoords, size+grow);
1136+ }
1137+ }
1138+
1139+ /**
1140+ * {@inheritDoc}
1141+ * @since 1.6
1142+ */
1143+ public final synchronized void moveTo(double x, double y) {
1144+ if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
1145+ doubleCoords[numCoords-2] = x;
1146+ doubleCoords[numCoords-1] = y;
1147+ } else {
1148+ needRoom(false, 2);
1149+ pointTypes[numTypes++] = SEG_MOVETO;
1150+ doubleCoords[numCoords++] = x;
1151+ doubleCoords[numCoords++] = y;
1152+ }
1153+ }
1154+
1155+ /**
1156+ * {@inheritDoc}
1157+ * @since 1.6
1158+ */
1159+ public final synchronized void lineTo(double x, double y) {
1160+ needRoom(true, 2);
1161+ pointTypes[numTypes++] = SEG_LINETO;
1162+ doubleCoords[numCoords++] = x;
1163+ doubleCoords[numCoords++] = y;
1164+ }
1165+
1166+ /**
1167+ * {@inheritDoc}
1168+ * @since 1.6
1169+ */
1170+ public final synchronized void quadTo(double x1, double y1,
1171+ double x2, double y2)
1172+ {
1173+ needRoom(true, 4);
1174+ pointTypes[numTypes++] = SEG_QUADTO;
1175+ doubleCoords[numCoords++] = x1;
1176+ doubleCoords[numCoords++] = y1;
1177+ doubleCoords[numCoords++] = x2;
1178+ doubleCoords[numCoords++] = y2;
1179+ }
1180+
1181+ /**
1182+ * {@inheritDoc}
1183+ * @since 1.6
1184+ */
1185+ public final synchronized void curveTo(double x1, double y1,
1186+ double x2, double y2,
1187+ double x3, double y3)
1188+ {
1189+ needRoom(true, 6);
1190+ pointTypes[numTypes++] = SEG_CUBICTO;
1191+ doubleCoords[numCoords++] = x1;
1192+ doubleCoords[numCoords++] = y1;
1193+ doubleCoords[numCoords++] = x2;
1194+ doubleCoords[numCoords++] = y2;
1195+ doubleCoords[numCoords++] = x3;
1196+ doubleCoords[numCoords++] = y3;
1197+ }
1198+
1199+ int pointCrossings(double px, double py) {
1200+ double movx, movy, curx, cury, endx, endy;
1201+ double coords[] = doubleCoords;
1202+ curx = movx = coords[0];
1203+ cury = movy = coords[1];
1204+ int crossings = 0;
1205+ int ci = 2;
1206+ for (int i = 1; i < numTypes; i++) {
1207+ switch (pointTypes[i]) {
1208+ case PathIterator.SEG_MOVETO:
1209+ if (cury != movy) {
1210+ crossings +=
1211+ Curve.pointCrossingsForLine(px, py,
1212+ curx, cury,
1213+ movx, movy);
1214+ }
1215+ movx = curx = coords[ci++];
1216+ movy = cury = coords[ci++];
1217+ break;
1218+ case PathIterator.SEG_LINETO:
1219+ crossings +=
1220+ Curve.pointCrossingsForLine(px, py,
1221+ curx, cury,
1222+ endx = coords[ci++],
1223+ endy = coords[ci++]);
1224+ curx = endx;
1225+ cury = endy;
1226+ break;
1227+ case PathIterator.SEG_QUADTO:
1228+ crossings +=
1229+ Curve.pointCrossingsForQuad(px, py,
1230+ curx, cury,
1231+ coords[ci++],
1232+ coords[ci++],
1233+ endx = coords[ci++],
1234+ endy = coords[ci++],
1235+ 0);
1236+ curx = endx;
1237+ cury = endy;
1238+ break;
1239+ case PathIterator.SEG_CUBICTO:
1240+ crossings +=
1241+ Curve.pointCrossingsForCubic(px, py,
1242+ curx, cury,
1243+ coords[ci++],
1244+ coords[ci++],
1245+ coords[ci++],
1246+ coords[ci++],
1247+ endx = coords[ci++],
1248+ endy = coords[ci++],
1249+ 0);
1250+ curx = endx;
1251+ cury = endy;
1252+ break;
1253+ case PathIterator.SEG_CLOSE:
1254+ if (cury != movy) {
1255+ crossings +=
1256+ Curve.pointCrossingsForLine(px, py,
1257+ curx, cury,
1258+ movx, movy);
1259+ }
1260+ curx = movx;
1261+ cury = movy;
1262+ break;
1263+ }
1264+ }
1265+ if (cury != movy) {
1266+ crossings +=
1267+ Curve.pointCrossingsForLine(px, py,
1268+ curx, cury,
1269+ movx, movy);
1270+ }
1271+ return crossings;
1272+ }
1273+
1274+ int rectCrossings(double rxmin, double rymin,
1275+ double rxmax, double rymax)
1276+ {
1277+ double coords[] = doubleCoords;
1278+ double curx, cury, movx, movy, endx, endy;
1279+ curx = movx = coords[0];
1280+ cury = movy = coords[1];
1281+ int crossings = 0;
1282+ int ci = 2;
1283+ for (int i = 1;
1284+ crossings != Curve.RECT_INTERSECTS && i < numTypes;
1285+ i++)
1286+ {
1287+ switch (pointTypes[i]) {
1288+ case PathIterator.SEG_MOVETO:
1289+ if (curx != movx || cury != movy) {
1290+ crossings =
1291+ Curve.rectCrossingsForLine(crossings,
1292+ rxmin, rymin,
1293+ rxmax, rymax,
1294+ curx, cury,
1295+ movx, movy);
1296+ }
1297+ // Count should always be a multiple of 2 here.
1298+ // assert((crossings & 1) != 0);
1299+ movx = curx = coords[ci++];
1300+ movy = cury = coords[ci++];
1301+ break;
1302+ case PathIterator.SEG_LINETO:
1303+ endx = coords[ci++];
1304+ endy = coords[ci++];
1305+ crossings =
1306+ Curve.rectCrossingsForLine(crossings,
1307+ rxmin, rymin,
1308+ rxmax, rymax,
1309+ curx, cury,
1310+ endx, endy);
1311+ curx = endx;
1312+ cury = endy;
1313+ break;
1314+ case PathIterator.SEG_QUADTO:
1315+ crossings =
1316+ Curve.rectCrossingsForQuad(crossings,
1317+ rxmin, rymin,
1318+ rxmax, rymax,
1319+ curx, cury,
1320+ coords[ci++],
1321+ coords[ci++],
1322+ endx = coords[ci++],
1323+ endy = coords[ci++],
1324+ 0);
1325+ curx = endx;
1326+ cury = endy;
1327+ break;
1328+ case PathIterator.SEG_CUBICTO:
1329+ crossings =
1330+ Curve.rectCrossingsForCubic(crossings,
1331+ rxmin, rymin,
1332+ rxmax, rymax,
1333+ curx, cury,
1334+ coords[ci++],
1335+ coords[ci++],
1336+ coords[ci++],
1337+ coords[ci++],
1338+ endx = coords[ci++],
1339+ endy = coords[ci++],
1340+ 0);
1341+ curx = endx;
1342+ cury = endy;
1343+ break;
1344+ case PathIterator.SEG_CLOSE:
1345+ if (curx != movx || cury != movy) {
1346+ crossings =
1347+ Curve.rectCrossingsForLine(crossings,
1348+ rxmin, rymin,
1349+ rxmax, rymax,
1350+ curx, cury,
1351+ movx, movy);
1352+ }
1353+ curx = movx;
1354+ cury = movy;
1355+ // Count should always be a multiple of 2 here.
1356+ // assert((crossings & 1) != 0);
1357+ break;
1358+ }
1359+ }
1360+ if (crossings != Curve.RECT_INTERSECTS &&
1361+ (curx != movx || cury != movy))
1362+ {
1363+ crossings =
1364+ Curve.rectCrossingsForLine(crossings,
1365+ rxmin, rymin,
1366+ rxmax, rymax,
1367+ curx, cury,
1368+ movx, movy);
1369+ }
1370+ // Count should always be a multiple of 2 here.
1371+ // assert((crossings & 1) != 0);
1372+ return crossings;
1373+ }
1374+
1375+ /**
1376+ * {@inheritDoc}
1377+ * @since 1.6
1378+ */
1379+ public final void append(PathIterator pi, boolean connect) {
1380+ double coords[] = new double[6];
1381+ while (!pi.isDone()) {
1382+ switch (pi.currentSegment(coords)) {
1383+ case SEG_MOVETO:
1384+ if (!connect || numTypes < 1 || numCoords < 1) {
1385+ moveTo(coords[0], coords[1]);
1386+ break;
1387+ }
1388+ if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1389+ doubleCoords[numCoords-2] == coords[0] &&
1390+ doubleCoords[numCoords-1] == coords[1])
1391+ {
1392+ // Collapse out initial moveto/lineto
1393+ break;
1394+ }
1395+ // NO BREAK;
1396+ case SEG_LINETO:
1397+ lineTo(coords[0], coords[1]);
1398+ break;
1399+ case SEG_QUADTO:
1400+ quadTo(coords[0], coords[1],
1401+ coords[2], coords[3]);
1402+ break;
1403+ case SEG_CUBICTO:
1404+ curveTo(coords[0], coords[1],
1405+ coords[2], coords[3],
1406+ coords[4], coords[5]);
1407+ break;
1408+ case SEG_CLOSE:
1409+ closePath();
1410+ break;
1411+ }
1412+ pi.next();
1413+ connect = false;
1414+ }
1415+ }
1416+
1417+ /**
1418+ * {@inheritDoc}
1419+ * @since 1.6
1420+ */
1421+ public final void transform(AffineTransform at) {
1422+ at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2);
1423+ }
1424+
1425+ /**
1426+ * {@inheritDoc}
1427+ * @since 1.6
1428+ */
1429+ public final synchronized Rectangle2D getBounds2D() {
1430+ double x1, y1, x2, y2;
1431+ int i = numCoords;
1432+ if (i > 0) {
1433+ y1 = y2 = doubleCoords[--i];
1434+ x1 = x2 = doubleCoords[--i];
1435+ while (i > 0) {
1436+ double y = doubleCoords[--i];
1437+ double x = doubleCoords[--i];
1438+ if (x < x1) x1 = x;
1439+ if (y < y1) y1 = y;
1440+ if (x > x2) x2 = x;
1441+ if (y > y2) y2 = y;
1442+ }
1443+ } else {
1444+ x1 = y1 = x2 = y2 = 0.0;
1445+ }
1446+ return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
1447+ }
1448+
1449+ /**
1450+ * {@inheritDoc}
1451+ * <p>
1452+ * The iterator for this class is not multi-threaded safe,
1453+ * which means that the {@code Path2D} class does not
1454+ * guarantee that modifications to the geometry of this
1455+ * {@code Path2D} object do not affect any iterations of
1456+ * that geometry that are already in process.
1457+ *
1458+ * @param at an {@code AffineTransform}
1459+ * @return a new {@code PathIterator} that iterates along the boundary
1460+ * of this {@code Shape} and provides access to the geometry
1461+ * of this {@code Shape}'s outline
1462+ * @since 1.6
1463+ */
1464+ public final PathIterator getPathIterator(AffineTransform at) {
1465+ if (at == null) {
1466+ return new CopyIterator(this);
1467+ } else {
1468+ return new TxIterator(this, at);
1469+ }
1470+ }
1471+
1472+ /**
1473+ * Creates a new object of the same class as this object.
1474+ *
1475+ * @return a clone of this instance.
1476+ * @exception OutOfMemoryError if there is not enough memory.
1477+ * @see java.lang.Cloneable
1478+ * @since 1.6
1479+ */
1480+ public final Object clone() {
1481+ // Note: It would be nice to have this return Path2D
1482+ // but one of our subclasses (GeneralPath) needs to
1483+ // offer "public Object clone()" for backwards
1484+ // compatibility so we cannot restrict it further.
1485+ // REMIND: Can we do both somehow?
1486+ return new Path2D.Double(this);
1487+ }
1488+
1489+ /*
1490+ * JDK 1.6 serialVersionUID
1491+ */
1492+ private static final long serialVersionUID = 1826762518450014216L;
1493+
1494+ /**
1495+ * Writes the default serializable fields to the
1496+ * {@code ObjectOutputStream} followed by an explicit
1497+ * serialization of the path segments stored in this
1498+ * path.
1499+ *
1500+ * @serialData
1501+ * <a name="Path2DSerialData"><!-- --></a>
1502+ * <ol>
1503+ * <li>The default serializable fields.
1504+ * There are no default serializable fields as of 1.6.
1505+ * <li>followed by
1506+ * a byte indicating the storage type of the original object
1507+ * as a hint (SERIAL_STORAGE_DBL_ARRAY)
1508+ * <li>followed by
1509+ * an integer indicating the number of path segments to follow (NP)
1510+ * or -1 to indicate an unknown number of path segments follows
1511+ * <li>followed by
1512+ * an integer indicating the total number of coordinates to follow (NC)
1513+ * or -1 to indicate an unknown number of coordinates follows
1514+ * (NC should always be even since coordinates always appear in pairs
1515+ * representing an x,y pair)
1516+ * <li>followed by
1517+ * a byte indicating the winding rule
1518+ * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
1519+ * {@link #WIND_NON_ZERO WIND_NON_ZERO})
1520+ * <li>followed by
1521+ * NP (or unlimited if NP < 0) sets of values consisting of
1522+ * a single byte indicating a path segment type
1523+ * followed by one or more pairs of float or double
1524+ * values representing the coordinates of the path segment
1525+ * <li>followed by
1526+ * a byte indicating the end of the path (SERIAL_PATH_END).
1527+ * </ol>
1528+ * <p>
1529+ * The following byte value constants are used in the serialized form
1530+ * of {@code Path2D} objects:
1531+ * <table>
1532+ * <tr>
1533+ * <th>Constant Name</th>
1534+ * <th>Byte Value</th>
1535+ * <th>Followed by</th>
1536+ * <th>Description</th>
1537+ * </tr>
1538+ * <tr>
1539+ * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
1540+ * <td>0x30</td>
1541+ * <td></td>
1542+ * <td>A hint that the original {@code Path2D} object stored
1543+ * the coordinates in a Java array of floats.</td>
1544+ * </tr>
1545+ * <tr>
1546+ * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
1547+ * <td>0x31</td>
1548+ * <td></td>
1549+ * <td>A hint that the original {@code Path2D} object stored
1550+ * the coordinates in a Java array of doubles.</td>
1551+ * </tr>
1552+ * <tr>
1553+ * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
1554+ * <td>0x40</td>
1555+ * <td>2 floats</td>
1556+ * <td>A {@link #moveTo moveTo} path segment follows.</td>
1557+ * </tr>
1558+ * <tr>
1559+ * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
1560+ * <td>0x41</td>
1561+ * <td>2 floats</td>
1562+ * <td>A {@link #lineTo lineTo} path segment follows.</td>
1563+ * </tr>
1564+ * <tr>
1565+ * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
1566+ * <td>0x42</td>
1567+ * <td>4 floats</td>
1568+ * <td>A {@link #quadTo quadTo} path segment follows.</td>
1569+ * </tr>
1570+ * <tr>
1571+ * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
1572+ * <td>0x43</td>
1573+ * <td>6 floats</td>
1574+ * <td>A {@link #curveTo curveTo} path segment follows.</td>
1575+ * </tr>
1576+ * <tr>
1577+ * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
1578+ * <td>0x50</td>
1579+ * <td>2 doubles</td>
1580+ * <td>A {@link #moveTo moveTo} path segment follows.</td>
1581+ * </tr>
1582+ * <tr>
1583+ * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
1584+ * <td>0x51</td>
1585+ * <td>2 doubles</td>
1586+ * <td>A {@link #lineTo lineTo} path segment follows.</td>
1587+ * </tr>
1588+ * <tr>
1589+ * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
1590+ * <td>0x52</td>
1591+ * <td>4 doubles</td>
1592+ * <td>A {@link #curveTo curveTo} path segment follows.</td>
1593+ * </tr>
1594+ * <tr>
1595+ * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
1596+ * <td>0x53</td>
1597+ * <td>6 doubles</td>
1598+ * <td>A {@link #curveTo curveTo} path segment follows.</td>
1599+ * </tr>
1600+ * <tr>
1601+ * <td>{@code SERIAL_SEG_CLOSE}</td>
1602+ * <td>0x60</td>
1603+ * <td></td>
1604+ * <td>A {@link #closePath closePath} path segment.</td>
1605+ * </tr>
1606+ * <tr>
1607+ * <td>{@code SERIAL_PATH_END}</td>
1608+ * <td>0x61</td>
1609+ * <td></td>
1610+ * <td>There are no more path segments following.</td>
1611+ * </table>
1612+ *
1613+ * @since 1.6
1614+ */
1615+ private void writeObject(java.io.ObjectOutputStream s)
1616+ throws java.io.IOException
1617+ {
1618+ super.writeObject(s, true);
1619+ }
1620+
1621+ /**
1622+ * Reads the default serializable fields from the
1623+ * {@code ObjectInputStream} followed by an explicit
1624+ * serialization of the path segments stored in this
1625+ * path.
1626+ * <p>
1627+ * There are no default serializable fields as of 1.6.
1628+ * <p>
1629+ * The serial data for this object is described in the
1630+ * writeObject method.
1631+ *
1632+ * @since 1.6
1633+ */
1634+ private void readObject(java.io.ObjectInputStream s)
1635+ throws java.lang.ClassNotFoundException, java.io.IOException
1636+ {
1637+ super.readObject(s, true);
1638+ }
1639+
1640+ static class CopyIterator extends Path2D.Iterator {
1641+ double doubleCoords[];
1642+
1643+ CopyIterator(Path2D.Double p2dd) {
1644+ super(p2dd);
1645+ this.doubleCoords = p2dd.doubleCoords;
1646+ }
1647+
1648+ public int currentSegment(float[] coords) {
1649+ int type = path.pointTypes[typeIdx];
1650+ int numCoords = curvecoords[type];
1651+ if (numCoords > 0) {
1652+ for (int i = 0; i < numCoords; i++) {
1653+ coords[i] = (float) doubleCoords[pointIdx + i];
1654+ }
1655+ }
1656+ return type;
1657+ }
1658+
1659+ public int currentSegment(double[] coords) {
1660+ int type = path.pointTypes[typeIdx];
1661+ int numCoords = curvecoords[type];
1662+ if (numCoords > 0) {
1663+ System.arraycopy(doubleCoords, pointIdx,
1664+ coords, 0, numCoords);
1665+ }
1666+ return type;
1667+ }
1668+ }
1669+
1670+ static class TxIterator extends Path2D.Iterator {
1671+ double doubleCoords[];
1672+ AffineTransform affine;
1673+
1674+ TxIterator(Path2D.Double p2dd, AffineTransform at) {
1675+ super(p2dd);
1676+ this.doubleCoords = p2dd.doubleCoords;
1677+ this.affine = at;
1678+ }
1679+
1680+ public int currentSegment(float[] coords) {
1681+ int type = path.pointTypes[typeIdx];
1682+ int numCoords = curvecoords[type];
1683+ if (numCoords > 0) {
1684+ affine.transform(doubleCoords, pointIdx,
1685+ coords, 0, numCoords / 2);
1686+ }
1687+ return type;
1688+ }
1689+
1690+ public int currentSegment(double[] coords) {
1691+ int type = path.pointTypes[typeIdx];
1692+ int numCoords = curvecoords[type];
1693+ if (numCoords > 0) {
1694+ affine.transform(doubleCoords, pointIdx,
1695+ coords, 0, numCoords / 2);
1696+ }
1697+ return type;
1698+ }
1699+ }
1700+ }
1701+
1702+ /**
1703+ * Adds a point to the path by moving to the specified
1704+ * coordinates specified in double precision.
1705+ *
1706+ * @param x the specified X coordinate
1707+ * @param y the specified Y coordinate
1708+ * @since 1.6
1709+ */
1710+ public abstract void moveTo(double x, double y);
1711+
1712+ /**
1713+ * Adds a point to the path by drawing a straight line from the
1714+ * current coordinates to the new specified coordinates
1715+ * specified in double precision.
1716+ *
1717+ * @param x the specified X coordinate
1718+ * @param y the specified Y coordinate
1719+ * @since 1.6
1720+ */
1721+ public abstract void lineTo(double x, double y);
1722+
1723+ /**
1724+ * Adds a curved segment, defined by two new points, to the path by
1725+ * drawing a Quadratic curve that intersects both the current
1726+ * coordinates and the specified coordinates {@code (x2,y2)},
1727+ * using the specified point {@code (x1,y1)} as a quadratic
1728+ * parametric control point.
1729+ * All coordinates are specified in double precision.
1730+ *
1731+ * @param x1 the X coordinate of the quadratic control point
1732+ * @param y1 the Y coordinate of the quadratic control point
1733+ * @param x2 the X coordinate of the final end point
1734+ * @param y2 the Y coordinate of the final end point
1735+ * @since 1.6
1736+ */
1737+ public abstract void quadTo(double x1, double y1,
1738+ double x2, double y2);
1739+
1740+ /**
1741+ * Adds a curved segment, defined by three new points, to the path by
1742+ * drawing a B&eacute;zier curve that intersects both the current
1743+ * coordinates and the specified coordinates {@code (x3,y3)},
1744+ * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
1745+ * B&eacute;zier control points.
1746+ * All coordinates are specified in double precision.
1747+ *
1748+ * @param x1 the X coordinate of the first B&eacute;zier control point
1749+ * @param y1 the Y coordinate of the first B&eacute;zier control point
1750+ * @param x2 the X coordinate of the second B&eacute;zier control point
1751+ * @param y2 the Y coordinate of the second B&eacute;zier control point
1752+ * @param x3 the X coordinate of the final end point
1753+ * @param y3 the Y coordinate of the final end point
1754+ * @since 1.6
1755+ */
1756+ public abstract void curveTo(double x1, double y1,
1757+ double x2, double y2,
1758+ double x3, double y3);
1759+
1760+ /**
1761+ * Closes the current subpath by drawing a straight line back to
1762+ * the coordinates of the last {@code moveTo}. If the path is already
1763+ * closed then this method has no effect.
1764+ *
1765+ * @since 1.6
1766+ */
1767+ public final synchronized void closePath() {
1768+ if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
1769+ needRoom(true, 0);
1770+ pointTypes[numTypes++] = SEG_CLOSE;
1771+ }
1772+ }
1773+
1774+ /**
1775+ * Appends the geometry of the specified {@code Shape} object to the
1776+ * path, possibly connecting the new geometry to the existing path
1777+ * segments with a line segment.
1778+ * If the {@code connect} parameter is {@code true} and the
1779+ * path is not empty then any initial {@code moveTo} in the
1780+ * geometry of the appended {@code Shape}
1781+ * is turned into a {@code lineTo} segment.
1782+ * If the destination coordinates of such a connecting {@code lineTo}
1783+ * segment match the ending coordinates of a currently open
1784+ * subpath then the segment is omitted as superfluous.
1785+ * The winding rule of the specified {@code Shape} is ignored
1786+ * and the appended geometry is governed by the winding
1787+ * rule specified for this path.
1788+ *
1789+ * @param s the {@code Shape} whose geometry is appended
1790+ * to this path
1791+ * @param connect a boolean to control whether or not to turn an initial
1792+ * {@code moveTo} segment into a {@code lineTo} segment
1793+ * to connect the new geometry to the existing path
1794+ * @since 1.6
1795+ */
1796+ public final void append(Shape s, boolean connect) {
1797+ append(s.getPathIterator(null), connect);
1798+ }
1799+
1800+ /**
1801+ * Appends the geometry of the specified
1802+ * {@link PathIterator} object
1803+ * to the path, possibly connecting the new geometry to the existing
1804+ * path segments with a line segment.
1805+ * If the {@code connect} parameter is {@code true} and the
1806+ * path is not empty then any initial {@code moveTo} in the
1807+ * geometry of the appended {@code Shape} is turned into a
1808+ * {@code lineTo} segment.
1809+ * If the destination coordinates of such a connecting {@code lineTo}
1810+ * segment match the ending coordinates of a currently open
1811+ * subpath then the segment is omitted as superfluous.
1812+ * The winding rule of the specified {@code Shape} is ignored
1813+ * and the appended geometry is governed by the winding
1814+ * rule specified for this path.
1815+ *
1816+ * @param pi the {@code PathIterator} whose geometry is appended to
1817+ * this path
1818+ * @param connect a boolean to control whether or not to turn an initial
1819+ * {@code moveTo} segment into a {@code lineTo} segment
1820+ * to connect the new geometry to the existing path
1821+ * @since 1.6
1822+ */
1823+ public abstract void append(PathIterator pi, boolean connect);
1824+
1825+ /**
1826+ * Returns the fill style winding rule.
1827+ *
1828+ * @return an integer representing the current winding rule.
1829+ * @see #WIND_EVEN_ODD
1830+ * @see #WIND_NON_ZERO
1831+ * @see #setWindingRule
1832+ * @since 1.6
1833+ */
1834+ public final synchronized int getWindingRule() {
1835+ return windingRule;
1836+ }
1837+
1838+ /**
1839+ * Sets the winding rule for this path to the specified value.
1840+ *
1841+ * @param rule an integer representing the specified
1842+ * winding rule
1843+ * @exception IllegalArgumentException if
1844+ * {@code rule} is not either
1845+ * {@link #WIND_EVEN_ODD} or
1846+ * {@link #WIND_NON_ZERO}
1847+ * @see #getWindingRule
1848+ * @since 1.6
1849+ */
1850+ public final void setWindingRule(int rule) {
1851+ if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
1852+ throw new IllegalArgumentException("winding rule must be "+
1853+ "WIND_EVEN_ODD or "+
1854+ "WIND_NON_ZERO");
1855+ }
1856+ windingRule = rule;
1857+ }
1858+
1859+ /**
1860+ * Returns the coordinates most recently added to the end of the path
1861+ * as a {@link Point2D} object.
1862+ *
1863+ * @return a {@code Point2D} object containing the ending coordinates of
1864+ * the path or {@code null} if there are no points in the path.
1865+ * @since 1.6
1866+ */
1867+ public final synchronized Point2D getCurrentPoint() {
1868+ int index = numCoords;
1869+ if (numTypes < 1 || index < 1) {
1870+ return null;
1871+ }
1872+ if (pointTypes[numTypes - 1] == SEG_CLOSE) {
1873+ loop:
1874+ for (int i = numTypes - 2; i > 0; i--) {
1875+ switch (pointTypes[i]) {
1876+ case SEG_MOVETO:
1877+ break loop;
1878+ case SEG_LINETO:
1879+ index -= 2;
1880+ break;
1881+ case SEG_QUADTO:
1882+ index -= 4;
1883+ break;
1884+ case SEG_CUBICTO:
1885+ index -= 6;
1886+ break;
1887+ case SEG_CLOSE:
1888+ break;
1889+ }
1890+ }
1891+ }
1892+ return getPoint(index - 2);
1893+ }
1894+
1895+ /**
1896+ * Resets the path to empty. The append position is set back to the
1897+ * beginning of the path and all coordinates and point types are
1898+ * forgotten.
1899+ *
1900+ * @since 1.6
1901+ */
1902+ public final synchronized void reset() {
1903+ numTypes = numCoords = 0;
1904+ }
1905+
1906+ /**
1907+ * Transforms the geometry of this path using the specified
1908+ * {@link AffineTransform}.
1909+ * The geometry is transformed in place, which permanently changes the
1910+ * boundary defined by this object.
1911+ *
1912+ * @param at the {@code AffineTransform} used to transform the area
1913+ * @since 1.6
1914+ */
1915+ public abstract void transform(AffineTransform at);
1916+
1917+ /**
1918+ * Returns a new {@code Shape} representing a transformed version
1919+ * of this {@code Path2D}.
1920+ * Note that the exact type and coordinate precision of the return
1921+ * value is not specified for this method.
1922+ * The method will return a Shape that contains no less precision
1923+ * for the transformed geometry than this {@code Path2D} currently
1924+ * maintains, but it may contain no more precision either.
1925+ * If the tradeoff of precision vs. storage size in the result is
1926+ * important then the convenience constructors in the
1927+ * {@link Path2D.Float#Path2D.Float(Shape, AffineTransform) Path2D.Float}
1928+ * and
1929+ * {@link Path2D.Double#Path2D.Double(Shape, AffineTransform) Path2D.Double}
1930+ * subclasses should be used to make the choice explicit.
1931+ *
1932+ * @param at the {@code AffineTransform} used to transform a
1933+ * new {@code Shape}.
1934+ * @return a new {@code Shape}, transformed with the specified
1935+ * {@code AffineTransform}.
1936+ * @since 1.6
1937+ */
1938+ public final synchronized Shape createTransformedShape(AffineTransform at) {
1939+ Path2D p2d = (Path2D) clone();
1940+ if (at != null) {
1941+ p2d.transform(at);
1942+ }
1943+ return p2d;
1944+ }
1945+
1946+ /**
1947+ * {@inheritDoc}
1948+ * @since 1.6
1949+ */
1950+ public final Rectangle getBounds() {
1951+ return getBounds2D().getBounds();
1952+ }
1953+
1954+ /**
1955+ * Tests if the specified coordinates are inside the closed
1956+ * boundary of the specified {@link PathIterator}.
1957+ * <p>
1958+ * This method provides a basic facility for implementors of
1959+ * the {@link Shape} interface to implement support for the
1960+ * {@link Shape#contains(double, double)} method.
1961+ *
1962+ * @param pi the specified {@code PathIterator}
1963+ * @param x the specified X coordinate
1964+ * @param y the specified Y coordinate
1965+ * @return {@code true} if the specified coordinates are inside the
1966+ * specified {@code PathIterator}; {@code false} otherwise
1967+ * @since 1.6
1968+ */
1969+ public static boolean contains(PathIterator pi, double x, double y) {
1970+ if (x * 0.0 + y * 0.0 == 0.0) {
1971+ /* N * 0.0 is 0.0 only if N is finite.
1972+ * Here we know that both x and y are finite.
1973+ */
1974+ int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1);
1975+ int cross = Curve.pointCrossingsForPath(pi, x, y);
1976+ return ((cross & mask) != 0);
1977+ } else {
1978+ /* Either x or y was infinite or NaN.
1979+ * A NaN always produces a negative response to any test
1980+ * and Infinity values cannot be "inside" any path so
1981+ * they should return false as well.
1982+ */
1983+ return false;
1984+ }
1985+ }
1986+
1987+ /**
1988+ * Tests if the specified {@link Point2D} is inside the closed
1989+ * boundary of the specified {@link PathIterator}.
1990+ * <p>
1991+ * This method provides a basic facility for implementors of
1992+ * the {@link Shape} interface to implement support for the
1993+ * {@link Shape#contains(Point2D)} method.
1994+ *
1995+ * @param pi the specified {@code PathIterator}
1996+ * @param p the specified {@code Point2D}
1997+ * @return {@code true} if the specified coordinates are inside the
1998+ * specified {@code PathIterator}; {@code false} otherwise
1999+ * @since 1.6
2000+ */
2001+ public static boolean contains(PathIterator pi, Point2D p) {
2002+ return contains(pi, p.getX(), p.getY());
2003+ }
2004+
2005+ /**
2006+ * {@inheritDoc}
2007+ * @since 1.6
2008+ */
2009+ public final boolean contains(double x, double y) {
2010+ if (x * 0.0 + y * 0.0 == 0.0) {
2011+ /* N * 0.0 is 0.0 only if N is finite.
2012+ * Here we know that both x and y are finite.
2013+ */
2014+ if (numTypes < 2) {
2015+ return false;
2016+ }
2017+ int mask = (windingRule == WIND_NON_ZERO ? -1 : 1);
2018+ return ((pointCrossings(x, y) & mask) != 0);
2019+ } else {
2020+ /* Either x or y was infinite or NaN.
2021+ * A NaN always produces a negative response to any test
2022+ * and Infinity values cannot be "inside" any path so
2023+ * they should return false as well.
2024+ */
2025+ return false;
2026+ }
2027+ }
2028+
2029+ /**
2030+ * {@inheritDoc}
2031+ * @since 1.6
2032+ */
2033+ public final boolean contains(Point2D p) {
2034+ return contains(p.getX(), p.getY());
2035+ }
2036+
2037+ /**
2038+ * Tests if the specified rectangular area is entirely inside the
2039+ * closed boundary of the specified {@link PathIterator}.
2040+ * <p>
2041+ * This method provides a basic facility for implementors of
2042+ * the {@link Shape} interface to implement support for the
2043+ * {@link Shape#contains(double, double, double, double)} method.
2044+ * <p>
2045+ * This method object may conservatively return false in
2046+ * cases where the specified rectangular area intersects a
2047+ * segment of the path, but that segment does not represent a
2048+ * boundary between the interior and exterior of the path.
2049+ * Such segments could lie entirely within the interior of the
2050+ * path if they are part of a path with a {@link #WIND_NON_ZERO}
2051+ * winding rule or if the segments are retraced in the reverse
2052+ * direction such that the two sets of segments cancel each
2053+ * other out without any exterior area falling between them.
2054+ * To determine whether segments represent true boundaries of
2055+ * the interior of the path would require extensive calculations
2056+ * involving all of the segments of the path and the winding
2057+ * rule and are thus beyond the scope of this implementation.
2058+ *
2059+ * @param pi the specified {@code PathIterator}
2060+ * @param x the specified X coordinate
2061+ * @param y the specified Y coordinate
2062+ * @param w the width of the specified rectangular area
2063+ * @param h the height of the specified rectangular area
2064+ * @return {@code true} if the specified {@code PathIterator} contains
2065+ * the specified rectangluar area; {@code false} otherwise.
2066+ * @since 1.6
2067+ */
2068+ public static boolean contains(PathIterator pi,
2069+ double x, double y, double w, double h)
2070+ {
2071+ if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2072+ /* [xy]+[wh] is NaN if any of those values are NaN,
2073+ * or if adding the two together would produce NaN
2074+ * by virtue of adding opposing Infinte values.
2075+ * Since we need to add them below, their sum must
2076+ * not be NaN.
2077+ * We return false because NaN always produces a
2078+ * negative response to tests
2079+ */
2080+ return false;
2081+ }
2082+ if (w <= 0 || h <= 0) {
2083+ return false;
2084+ }
2085+ int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2086+ int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2087+ return (crossings != Curve.RECT_INTERSECTS &&
2088+ (crossings & mask) != 0);
2089+ }
2090+
2091+ /**
2092+ * Tests if the specified {@link Rectangle2D} is entirely inside the
2093+ * closed boundary of the specified {@link PathIterator}.
2094+ * <p>
2095+ * This method provides a basic facility for implementors of
2096+ * the {@link Shape} interface to implement support for the
2097+ * {@link Shape#contains(Rectangle2D)} method.
2098+ * <p>
2099+ * This method object may conservatively return false in
2100+ * cases where the specified rectangular area intersects a
2101+ * segment of the path, but that segment does not represent a
2102+ * boundary between the interior and exterior of the path.
2103+ * Such segments could lie entirely within the interior of the
2104+ * path if they are part of a path with a {@link #WIND_NON_ZERO}
2105+ * winding rule or if the segments are retraced in the reverse
2106+ * direction such that the two sets of segments cancel each
2107+ * other out without any exterior area falling between them.
2108+ * To determine whether segments represent true boundaries of
2109+ * the interior of the path would require extensive calculations
2110+ * involving all of the segments of the path and the winding
2111+ * rule and are thus beyond the scope of this implementation.
2112+ *
2113+ * @param pi the specified {@code PathIterator}
2114+ * @param r a specified {@code Rectangle2D}
2115+ * @return {@code true} if the specified {@code PathIterator} contains
2116+ * the specified {@code Rectangle2D}; {@code false} otherwise.
2117+ * @since 1.6
2118+ */
2119+ public static boolean contains(PathIterator pi, Rectangle2D r) {
2120+ return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2121+ }
2122+
2123+ /**
2124+ * {@inheritDoc}
2125+ * <p>
2126+ * This method object may conservatively return false in
2127+ * cases where the specified rectangular area intersects a
2128+ * segment of the path, but that segment does not represent a
2129+ * boundary between the interior and exterior of the path.
2130+ * Such segments could lie entirely within the interior of the
2131+ * path if they are part of a path with a {@link #WIND_NON_ZERO}
2132+ * winding rule or if the segments are retraced in the reverse
2133+ * direction such that the two sets of segments cancel each
2134+ * other out without any exterior area falling between them.
2135+ * To determine whether segments represent true boundaries of
2136+ * the interior of the path would require extensive calculations
2137+ * involving all of the segments of the path and the winding
2138+ * rule and are thus beyond the scope of this implementation.
2139+ *
2140+ * @since 1.6
2141+ */
2142+ public final boolean contains(double x, double y, double w, double h) {
2143+ if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2144+ /* [xy]+[wh] is NaN if any of those values are NaN,
2145+ * or if adding the two together would produce NaN
2146+ * by virtue of adding opposing Infinte values.
2147+ * Since we need to add them below, their sum must
2148+ * not be NaN.
2149+ * We return false because NaN always produces a
2150+ * negative response to tests
2151+ */
2152+ return false;
2153+ }
2154+ if (w <= 0 || h <= 0) {
2155+ return false;
2156+ }
2157+ int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2158+ int crossings = rectCrossings(x, y, x+w, y+h);
2159+ return (crossings != Curve.RECT_INTERSECTS &&
2160+ (crossings & mask) != 0);
2161+ }
2162+
2163+ /**
2164+ * {@inheritDoc}
2165+ * <p>
2166+ * This method object may conservatively return false in
2167+ * cases where the specified rectangular area intersects a
2168+ * segment of the path, but that segment does not represent a
2169+ * boundary between the interior and exterior of the path.
2170+ * Such segments could lie entirely within the interior of the
2171+ * path if they are part of a path with a {@link #WIND_NON_ZERO}
2172+ * winding rule or if the segments are retraced in the reverse
2173+ * direction such that the two sets of segments cancel each
2174+ * other out without any exterior area falling between them.
2175+ * To determine whether segments represent true boundaries of
2176+ * the interior of the path would require extensive calculations
2177+ * involving all of the segments of the path and the winding
2178+ * rule and are thus beyond the scope of this implementation.
2179+ *
2180+ * @since 1.6
2181+ */
2182+ public final boolean contains(Rectangle2D r) {
2183+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2184+ }
2185+
2186+ /**
2187+ * Tests if the interior of the specified {@link PathIterator}
2188+ * intersects the interior of a specified set of rectangular
2189+ * coordinates.
2190+ * <p>
2191+ * This method provides a basic facility for implementors of
2192+ * the {@link Shape} interface to implement support for the
2193+ * {@link Shape#intersects(double, double, double, double)} method.
2194+ * <p>
2195+ * This method object may conservatively return true in
2196+ * cases where the specified rectangular area intersects a
2197+ * segment of the path, but that segment does not represent a
2198+ * boundary between the interior and exterior of the path.
2199+ * Such a case may occur if some set of segments of the
2200+ * path are retraced in the reverse direction such that the
2201+ * two sets of segments cancel each other out without any
2202+ * interior area between them.
2203+ * To determine whether segments represent true boundaries of
2204+ * the interior of the path would require extensive calculations
2205+ * involving all of the segments of the path and the winding
2206+ * rule and are thus beyond the scope of this implementation.
2207+ *
2208+ * @param pi the specified {@code PathIterator}
2209+ * @param x the specified X coordinate
2210+ * @param y the specified Y coordinate
2211+ * @param w the width of the specified rectangular coordinates
2212+ * @param h the height of the specified rectangular coordinates
2213+ * @return {@code true} if the specified {@code PathIterator} and
2214+ * the interior of the specified set of rectangular
2215+ * coordinates intersect each other; {@code false} otherwise.
2216+ * @since 1.6
2217+ */
2218+ public static boolean intersects(PathIterator pi,
2219+ double x, double y, double w, double h)
2220+ {
2221+ if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2222+ /* [xy]+[wh] is NaN if any of those values are NaN,
2223+ * or if adding the two together would produce NaN
2224+ * by virtue of adding opposing Infinte values.
2225+ * Since we need to add them below, their sum must
2226+ * not be NaN.
2227+ * We return false because NaN always produces a
2228+ * negative response to tests
2229+ */
2230+ return false;
2231+ }
2232+ if (w <= 0 || h <= 0) {
2233+ return false;
2234+ }
2235+ int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2236+ int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2237+ return (crossings == Curve.RECT_INTERSECTS ||
2238+ (crossings & mask) != 0);
2239+ }
2240+
2241+ /**
2242+ * Tests if the interior of the specified {@link PathIterator}
2243+ * intersects the interior of a specified {@link Rectangle2D}.
2244+ * <p>
2245+ * This method provides a basic facility for implementors of
2246+ * the {@link Shape} interface to implement support for the
2247+ * {@link Shape#intersects(Rectangle2D)} method.
2248+ * <p>
2249+ * This method object may conservatively return true in
2250+ * cases where the specified rectangular area intersects a
2251+ * segment of the path, but that segment does not represent a
2252+ * boundary between the interior and exterior of the path.
2253+ * Such a case may occur if some set of segments of the
2254+ * path are retraced in the reverse direction such that the
2255+ * two sets of segments cancel each other out without any
2256+ * interior area between them.
2257+ * To determine whether segments represent true boundaries of
2258+ * the interior of the path would require extensive calculations
2259+ * involving all of the segments of the path and the winding
2260+ * rule and are thus beyond the scope of this implementation.
2261+ *
2262+ * @param pi the specified {@code PathIterator}
2263+ * @param r the specified {@code Rectangle2D}
2264+ * @return {@code true} if the specified {@code PathIterator} and
2265+ * the interior of the specified {@code Rectangle2D}
2266+ * intersect each other; {@code false} otherwise.
2267+ * @since 1.6
2268+ */
2269+ public static boolean intersects(PathIterator pi, Rectangle2D r) {
2270+ return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2271+ }
2272+
2273+ /**
2274+ * {@inheritDoc}
2275+ * <p>
2276+ * This method object may conservatively return true in
2277+ * cases where the specified rectangular area intersects a
2278+ * segment of the path, but that segment does not represent a
2279+ * boundary between the interior and exterior of the path.
2280+ * Such a case may occur if some set of segments of the
2281+ * path are retraced in the reverse direction such that the
2282+ * two sets of segments cancel each other out without any
2283+ * interior area between them.
2284+ * To determine whether segments represent true boundaries of
2285+ * the interior of the path would require extensive calculations
2286+ * involving all of the segments of the path and the winding
2287+ * rule and are thus beyond the scope of this implementation.
2288+ *
2289+ * @since 1.6
2290+ */
2291+ public final boolean intersects(double x, double y, double w, double h) {
2292+ if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2293+ /* [xy]+[wh] is NaN if any of those values are NaN,
2294+ * or if adding the two together would produce NaN
2295+ * by virtue of adding opposing Infinte values.
2296+ * Since we need to add them below, their sum must
2297+ * not be NaN.
2298+ * We return false because NaN always produces a
2299+ * negative response to tests
2300+ */
2301+ return false;
2302+ }
2303+ if (w <= 0 || h <= 0) {
2304+ return false;
2305+ }
2306+ int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2307+ int crossings = rectCrossings(x, y, x+w, y+h);
2308+ return (crossings == Curve.RECT_INTERSECTS ||
2309+ (crossings & mask) != 0);
2310+ }
2311+
2312+ /**
2313+ * {@inheritDoc}
2314+ * <p>
2315+ * This method object may conservatively return true in
2316+ * cases where the specified rectangular area intersects a
2317+ * segment of the path, but that segment does not represent a
2318+ * boundary between the interior and exterior of the path.
2319+ * Such a case may occur if some set of segments of the
2320+ * path are retraced in the reverse direction such that the
2321+ * two sets of segments cancel each other out without any
2322+ * interior area between them.
2323+ * To determine whether segments represent true boundaries of
2324+ * the interior of the path would require extensive calculations
2325+ * involving all of the segments of the path and the winding
2326+ * rule and are thus beyond the scope of this implementation.
2327+ *
2328+ * @since 1.6
2329+ */
2330+ public final boolean intersects(Rectangle2D r) {
2331+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2332+ }
2333+
2334+ /**
2335+ * {@inheritDoc}
2336+ * <p>
2337+ * The iterator for this class is not multi-threaded safe,
2338+ * which means that this {@code Path2D} class does not
2339+ * guarantee that modifications to the geometry of this
2340+ * {@code Path2D} object do not affect any iterations of
2341+ * that geometry that are already in process.
2342+ *
2343+ * @since 1.6
2344+ */
2345+ public final PathIterator getPathIterator(AffineTransform at,
2346+ double flatness)
2347+ {
2348+ return new FlatteningPathIterator(getPathIterator(at), flatness);
2349+ }
2350+
2351+ /**
2352+ * Creates a new object of the same class as this object.
2353+ *
2354+ * @return a clone of this instance.
2355+ * @exception OutOfMemoryError if there is not enough memory.
2356+ * @see java.lang.Cloneable
2357+ * @since 1.6
2358+ */
2359+ public abstract Object clone();
2360+ // Note: It would be nice to have this return Path2D
2361+ // but one of our subclasses (GeneralPath) needs to
2362+ // offer "public Object clone()" for backwards
2363+ // compatibility so we cannot restrict it further.
2364+ // REMIND: Can we do both somehow?
2365+
2366+ /*
2367+ * Support fields and methods for serializing the subclasses.
2368+ */
2369+ private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30;
2370+ private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2371+
2372+ private static final byte SERIAL_SEG_FLT_MOVETO = 0x40;
2373+ private static final byte SERIAL_SEG_FLT_LINETO = 0x41;
2374+ private static final byte SERIAL_SEG_FLT_QUADTO = 0x42;
2375+ private static final byte SERIAL_SEG_FLT_CUBICTO = 0x43;
2376+
2377+ private static final byte SERIAL_SEG_DBL_MOVETO = 0x50;
2378+ private static final byte SERIAL_SEG_DBL_LINETO = 0x51;
2379+ private static final byte SERIAL_SEG_DBL_QUADTO = 0x52;
2380+ private static final byte SERIAL_SEG_DBL_CUBICTO = 0x53;
2381+
2382+ private static final byte SERIAL_SEG_CLOSE = 0x60;
2383+ private static final byte SERIAL_PATH_END = 0x61;
2384+
2385+ final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2386+ throws java.io.IOException
2387+ {
2388+ s.defaultWriteObject();
2389+
2390+ float fCoords[];
2391+ double dCoords[];
2392+
2393+ if (isdbl) {
2394+ dCoords = ((Path2D.Double) this).doubleCoords;
2395+ fCoords = null;
2396+ } else {
2397+ fCoords = ((Path2D.Float) this).floatCoords;
2398+ dCoords = null;
2399+ }
2400+
2401+ int numTypes = this.numTypes;
2402+
2403+ s.writeByte(isdbl
2404+ ? SERIAL_STORAGE_DBL_ARRAY
2405+ : SERIAL_STORAGE_FLT_ARRAY);
2406+ s.writeInt(numTypes);
2407+ s.writeInt(numCoords);
2408+ s.writeByte((byte) windingRule);
2409+
2410+ int cindex = 0;
2411+ for (int i = 0; i < numTypes; i++) {
2412+ int npoints;
2413+ byte serialtype;
2414+ switch (pointTypes[i]) {
2415+ case SEG_MOVETO:
2416+ npoints = 1;
2417+ serialtype = (isdbl
2418+ ? SERIAL_SEG_DBL_MOVETO
2419+ : SERIAL_SEG_FLT_MOVETO);
2420+ break;
2421+ case SEG_LINETO:
2422+ npoints = 1;
2423+ serialtype = (isdbl
2424+ ? SERIAL_SEG_DBL_LINETO
2425+ : SERIAL_SEG_FLT_LINETO);
2426+ break;
2427+ case SEG_QUADTO:
2428+ npoints = 2;
2429+ serialtype = (isdbl
2430+ ? SERIAL_SEG_DBL_QUADTO
2431+ : SERIAL_SEG_FLT_QUADTO);
2432+ break;
2433+ case SEG_CUBICTO:
2434+ npoints = 3;
2435+ serialtype = (isdbl
2436+ ? SERIAL_SEG_DBL_CUBICTO
2437+ : SERIAL_SEG_FLT_CUBICTO);
2438+ break;
2439+ case SEG_CLOSE:
2440+ npoints = 0;
2441+ serialtype = SERIAL_SEG_CLOSE;
2442+ break;
2443+
2444+ default:
2445+ // Should never happen
2446+ throw new InternalError("unrecognized path type");
2447+ }
2448+ s.writeByte(serialtype);
2449+ while (--npoints >= 0) {
2450+ if (isdbl) {
2451+ s.writeDouble(dCoords[cindex++]);
2452+ s.writeDouble(dCoords[cindex++]);
2453+ } else {
2454+ s.writeFloat(fCoords[cindex++]);
2455+ s.writeFloat(fCoords[cindex++]);
2456+ }
2457+ }
2458+ }
2459+ s.writeByte((byte) SERIAL_PATH_END);
2460+ }
2461+
2462+ final void readObject(java.io.ObjectInputStream s, boolean storedbl)
2463+ throws java.lang.ClassNotFoundException, java.io.IOException
2464+ {
2465+ s.defaultReadObject();
2466+
2467+ // The subclass calls this method with the storage type that
2468+ // they want us to use (storedbl) so we ignore the storage
2469+ // method hint from the stream.
2470+ s.readByte();
2471+ int nT = s.readInt();
2472+ int nC = s.readInt();
2473+ try {
2474+ setWindingRule(s.readByte());
2475+ } catch (IllegalArgumentException iae) {
2476+ throw new java.io.InvalidObjectException(iae.getMessage());
2477+ }
2478+
2479+ pointTypes = new byte[(nT < 0) ? INIT_SIZE : nT];
2480+ if (nC < 0) {
2481+ nC = INIT_SIZE * 2;
2482+ }
2483+ if (storedbl) {
2484+ ((Path2D.Double) this).doubleCoords = new double[nC];
2485+ } else {
2486+ ((Path2D.Float) this).floatCoords = new float[nC];
2487+ }
2488+
2489+ PATHDONE:
2490+ for (int i = 0; nT < 0 || i < nT; i++) {
2491+ boolean isdbl;
2492+ int npoints;
2493+ byte segtype;
2494+
2495+ byte serialtype = s.readByte();
2496+ switch (serialtype) {
2497+ case SERIAL_SEG_FLT_MOVETO:
2498+ isdbl = false;
2499+ npoints = 1;
2500+ segtype = SEG_MOVETO;
2501+ break;
2502+ case SERIAL_SEG_FLT_LINETO:
2503+ isdbl = false;
2504+ npoints = 1;
2505+ segtype = SEG_LINETO;
2506+ break;
2507+ case SERIAL_SEG_FLT_QUADTO:
2508+ isdbl = false;
2509+ npoints = 2;
2510+ segtype = SEG_QUADTO;
2511+ break;
2512+ case SERIAL_SEG_FLT_CUBICTO:
2513+ isdbl = false;
2514+ npoints = 3;
2515+ segtype = SEG_CUBICTO;
2516+ break;
2517+
2518+ case SERIAL_SEG_DBL_MOVETO:
2519+ isdbl = true;
2520+ npoints = 1;
2521+ segtype = SEG_MOVETO;
2522+ break;
2523+ case SERIAL_SEG_DBL_LINETO:
2524+ isdbl = true;
2525+ npoints = 1;
2526+ segtype = SEG_LINETO;
2527+ break;
2528+ case SERIAL_SEG_DBL_QUADTO:
2529+ isdbl = true;
2530+ npoints = 2;
2531+ segtype = SEG_QUADTO;
2532+ break;
2533+ case SERIAL_SEG_DBL_CUBICTO:
2534+ isdbl = true;
2535+ npoints = 3;
2536+ segtype = SEG_CUBICTO;
2537+ break;
2538+
2539+ case SERIAL_SEG_CLOSE:
2540+ isdbl = false;
2541+ npoints = 0;
2542+ segtype = SEG_CLOSE;
2543+ break;
2544+
2545+ case SERIAL_PATH_END:
2546+ if (nT < 0) {
2547+ break PATHDONE;
2548+ }
2549+ throw new StreamCorruptedException("unexpected PATH_END");
2550+
2551+ default:
2552+ throw new StreamCorruptedException("unrecognized path type");
2553+ }
2554+ needRoom(segtype != SEG_MOVETO, npoints * 2);
2555+ if (isdbl) {
2556+ while (--npoints >= 0) {
2557+ append(s.readDouble(), s.readDouble());
2558+ }
2559+ } else {
2560+ while (--npoints >= 0) {
2561+ append(s.readFloat(), s.readFloat());
2562+ }
2563+ }
2564+ pointTypes[numTypes++] = segtype;
2565+ }
2566+ if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2567+ throw new StreamCorruptedException("missing PATH_END");
2568+ }
2569+ }
2570+
2571+ static abstract class Iterator implements PathIterator {
2572+ int typeIdx;
2573+ int pointIdx;
2574+ Path2D path;
2575+
2576+ static final int curvecoords[] = {2, 2, 4, 6, 0};
2577+
2578+ Iterator(Path2D path) {
2579+ this.path = path;
2580+ }
2581+
2582+ public int getWindingRule() {
2583+ return path.getWindingRule();
2584+ }
2585+
2586+ public boolean isDone() {
2587+ return (typeIdx >= path.numTypes);
2588+ }
2589+
2590+ public void next() {
2591+ int type = path.pointTypes[typeIdx++];
2592+ pointIdx += curvecoords[type];
2593+ }
2594+ }
2595+}
java/pkg/java/awt/geom/PathIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/PathIterator.java+215−0
@@ -0,0 +1,215 @@
1+/*
2+ * Copyright (c) 1997, 2000, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+/**
29+ * The <code>PathIterator</code> interface provides the mechanism
30+ * for objects that implement the {@link java.awt.Shape Shape}
31+ * interface to return the geometry of their boundary by allowing
32+ * a caller to retrieve the path of that boundary a segment at a
33+ * time. This interface allows these objects to retrieve the path of
34+ * their boundary a segment at a time by using 1st through 3rd order
35+ * B&eacute;zier curves, which are lines and quadratic or cubic
36+ * B&eacute;zier splines.
37+ * <p>
38+ * Multiple subpaths can be expressed by using a "MOVETO" segment to
39+ * create a discontinuity in the geometry to move from the end of
40+ * one subpath to the beginning of the next.
41+ * <p>
42+ * Each subpath can be closed manually by ending the last segment in
43+ * the subpath on the same coordinate as the beginning "MOVETO" segment
44+ * for that subpath or by using a "CLOSE" segment to append a line
45+ * segment from the last point back to the first.
46+ * Be aware that manually closing an outline as opposed to using a
47+ * "CLOSE" segment to close the path might result in different line
48+ * style decorations being used at the end points of the subpath.
49+ * For example, the {@link java.awt.BasicStroke BasicStroke} object
50+ * uses a line "JOIN" decoration to connect the first and last points
51+ * if a "CLOSE" segment is encountered, whereas simply ending the path
52+ * on the same coordinate as the beginning coordinate results in line
53+ * "CAP" decorations being used at the ends.
54+ *
55+ * @see java.awt.Shape
56+ * @see java.awt.BasicStroke
57+ *
58+ * @author Jim Graham
59+ */
60+public interface PathIterator {
61+ /**
62+ * The winding rule constant for specifying an even-odd rule
63+ * for determining the interior of a path.
64+ * The even-odd rule specifies that a point lies inside the
65+ * path if a ray drawn in any direction from that point to
66+ * infinity is crossed by path segments an odd number of times.
67+ */
68+ public static final int WIND_EVEN_ODD = 0;
69+
70+ /**
71+ * The winding rule constant for specifying a non-zero rule
72+ * for determining the interior of a path.
73+ * The non-zero rule specifies that a point lies inside the
74+ * path if a ray drawn in any direction from that point to
75+ * infinity is crossed by path segments a different number
76+ * of times in the counter-clockwise direction than the
77+ * clockwise direction.
78+ */
79+ public static final int WIND_NON_ZERO = 1;
80+
81+ /**
82+ * The segment type constant for a point that specifies the
83+ * starting location for a new subpath.
84+ */
85+ public static final int SEG_MOVETO = 0;
86+
87+ /**
88+ * The segment type constant for a point that specifies the
89+ * end point of a line to be drawn from the most recently
90+ * specified point.
91+ */
92+ public static final int SEG_LINETO = 1;
93+
94+ /**
95+ * The segment type constant for the pair of points that specify
96+ * a quadratic parametric curve to be drawn from the most recently
97+ * specified point.
98+ * The curve is interpolated by solving the parametric control
99+ * equation in the range <code>(t=[0..1])</code> using
100+ * the most recently specified (current) point (CP),
101+ * the first control point (P1),
102+ * and the final interpolated control point (P2).
103+ * The parametric control equation for this curve is:
104+ * <pre>
105+ * P(t) = B(2,0)*CP + B(2,1)*P1 + B(2,2)*P2
106+ * 0 &lt;= t &lt;= 1
107+ *
108+ * B(n,m) = mth coefficient of nth degree Bernstein polynomial
109+ * = C(n,m) * t^(m) * (1 - t)^(n-m)
110+ * C(n,m) = Combinations of n things, taken m at a time
111+ * = n! / (m! * (n-m)!)
112+ * </pre>
113+ */
114+ public static final int SEG_QUADTO = 2;
115+
116+ /**
117+ * The segment type constant for the set of 3 points that specify
118+ * a cubic parametric curve to be drawn from the most recently
119+ * specified point.
120+ * The curve is interpolated by solving the parametric control
121+ * equation in the range <code>(t=[0..1])</code> using
122+ * the most recently specified (current) point (CP),
123+ * the first control point (P1),
124+ * the second control point (P2),
125+ * and the final interpolated control point (P3).
126+ * The parametric control equation for this curve is:
127+ * <pre>
128+ * P(t) = B(3,0)*CP + B(3,1)*P1 + B(3,2)*P2 + B(3,3)*P3
129+ * 0 &lt;= t &lt;= 1
130+ *
131+ * B(n,m) = mth coefficient of nth degree Bernstein polynomial
132+ * = C(n,m) * t^(m) * (1 - t)^(n-m)
133+ * C(n,m) = Combinations of n things, taken m at a time
134+ * = n! / (m! * (n-m)!)
135+ * </pre>
136+ * This form of curve is commonly known as a B&eacute;zier curve.
137+ */
138+ public static final int SEG_CUBICTO = 3;
139+
140+ /**
141+ * The segment type constant that specifies that
142+ * the preceding subpath should be closed by appending a line segment
143+ * back to the point corresponding to the most recent SEG_MOVETO.
144+ */
145+ public static final int SEG_CLOSE = 4;
146+
147+ /**
148+ * Returns the winding rule for determining the interior of the
149+ * path.
150+ * @return the winding rule.
151+ * @see #WIND_EVEN_ODD
152+ * @see #WIND_NON_ZERO
153+ */
154+ public int getWindingRule();
155+
156+ /**
157+ * Tests if the iteration is complete.
158+ * @return <code>true</code> if all the segments have
159+ * been read; <code>false</code> otherwise.
160+ */
161+ public boolean isDone();
162+
163+ /**
164+ * Moves the iterator to the next segment of the path forwards
165+ * along the primary direction of traversal as long as there are
166+ * more points in that direction.
167+ */
168+ public void next();
169+
170+ /**
171+ * Returns the coordinates and type of the current path segment in
172+ * the iteration.
173+ * The return value is the path-segment type:
174+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
175+ * A float array of length 6 must be passed in and can be used to
176+ * store the coordinates of the point(s).
177+ * Each point is stored as a pair of float x,y coordinates.
178+ * SEG_MOVETO and SEG_LINETO types returns one point,
179+ * SEG_QUADTO returns two points,
180+ * SEG_CUBICTO returns 3 points
181+ * and SEG_CLOSE does not return any points.
182+ * @param coords an array that holds the data returned from
183+ * this method
184+ * @return the path-segment type of the current path segment.
185+ * @see #SEG_MOVETO
186+ * @see #SEG_LINETO
187+ * @see #SEG_QUADTO
188+ * @see #SEG_CUBICTO
189+ * @see #SEG_CLOSE
190+ */
191+ public int currentSegment(float[] coords);
192+
193+ /**
194+ * Returns the coordinates and type of the current path segment in
195+ * the iteration.
196+ * The return value is the path-segment type:
197+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
198+ * A double array of length 6 must be passed in and can be used to
199+ * store the coordinates of the point(s).
200+ * Each point is stored as a pair of double x,y coordinates.
201+ * SEG_MOVETO and SEG_LINETO types returns one point,
202+ * SEG_QUADTO returns two points,
203+ * SEG_CUBICTO returns 3 points
204+ * and SEG_CLOSE does not return any points.
205+ * @param coords an array that holds the data returned from
206+ * this method
207+ * @return the path-segment type of the current path segment.
208+ * @see #SEG_MOVETO
209+ * @see #SEG_LINETO
210+ * @see #SEG_QUADTO
211+ * @see #SEG_CUBICTO
212+ * @see #SEG_CLOSE
213+ */
214+ public int currentSegment(double[] coords);
215+}
java/pkg/java/awt/geom/Point2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Point2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Point2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Point2D.java+428−0
@@ -0,0 +1,428 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.io.Serializable;
29+
30+/**
31+ * The <code>Point2D</code> class defines a point representing a location
32+ * in {@code (x,y)} coordinate space.
33+ * <p>
34+ * This class is only the abstract superclass for all objects that
35+ * store a 2D coordinate.
36+ * The actual storage representation of the coordinates is left to
37+ * the subclass.
38+ *
39+ * @author Jim Graham
40+ * @since 1.2
41+ */
42+public abstract class Point2D implements Cloneable {
43+
44+ /**
45+ * The <code>Float</code> class defines a point specified in float
46+ * precision.
47+ * @since 1.2
48+ */
49+ public static class Float extends Point2D implements Serializable {
50+ /**
51+ * The X coordinate of this <code>Point2D</code>.
52+ * @since 1.2
53+ * @serial
54+ */
55+ public float x;
56+
57+ /**
58+ * The Y coordinate of this <code>Point2D</code>.
59+ * @since 1.2
60+ * @serial
61+ */
62+ public float y;
63+
64+ /**
65+ * Constructs and initializes a <code>Point2D</code> with
66+ * coordinates (0,&nbsp;0).
67+ * @since 1.2
68+ */
69+ public Float() {
70+ }
71+
72+ /**
73+ * Constructs and initializes a <code>Point2D</code> with
74+ * the specified coordinates.
75+ *
76+ * @param x the X coordinate of the newly
77+ * constructed <code>Point2D</code>
78+ * @param y the Y coordinate of the newly
79+ * constructed <code>Point2D</code>
80+ * @since 1.2
81+ */
82+ public Float(float x, float y) {
83+ this.x = x;
84+ this.y = y;
85+ }
86+
87+ /**
88+ * {@inheritDoc}
89+ * @since 1.2
90+ */
91+ public double getX() {
92+ return (double) x;
93+ }
94+
95+ /**
96+ * {@inheritDoc}
97+ * @since 1.2
98+ */
99+ public double getY() {
100+ return (double) y;
101+ }
102+
103+ /**
104+ * {@inheritDoc}
105+ * @since 1.2
106+ */
107+ public void setLocation(double x, double y) {
108+ this.x = (float) x;
109+ this.y = (float) y;
110+ }
111+
112+ /**
113+ * Sets the location of this <code>Point2D</code> to the
114+ * specified <code>float</code> coordinates.
115+ *
116+ * @param x the new X coordinate of this {@code Point2D}
117+ * @param y the new Y coordinate of this {@code Point2D}
118+ * @since 1.2
119+ */
120+ public void setLocation(float x, float y) {
121+ this.x = x;
122+ this.y = y;
123+ }
124+
125+ /**
126+ * Returns a <code>String</code> that represents the value
127+ * of this <code>Point2D</code>.
128+ * @return a string representation of this <code>Point2D</code>.
129+ * @since 1.2
130+ */
131+ public String toString() {
132+ return "Point2D.Float["+x+", "+y+"]";
133+ }
134+
135+ /*
136+ * JDK 1.6 serialVersionUID
137+ */
138+ private static final long serialVersionUID = -2870572449815403710L;
139+ }
140+
141+ /**
142+ * The <code>Double</code> class defines a point specified in
143+ * <code>double</code> precision.
144+ * @since 1.2
145+ */
146+ public static class Double extends Point2D implements Serializable {
147+ /**
148+ * The X coordinate of this <code>Point2D</code>.
149+ * @since 1.2
150+ * @serial
151+ */
152+ public double x;
153+
154+ /**
155+ * The Y coordinate of this <code>Point2D</code>.
156+ * @since 1.2
157+ * @serial
158+ */
159+ public double y;
160+
161+ /**
162+ * Constructs and initializes a <code>Point2D</code> with
163+ * coordinates (0,&nbsp;0).
164+ * @since 1.2
165+ */
166+ public Double() {
167+ }
168+
169+ /**
170+ * Constructs and initializes a <code>Point2D</code> with the
171+ * specified coordinates.
172+ *
173+ * @param x the X coordinate of the newly
174+ * constructed <code>Point2D</code>
175+ * @param y the Y coordinate of the newly
176+ * constructed <code>Point2D</code>
177+ * @since 1.2
178+ */
179+ public Double(double x, double y) {
180+ this.x = x;
181+ this.y = y;
182+ }
183+
184+ /**
185+ * {@inheritDoc}
186+ * @since 1.2
187+ */
188+ public double getX() {
189+ return x;
190+ }
191+
192+ /**
193+ * {@inheritDoc}
194+ * @since 1.2
195+ */
196+ public double getY() {
197+ return y;
198+ }
199+
200+ /**
201+ * {@inheritDoc}
202+ * @since 1.2
203+ */
204+ public void setLocation(double x, double y) {
205+ this.x = x;
206+ this.y = y;
207+ }
208+
209+ /**
210+ * Returns a <code>String</code> that represents the value
211+ * of this <code>Point2D</code>.
212+ * @return a string representation of this <code>Point2D</code>.
213+ * @since 1.2
214+ */
215+ public String toString() {
216+ return "Point2D.Double["+x+", "+y+"]";
217+ }
218+
219+ /*
220+ * JDK 1.6 serialVersionUID
221+ */
222+ private static final long serialVersionUID = 6150783262733311327L;
223+ }
224+
225+ /**
226+ * This is an abstract class that cannot be instantiated directly.
227+ * Type-specific implementation subclasses are available for
228+ * instantiation and provide a number of formats for storing
229+ * the information necessary to satisfy the various accessor
230+ * methods below.
231+ *
232+ * @see java.awt.geom.Point2D.Float
233+ * @see java.awt.geom.Point2D.Double
234+ * @see java.awt.Point
235+ * @since 1.2
236+ */
237+ protected Point2D() {
238+ }
239+
240+ /**
241+ * Returns the X coordinate of this <code>Point2D</code> in
242+ * <code>double</code> precision.
243+ * @return the X coordinate of this <code>Point2D</code>.
244+ * @since 1.2
245+ */
246+ public abstract double getX();
247+
248+ /**
249+ * Returns the Y coordinate of this <code>Point2D</code> in
250+ * <code>double</code> precision.
251+ * @return the Y coordinate of this <code>Point2D</code>.
252+ * @since 1.2
253+ */
254+ public abstract double getY();
255+
256+ /**
257+ * Sets the location of this <code>Point2D</code> to the
258+ * specified <code>double</code> coordinates.
259+ *
260+ * @param x the new X coordinate of this {@code Point2D}
261+ * @param y the new Y coordinate of this {@code Point2D}
262+ * @since 1.2
263+ */
264+ public abstract void setLocation(double x, double y);
265+
266+ /**
267+ * Sets the location of this <code>Point2D</code> to the same
268+ * coordinates as the specified <code>Point2D</code> object.
269+ * @param p the specified <code>Point2D</code> to which to set
270+ * this <code>Point2D</code>
271+ * @since 1.2
272+ */
273+ public void setLocation(Point2D p) {
274+ setLocation(p.getX(), p.getY());
275+ }
276+
277+ /**
278+ * Returns the square of the distance between two points.
279+ *
280+ * @param x1 the X coordinate of the first specified point
281+ * @param y1 the Y coordinate of the first specified point
282+ * @param x2 the X coordinate of the second specified point
283+ * @param y2 the Y coordinate of the second specified point
284+ * @return the square of the distance between the two
285+ * sets of specified coordinates.
286+ * @since 1.2
287+ */
288+ public static double distanceSq(double x1, double y1,
289+ double x2, double y2)
290+ {
291+ x1 -= x2;
292+ y1 -= y2;
293+ return (x1 * x1 + y1 * y1);
294+ }
295+
296+ /**
297+ * Returns the distance between two points.
298+ *
299+ * @param x1 the X coordinate of the first specified point
300+ * @param y1 the Y coordinate of the first specified point
301+ * @param x2 the X coordinate of the second specified point
302+ * @param y2 the Y coordinate of the second specified point
303+ * @return the distance between the two sets of specified
304+ * coordinates.
305+ * @since 1.2
306+ */
307+ public static double distance(double x1, double y1,
308+ double x2, double y2)
309+ {
310+ x1 -= x2;
311+ y1 -= y2;
312+ return Math.sqrt(x1 * x1 + y1 * y1);
313+ }
314+
315+ /**
316+ * Returns the square of the distance from this
317+ * <code>Point2D</code> to a specified point.
318+ *
319+ * @param px the X coordinate of the specified point to be measured
320+ * against this <code>Point2D</code>
321+ * @param py the Y coordinate of the specified point to be measured
322+ * against this <code>Point2D</code>
323+ * @return the square of the distance between this
324+ * <code>Point2D</code> and the specified point.
325+ * @since 1.2
326+ */
327+ public double distanceSq(double px, double py) {
328+ px -= getX();
329+ py -= getY();
330+ return (px * px + py * py);
331+ }
332+
333+ /**
334+ * Returns the square of the distance from this
335+ * <code>Point2D</code> to a specified <code>Point2D</code>.
336+ *
337+ * @param pt the specified point to be measured
338+ * against this <code>Point2D</code>
339+ * @return the square of the distance between this
340+ * <code>Point2D</code> to a specified <code>Point2D</code>.
341+ * @since 1.2
342+ */
343+ public double distanceSq(Point2D pt) {
344+ double px = pt.getX() - this.getX();
345+ double py = pt.getY() - this.getY();
346+ return (px * px + py * py);
347+ }
348+
349+ /**
350+ * Returns the distance from this <code>Point2D</code> to
351+ * a specified point.
352+ *
353+ * @param px the X coordinate of the specified point to be measured
354+ * against this <code>Point2D</code>
355+ * @param py the Y coordinate of the specified point to be measured
356+ * against this <code>Point2D</code>
357+ * @return the distance between this <code>Point2D</code>
358+ * and a specified point.
359+ * @since 1.2
360+ */
361+ public double distance(double px, double py) {
362+ px -= getX();
363+ py -= getY();
364+ return Math.sqrt(px * px + py * py);
365+ }
366+
367+ /**
368+ * Returns the distance from this <code>Point2D</code> to a
369+ * specified <code>Point2D</code>.
370+ *
371+ * @param pt the specified point to be measured
372+ * against this <code>Point2D</code>
373+ * @return the distance between this <code>Point2D</code> and
374+ * the specified <code>Point2D</code>.
375+ * @since 1.2
376+ */
377+ public double distance(Point2D pt) {
378+ double px = pt.getX() - this.getX();
379+ double py = pt.getY() - this.getY();
380+ return Math.sqrt(px * px + py * py);
381+ }
382+
383+ /**
384+ * Creates a new object of the same class and with the
385+ * same contents as this object.
386+ * @return a clone of this instance.
387+ * @exception OutOfMemoryError if there is not enough memory.
388+ * @see java.lang.Cloneable
389+ * @since 1.2
390+ */
391+ public Object clone() {
392+ try {
393+ return super.clone();
394+ } catch (CloneNotSupportedException e) {
395+ // this shouldn't happen, since we are Cloneable
396+ throw new InternalError();
397+ }
398+ }
399+
400+ /**
401+ * Returns the hashcode for this <code>Point2D</code>.
402+ * @return a hash code for this <code>Point2D</code>.
403+ */
404+ public int hashCode() {
405+ long bits = java.lang.Double.doubleToLongBits(getX());
406+ bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
407+ return (((int) bits) ^ ((int) (bits >> 32)));
408+ }
409+
410+ /**
411+ * Determines whether or not two points are equal. Two instances of
412+ * <code>Point2D</code> are equal if the values of their
413+ * <code>x</code> and <code>y</code> member fields, representing
414+ * their position in the coordinate space, are the same.
415+ * @param obj an object to be compared with this <code>Point2D</code>
416+ * @return <code>true</code> if the object to be compared is
417+ * an instance of <code>Point2D</code> and has
418+ * the same values; <code>false</code> otherwise.
419+ * @since 1.2
420+ */
421+ public boolean equals(Object obj) {
422+ if (obj instanceof Point2D) {
423+ Point2D p2d = (Point2D) obj;
424+ return (getX() == p2d.getX()) && (getY() == p2d.getY());
425+ }
426+ return super.equals(obj);
427+ }
428+}
java/pkg/java/awt/geom/QuadCurve2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/QuadCurve2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/QuadCurve2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/QuadCurve2D.java+1401−0
@@ -0,0 +1,1401 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.awt.Rectangle;
30+import java.io.Serializable;
31+import sun.awt.geom.Curve;
32+
33+/**
34+ * The <code>QuadCurve2D</code> class defines a quadratic parametric curve
35+ * segment in {@code (x,y)} coordinate space.
36+ * <p>
37+ * This class is only the abstract superclass for all objects that
38+ * store a 2D quadratic curve segment.
39+ * The actual storage representation of the coordinates is left to
40+ * the subclass.
41+ *
42+ * @author Jim Graham
43+ * @since 1.2
44+ */
45+public abstract class QuadCurve2D implements Shape, Cloneable {
46+
47+ /**
48+ * A quadratic parametric curve segment specified with
49+ * {@code float} coordinates.
50+ *
51+ * @since 1.2
52+ */
53+ public static class Float extends QuadCurve2D implements Serializable {
54+ /**
55+ * The X coordinate of the start point of the quadratic curve
56+ * segment.
57+ * @since 1.2
58+ * @serial
59+ */
60+ public float x1;
61+
62+ /**
63+ * The Y coordinate of the start point of the quadratic curve
64+ * segment.
65+ * @since 1.2
66+ * @serial
67+ */
68+ public float y1;
69+
70+ /**
71+ * The X coordinate of the control point of the quadratic curve
72+ * segment.
73+ * @since 1.2
74+ * @serial
75+ */
76+ public float ctrlx;
77+
78+ /**
79+ * The Y coordinate of the control point of the quadratic curve
80+ * segment.
81+ * @since 1.2
82+ * @serial
83+ */
84+ public float ctrly;
85+
86+ /**
87+ * The X coordinate of the end point of the quadratic curve
88+ * segment.
89+ * @since 1.2
90+ * @serial
91+ */
92+ public float x2;
93+
94+ /**
95+ * The Y coordinate of the end point of the quadratic curve
96+ * segment.
97+ * @since 1.2
98+ * @serial
99+ */
100+ public float y2;
101+
102+ /**
103+ * Constructs and initializes a <code>QuadCurve2D</code> with
104+ * coordinates (0, 0, 0, 0, 0, 0).
105+ * @since 1.2
106+ */
107+ public Float() {
108+ }
109+
110+ /**
111+ * Constructs and initializes a <code>QuadCurve2D</code> from the
112+ * specified {@code float} coordinates.
113+ *
114+ * @param x1 the X coordinate of the start point
115+ * @param y1 the Y coordinate of the start point
116+ * @param ctrlx the X coordinate of the control point
117+ * @param ctrly the Y coordinate of the control point
118+ * @param x2 the X coordinate of the end point
119+ * @param y2 the Y coordinate of the end point
120+ * @since 1.2
121+ */
122+ public Float(float x1, float y1,
123+ float ctrlx, float ctrly,
124+ float x2, float y2)
125+ {
126+ setCurve(x1, y1, ctrlx, ctrly, x2, y2);
127+ }
128+
129+ /**
130+ * {@inheritDoc}
131+ * @since 1.2
132+ */
133+ public double getX1() {
134+ return (double) x1;
135+ }
136+
137+ /**
138+ * {@inheritDoc}
139+ * @since 1.2
140+ */
141+ public double getY1() {
142+ return (double) y1;
143+ }
144+
145+ /**
146+ * {@inheritDoc}
147+ * @since 1.2
148+ */
149+ public Point2D getP1() {
150+ return new Point2D.Float(x1, y1);
151+ }
152+
153+ /**
154+ * {@inheritDoc}
155+ * @since 1.2
156+ */
157+ public double getCtrlX() {
158+ return (double) ctrlx;
159+ }
160+
161+ /**
162+ * {@inheritDoc}
163+ * @since 1.2
164+ */
165+ public double getCtrlY() {
166+ return (double) ctrly;
167+ }
168+
169+ /**
170+ * {@inheritDoc}
171+ * @since 1.2
172+ */
173+ public Point2D getCtrlPt() {
174+ return new Point2D.Float(ctrlx, ctrly);
175+ }
176+
177+ /**
178+ * {@inheritDoc}
179+ * @since 1.2
180+ */
181+ public double getX2() {
182+ return (double) x2;
183+ }
184+
185+ /**
186+ * {@inheritDoc}
187+ * @since 1.2
188+ */
189+ public double getY2() {
190+ return (double) y2;
191+ }
192+
193+ /**
194+ * {@inheritDoc}
195+ * @since 1.2
196+ */
197+ public Point2D getP2() {
198+ return new Point2D.Float(x2, y2);
199+ }
200+
201+ /**
202+ * {@inheritDoc}
203+ * @since 1.2
204+ */
205+ public void setCurve(double x1, double y1,
206+ double ctrlx, double ctrly,
207+ double x2, double y2)
208+ {
209+ this.x1 = (float) x1;
210+ this.y1 = (float) y1;
211+ this.ctrlx = (float) ctrlx;
212+ this.ctrly = (float) ctrly;
213+ this.x2 = (float) x2;
214+ this.y2 = (float) y2;
215+ }
216+
217+ /**
218+ * Sets the location of the end points and control point of this curve
219+ * to the specified {@code float} coordinates.
220+ *
221+ * @param x1 the X coordinate of the start point
222+ * @param y1 the Y coordinate of the start point
223+ * @param ctrlx the X coordinate of the control point
224+ * @param ctrly the Y coordinate of the control point
225+ * @param x2 the X coordinate of the end point
226+ * @param y2 the Y coordinate of the end point
227+ * @since 1.2
228+ */
229+ public void setCurve(float x1, float y1,
230+ float ctrlx, float ctrly,
231+ float x2, float y2)
232+ {
233+ this.x1 = x1;
234+ this.y1 = y1;
235+ this.ctrlx = ctrlx;
236+ this.ctrly = ctrly;
237+ this.x2 = x2;
238+ this.y2 = y2;
239+ }
240+
241+ /**
242+ * {@inheritDoc}
243+ * @since 1.2
244+ */
245+ public Rectangle2D getBounds2D() {
246+ float left = Math.min(Math.min(x1, x2), ctrlx);
247+ float top = Math.min(Math.min(y1, y2), ctrly);
248+ float right = Math.max(Math.max(x1, x2), ctrlx);
249+ float bottom = Math.max(Math.max(y1, y2), ctrly);
250+ return new Rectangle2D.Float(left, top,
251+ right - left, bottom - top);
252+ }
253+
254+ /*
255+ * JDK 1.6 serialVersionUID
256+ */
257+ private static final long serialVersionUID = -8511188402130719609L;
258+ }
259+
260+ /**
261+ * A quadratic parametric curve segment specified with
262+ * {@code double} coordinates.
263+ *
264+ * @since 1.2
265+ */
266+ public static class Double extends QuadCurve2D implements Serializable {
267+ /**
268+ * The X coordinate of the start point of the quadratic curve
269+ * segment.
270+ * @since 1.2
271+ * @serial
272+ */
273+ public double x1;
274+
275+ /**
276+ * The Y coordinate of the start point of the quadratic curve
277+ * segment.
278+ * @since 1.2
279+ * @serial
280+ */
281+ public double y1;
282+
283+ /**
284+ * The X coordinate of the control point of the quadratic curve
285+ * segment.
286+ * @since 1.2
287+ * @serial
288+ */
289+ public double ctrlx;
290+
291+ /**
292+ * The Y coordinate of the control point of the quadratic curve
293+ * segment.
294+ * @since 1.2
295+ * @serial
296+ */
297+ public double ctrly;
298+
299+ /**
300+ * The X coordinate of the end point of the quadratic curve
301+ * segment.
302+ * @since 1.2
303+ * @serial
304+ */
305+ public double x2;
306+
307+ /**
308+ * The Y coordinate of the end point of the quadratic curve
309+ * segment.
310+ * @since 1.2
311+ * @serial
312+ */
313+ public double y2;
314+
315+ /**
316+ * Constructs and initializes a <code>QuadCurve2D</code> with
317+ * coordinates (0, 0, 0, 0, 0, 0).
318+ * @since 1.2
319+ */
320+ public Double() {
321+ }
322+
323+ /**
324+ * Constructs and initializes a <code>QuadCurve2D</code> from the
325+ * specified {@code double} coordinates.
326+ *
327+ * @param x1 the X coordinate of the start point
328+ * @param y1 the Y coordinate of the start point
329+ * @param ctrlx the X coordinate of the control point
330+ * @param ctrly the Y coordinate of the control point
331+ * @param x2 the X coordinate of the end point
332+ * @param y2 the Y coordinate of the end point
333+ * @since 1.2
334+ */
335+ public Double(double x1, double y1,
336+ double ctrlx, double ctrly,
337+ double x2, double y2)
338+ {
339+ setCurve(x1, y1, ctrlx, ctrly, x2, y2);
340+ }
341+
342+ /**
343+ * {@inheritDoc}
344+ * @since 1.2
345+ */
346+ public double getX1() {
347+ return x1;
348+ }
349+
350+ /**
351+ * {@inheritDoc}
352+ * @since 1.2
353+ */
354+ public double getY1() {
355+ return y1;
356+ }
357+
358+ /**
359+ * {@inheritDoc}
360+ * @since 1.2
361+ */
362+ public Point2D getP1() {
363+ return new Point2D.Double(x1, y1);
364+ }
365+
366+ /**
367+ * {@inheritDoc}
368+ * @since 1.2
369+ */
370+ public double getCtrlX() {
371+ return ctrlx;
372+ }
373+
374+ /**
375+ * {@inheritDoc}
376+ * @since 1.2
377+ */
378+ public double getCtrlY() {
379+ return ctrly;
380+ }
381+
382+ /**
383+ * {@inheritDoc}
384+ * @since 1.2
385+ */
386+ public Point2D getCtrlPt() {
387+ return new Point2D.Double(ctrlx, ctrly);
388+ }
389+
390+ /**
391+ * {@inheritDoc}
392+ * @since 1.2
393+ */
394+ public double getX2() {
395+ return x2;
396+ }
397+
398+ /**
399+ * {@inheritDoc}
400+ * @since 1.2
401+ */
402+ public double getY2() {
403+ return y2;
404+ }
405+
406+ /**
407+ * {@inheritDoc}
408+ * @since 1.2
409+ */
410+ public Point2D getP2() {
411+ return new Point2D.Double(x2, y2);
412+ }
413+
414+ /**
415+ * {@inheritDoc}
416+ * @since 1.2
417+ */
418+ public void setCurve(double x1, double y1,
419+ double ctrlx, double ctrly,
420+ double x2, double y2)
421+ {
422+ this.x1 = x1;
423+ this.y1 = y1;
424+ this.ctrlx = ctrlx;
425+ this.ctrly = ctrly;
426+ this.x2 = x2;
427+ this.y2 = y2;
428+ }
429+
430+ /**
431+ * {@inheritDoc}
432+ * @since 1.2
433+ */
434+ public Rectangle2D getBounds2D() {
435+ double left = Math.min(Math.min(x1, x2), ctrlx);
436+ double top = Math.min(Math.min(y1, y2), ctrly);
437+ double right = Math.max(Math.max(x1, x2), ctrlx);
438+ double bottom = Math.max(Math.max(y1, y2), ctrly);
439+ return new Rectangle2D.Double(left, top,
440+ right - left, bottom - top);
441+ }
442+
443+ /*
444+ * JDK 1.6 serialVersionUID
445+ */
446+ private static final long serialVersionUID = 4217149928428559721L;
447+ }
448+
449+ /**
450+ * This is an abstract class that cannot be instantiated directly.
451+ * Type-specific implementation subclasses are available for
452+ * instantiation and provide a number of formats for storing
453+ * the information necessary to satisfy the various accessor
454+ * methods below.
455+ *
456+ * @see java.awt.geom.QuadCurve2D.Float
457+ * @see java.awt.geom.QuadCurve2D.Double
458+ * @since 1.2
459+ */
460+ protected QuadCurve2D() {
461+ }
462+
463+ /**
464+ * Returns the X coordinate of the start point in
465+ * <code>double</code> in precision.
466+ * @return the X coordinate of the start point.
467+ * @since 1.2
468+ */
469+ public abstract double getX1();
470+
471+ /**
472+ * Returns the Y coordinate of the start point in
473+ * <code>double</code> precision.
474+ * @return the Y coordinate of the start point.
475+ * @since 1.2
476+ */
477+ public abstract double getY1();
478+
479+ /**
480+ * Returns the start point.
481+ * @return a <code>Point2D</code> that is the start point of this
482+ * <code>QuadCurve2D</code>.
483+ * @since 1.2
484+ */
485+ public abstract Point2D getP1();
486+
487+ /**
488+ * Returns the X coordinate of the control point in
489+ * <code>double</code> precision.
490+ * @return X coordinate the control point
491+ * @since 1.2
492+ */
493+ public abstract double getCtrlX();
494+
495+ /**
496+ * Returns the Y coordinate of the control point in
497+ * <code>double</code> precision.
498+ * @return the Y coordinate of the control point.
499+ * @since 1.2
500+ */
501+ public abstract double getCtrlY();
502+
503+ /**
504+ * Returns the control point.
505+ * @return a <code>Point2D</code> that is the control point of this
506+ * <code>Point2D</code>.
507+ * @since 1.2
508+ */
509+ public abstract Point2D getCtrlPt();
510+
511+ /**
512+ * Returns the X coordinate of the end point in
513+ * <code>double</code> precision.
514+ * @return the x coordiante of the end point.
515+ * @since 1.2
516+ */
517+ public abstract double getX2();
518+
519+ /**
520+ * Returns the Y coordinate of the end point in
521+ * <code>double</code> precision.
522+ * @return the Y coordinate of the end point.
523+ * @since 1.2
524+ */
525+ public abstract double getY2();
526+
527+ /**
528+ * Returns the end point.
529+ * @return a <code>Point</code> object that is the end point
530+ * of this <code>Point2D</code>.
531+ * @since 1.2
532+ */
533+ public abstract Point2D getP2();
534+
535+ /**
536+ * Sets the location of the end points and control point of this curve
537+ * to the specified <code>double</code> coordinates.
538+ *
539+ * @param x1 the X coordinate of the start point
540+ * @param y1 the Y coordinate of the start point
541+ * @param ctrlx the X coordinate of the control point
542+ * @param ctrly the Y coordinate of the control point
543+ * @param x2 the X coordinate of the end point
544+ * @param y2 the Y coordinate of the end point
545+ * @since 1.2
546+ */
547+ public abstract void setCurve(double x1, double y1,
548+ double ctrlx, double ctrly,
549+ double x2, double y2);
550+
551+ /**
552+ * Sets the location of the end points and control points of this
553+ * <code>QuadCurve2D</code> to the <code>double</code> coordinates at
554+ * the specified offset in the specified array.
555+ * @param coords the array containing coordinate values
556+ * @param offset the index into the array from which to start
557+ * getting the coordinate values and assigning them to this
558+ * <code>QuadCurve2D</code>
559+ * @since 1.2
560+ */
561+ public void setCurve(double[] coords, int offset) {
562+ setCurve(coords[offset + 0], coords[offset + 1],
563+ coords[offset + 2], coords[offset + 3],
564+ coords[offset + 4], coords[offset + 5]);
565+ }
566+
567+ /**
568+ * Sets the location of the end points and control point of this
569+ * <code>QuadCurve2D</code> to the specified <code>Point2D</code>
570+ * coordinates.
571+ * @param p1 the start point
572+ * @param cp the control point
573+ * @param p2 the end point
574+ * @since 1.2
575+ */
576+ public void setCurve(Point2D p1, Point2D cp, Point2D p2) {
577+ setCurve(p1.getX(), p1.getY(),
578+ cp.getX(), cp.getY(),
579+ p2.getX(), p2.getY());
580+ }
581+
582+ /**
583+ * Sets the location of the end points and control points of this
584+ * <code>QuadCurve2D</code> to the coordinates of the
585+ * <code>Point2D</code> objects at the specified offset in
586+ * the specified array.
587+ * @param pts an array containing <code>Point2D</code> that define
588+ * coordinate values
589+ * @param offset the index into <code>pts</code> from which to start
590+ * getting the coordinate values and assigning them to this
591+ * <code>QuadCurve2D</code>
592+ * @since 1.2
593+ */
594+ public void setCurve(Point2D[] pts, int offset) {
595+ setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
596+ pts[offset + 1].getX(), pts[offset + 1].getY(),
597+ pts[offset + 2].getX(), pts[offset + 2].getY());
598+ }
599+
600+ /**
601+ * Sets the location of the end points and control point of this
602+ * <code>QuadCurve2D</code> to the same as those in the specified
603+ * <code>QuadCurve2D</code>.
604+ * @param c the specified <code>QuadCurve2D</code>
605+ * @since 1.2
606+ */
607+ public void setCurve(QuadCurve2D c) {
608+ setCurve(c.getX1(), c.getY1(),
609+ c.getCtrlX(), c.getCtrlY(),
610+ c.getX2(), c.getY2());
611+ }
612+
613+ /**
614+ * Returns the square of the flatness, or maximum distance of a
615+ * control point from the line connecting the end points, of the
616+ * quadratic curve specified by the indicated control points.
617+ *
618+ * @param x1 the X coordinate of the start point
619+ * @param y1 the Y coordinate of the start point
620+ * @param ctrlx the X coordinate of the control point
621+ * @param ctrly the Y coordinate of the control point
622+ * @param x2 the X coordinate of the end point
623+ * @param y2 the Y coordinate of the end point
624+ * @return the square of the flatness of the quadratic curve
625+ * defined by the specified coordinates.
626+ * @since 1.2
627+ */
628+ public static double getFlatnessSq(double x1, double y1,
629+ double ctrlx, double ctrly,
630+ double x2, double y2) {
631+ return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly);
632+ }
633+
634+ /**
635+ * Returns the flatness, or maximum distance of a
636+ * control point from the line connecting the end points, of the
637+ * quadratic curve specified by the indicated control points.
638+ *
639+ * @param x1 the X coordinate of the start point
640+ * @param y1 the Y coordinate of the start point
641+ * @param ctrlx the X coordinate of the control point
642+ * @param ctrly the Y coordinate of the control point
643+ * @param x2 the X coordinate of the end point
644+ * @param y2 the Y coordinate of the end point
645+ * @return the flatness of the quadratic curve defined by the
646+ * specified coordinates.
647+ * @since 1.2
648+ */
649+ public static double getFlatness(double x1, double y1,
650+ double ctrlx, double ctrly,
651+ double x2, double y2) {
652+ return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly);
653+ }
654+
655+ /**
656+ * Returns the square of the flatness, or maximum distance of a
657+ * control point from the line connecting the end points, of the
658+ * quadratic curve specified by the control points stored in the
659+ * indicated array at the indicated index.
660+ * @param coords an array containing coordinate values
661+ * @param offset the index into <code>coords</code> from which to
662+ * to start getting the values from the array
663+ * @return the flatness of the quadratic curve that is defined by the
664+ * values in the specified array at the specified index.
665+ * @since 1.2
666+ */
667+ public static double getFlatnessSq(double coords[], int offset) {
668+ return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1],
669+ coords[offset + 4], coords[offset + 5],
670+ coords[offset + 2], coords[offset + 3]);
671+ }
672+
673+ /**
674+ * Returns the flatness, or maximum distance of a
675+ * control point from the line connecting the end points, of the
676+ * quadratic curve specified by the control points stored in the
677+ * indicated array at the indicated index.
678+ * @param coords an array containing coordinate values
679+ * @param offset the index into <code>coords</code> from which to
680+ * start getting the coordinate values
681+ * @return the flatness of a quadratic curve defined by the
682+ * specified array at the specified offset.
683+ * @since 1.2
684+ */
685+ public static double getFlatness(double coords[], int offset) {
686+ return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1],
687+ coords[offset + 4], coords[offset + 5],
688+ coords[offset + 2], coords[offset + 3]);
689+ }
690+
691+ /**
692+ * Returns the square of the flatness, or maximum distance of a
693+ * control point from the line connecting the end points, of this
694+ * <code>QuadCurve2D</code>.
695+ * @return the square of the flatness of this
696+ * <code>QuadCurve2D</code>.
697+ * @since 1.2
698+ */
699+ public double getFlatnessSq() {
700+ return Line2D.ptSegDistSq(getX1(), getY1(),
701+ getX2(), getY2(),
702+ getCtrlX(), getCtrlY());
703+ }
704+
705+ /**
706+ * Returns the flatness, or maximum distance of a
707+ * control point from the line connecting the end points, of this
708+ * <code>QuadCurve2D</code>.
709+ * @return the flatness of this <code>QuadCurve2D</code>.
710+ * @since 1.2
711+ */
712+ public double getFlatness() {
713+ return Line2D.ptSegDist(getX1(), getY1(),
714+ getX2(), getY2(),
715+ getCtrlX(), getCtrlY());
716+ }
717+
718+ /**
719+ * Subdivides this <code>QuadCurve2D</code> and stores the resulting
720+ * two subdivided curves into the <code>left</code> and
721+ * <code>right</code> curve parameters.
722+ * Either or both of the <code>left</code> and <code>right</code>
723+ * objects can be the same as this <code>QuadCurve2D</code> or
724+ * <code>null</code>.
725+ * @param left the <code>QuadCurve2D</code> object for storing the
726+ * left or first half of the subdivided curve
727+ * @param right the <code>QuadCurve2D</code> object for storing the
728+ * right or second half of the subdivided curve
729+ * @since 1.2
730+ */
731+ public void subdivide(QuadCurve2D left, QuadCurve2D right) {
732+ subdivide(this, left, right);
733+ }
734+
735+ /**
736+ * Subdivides the quadratic curve specified by the <code>src</code>
737+ * parameter and stores the resulting two subdivided curves into the
738+ * <code>left</code> and <code>right</code> curve parameters.
739+ * Either or both of the <code>left</code> and <code>right</code>
740+ * objects can be the same as the <code>src</code> object or
741+ * <code>null</code>.
742+ * @param src the quadratic curve to be subdivided
743+ * @param left the <code>QuadCurve2D</code> object for storing the
744+ * left or first half of the subdivided curve
745+ * @param right the <code>QuadCurve2D</code> object for storing the
746+ * right or second half of the subdivided curve
747+ * @since 1.2
748+ */
749+ public static void subdivide(QuadCurve2D src,
750+ QuadCurve2D left,
751+ QuadCurve2D right) {
752+ double x1 = src.getX1();
753+ double y1 = src.getY1();
754+ double ctrlx = src.getCtrlX();
755+ double ctrly = src.getCtrlY();
756+ double x2 = src.getX2();
757+ double y2 = src.getY2();
758+ double ctrlx1 = (x1 + ctrlx) / 2.0;
759+ double ctrly1 = (y1 + ctrly) / 2.0;
760+ double ctrlx2 = (x2 + ctrlx) / 2.0;
761+ double ctrly2 = (y2 + ctrly) / 2.0;
762+ ctrlx = (ctrlx1 + ctrlx2) / 2.0;
763+ ctrly = (ctrly1 + ctrly2) / 2.0;
764+ if (left != null) {
765+ left.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx, ctrly);
766+ }
767+ if (right != null) {
768+ right.setCurve(ctrlx, ctrly, ctrlx2, ctrly2, x2, y2);
769+ }
770+ }
771+
772+ /**
773+ * Subdivides the quadratic curve specified by the coordinates
774+ * stored in the <code>src</code> array at indices
775+ * <code>srcoff</code> through <code>srcoff</code>&nbsp;+&nbsp;5
776+ * and stores the resulting two subdivided curves into the two
777+ * result arrays at the corresponding indices.
778+ * Either or both of the <code>left</code> and <code>right</code>
779+ * arrays can be <code>null</code> or a reference to the same array
780+ * and offset as the <code>src</code> array.
781+ * Note that the last point in the first subdivided curve is the
782+ * same as the first point in the second subdivided curve. Thus,
783+ * it is possible to pass the same array for <code>left</code> and
784+ * <code>right</code> and to use offsets such that
785+ * <code>rightoff</code> equals <code>leftoff</code> + 4 in order
786+ * to avoid allocating extra storage for this common point.
787+ * @param src the array holding the coordinates for the source curve
788+ * @param srcoff the offset into the array of the beginning of the
789+ * the 6 source coordinates
790+ * @param left the array for storing the coordinates for the first
791+ * half of the subdivided curve
792+ * @param leftoff the offset into the array of the beginning of the
793+ * the 6 left coordinates
794+ * @param right the array for storing the coordinates for the second
795+ * half of the subdivided curve
796+ * @param rightoff the offset into the array of the beginning of the
797+ * the 6 right coordinates
798+ * @since 1.2
799+ */
800+ public static void subdivide(double src[], int srcoff,
801+ double left[], int leftoff,
802+ double right[], int rightoff) {
803+ double x1 = src[srcoff + 0];
804+ double y1 = src[srcoff + 1];
805+ double ctrlx = src[srcoff + 2];
806+ double ctrly = src[srcoff + 3];
807+ double x2 = src[srcoff + 4];
808+ double y2 = src[srcoff + 5];
809+ if (left != null) {
810+ left[leftoff + 0] = x1;
811+ left[leftoff + 1] = y1;
812+ }
813+ if (right != null) {
814+ right[rightoff + 4] = x2;
815+ right[rightoff + 5] = y2;
816+ }
817+ x1 = (x1 + ctrlx) / 2.0;
818+ y1 = (y1 + ctrly) / 2.0;
819+ x2 = (x2 + ctrlx) / 2.0;
820+ y2 = (y2 + ctrly) / 2.0;
821+ ctrlx = (x1 + x2) / 2.0;
822+ ctrly = (y1 + y2) / 2.0;
823+ if (left != null) {
824+ left[leftoff + 2] = x1;
825+ left[leftoff + 3] = y1;
826+ left[leftoff + 4] = ctrlx;
827+ left[leftoff + 5] = ctrly;
828+ }
829+ if (right != null) {
830+ right[rightoff + 0] = ctrlx;
831+ right[rightoff + 1] = ctrly;
832+ right[rightoff + 2] = x2;
833+ right[rightoff + 3] = y2;
834+ }
835+ }
836+
837+ /**
838+ * Solves the quadratic whose coefficients are in the <code>eqn</code>
839+ * array and places the non-complex roots back into the same array,
840+ * returning the number of roots. The quadratic solved is represented
841+ * by the equation:
842+ * <pre>
843+ * eqn = {C, B, A};
844+ * ax^2 + bx + c = 0
845+ * </pre>
846+ * A return value of <code>-1</code> is used to distinguish a constant
847+ * equation, which might be always 0 or never 0, from an equation that
848+ * has no zeroes.
849+ * @param eqn the array that contains the quadratic coefficients
850+ * @return the number of roots, or <code>-1</code> if the equation is
851+ * a constant
852+ * @since 1.2
853+ */
854+ public static int solveQuadratic(double eqn[]) {
855+ return solveQuadratic(eqn, eqn);
856+ }
857+
858+ /**
859+ * Solves the quadratic whose coefficients are in the <code>eqn</code>
860+ * array and places the non-complex roots into the <code>res</code>
861+ * array, returning the number of roots.
862+ * The quadratic solved is represented by the equation:
863+ * <pre>
864+ * eqn = {C, B, A};
865+ * ax^2 + bx + c = 0
866+ * </pre>
867+ * A return value of <code>-1</code> is used to distinguish a constant
868+ * equation, which might be always 0 or never 0, from an equation that
869+ * has no zeroes.
870+ * @param eqn the specified array of coefficients to use to solve
871+ * the quadratic equation
872+ * @param res the array that contains the non-complex roots
873+ * resulting from the solution of the quadratic equation
874+ * @return the number of roots, or <code>-1</code> if the equation is
875+ * a constant.
876+ * @since 1.3
877+ */
878+ public static int solveQuadratic(double eqn[], double res[]) {
879+ double a = eqn[2];
880+ double b = eqn[1];
881+ double c = eqn[0];
882+ int roots = 0;
883+ if (a == 0.0) {
884+ // The quadratic parabola has degenerated to a line.
885+ if (b == 0.0) {
886+ // The line has degenerated to a constant.
887+ return -1;
888+ }
889+ res[roots++] = -c / b;
890+ } else {
891+ // From Numerical Recipes, 5.6, Quadratic and Cubic Equations
892+ double d = b * b - 4.0 * a * c;
893+ if (d < 0.0) {
894+ // If d < 0.0, then there are no roots
895+ return 0;
896+ }
897+ d = Math.sqrt(d);
898+ // For accuracy, calculate one root using:
899+ // (-b +/- d) / 2a
900+ // and the other using:
901+ // 2c / (-b +/- d)
902+ // Choose the sign of the +/- so that b+d gets larger in magnitude
903+ if (b < 0.0) {
904+ d = -d;
905+ }
906+ double q = (b + d) / -2.0;
907+ // We already tested a for being 0 above
908+ res[roots++] = q / a;
909+ if (q != 0.0) {
910+ res[roots++] = c / q;
911+ }
912+ }
913+ return roots;
914+ }
915+
916+ /**
917+ * {@inheritDoc}
918+ * @since 1.2
919+ */
920+ public boolean contains(double x, double y) {
921+
922+ double x1 = getX1();
923+ double y1 = getY1();
924+ double xc = getCtrlX();
925+ double yc = getCtrlY();
926+ double x2 = getX2();
927+ double y2 = getY2();
928+
929+ /*
930+ * We have a convex shape bounded by quad curve Pc(t)
931+ * and ine Pl(t).
932+ *
933+ * P1 = (x1, y1) - start point of curve
934+ * P2 = (x2, y2) - end point of curve
935+ * Pc = (xc, yc) - control point
936+ *
937+ * Pq(t) = P1*(1 - t)^2 + 2*Pc*t*(1 - t) + P2*t^2 =
938+ * = (P1 - 2*Pc + P2)*t^2 + 2*(Pc - P1)*t + P1
939+ * Pl(t) = P1*(1 - t) + P2*t
940+ * t = [0:1]
941+ *
942+ * P = (x, y) - point of interest
943+ *
944+ * Let's look at second derivative of quad curve equation:
945+ *
946+ * Pq''(t) = 2 * (P1 - 2 * Pc + P2) = Pq''
947+ * It's constant vector.
948+ *
949+ * Let's draw a line through P to be parallel to this
950+ * vector and find the intersection of the quad curve
951+ * and the line.
952+ *
953+ * Pq(t) is point of intersection if system of equations
954+ * below has the solution.
955+ *
956+ * L(s) = P + Pq''*s == Pq(t)
957+ * Pq''*s + (P - Pq(t)) == 0
958+ *
959+ * | xq''*s + (x - xq(t)) == 0
960+ * | yq''*s + (y - yq(t)) == 0
961+ *
962+ * This system has the solution if rank of its matrix equals to 1.
963+ * That is, determinant of the matrix should be zero.
964+ *
965+ * (y - yq(t))*xq'' == (x - xq(t))*yq''
966+ *
967+ * Let's solve this equation with 't' variable.
968+ * Also let kx = x1 - 2*xc + x2
969+ * ky = y1 - 2*yc + y2
970+ *
971+ * t0q = (1/2)*((x - x1)*ky - (y - y1)*kx) /
972+ * ((xc - x1)*ky - (yc - y1)*kx)
973+ *
974+ * Let's do the same for our line Pl(t):
975+ *
976+ * t0l = ((x - x1)*ky - (y - y1)*kx) /
977+ * ((x2 - x1)*ky - (y2 - y1)*kx)
978+ *
979+ * It's easy to check that t0q == t0l. This fact means
980+ * we can compute t0 only one time.
981+ *
982+ * In case t0 < 0 or t0 > 1, we have an intersections outside
983+ * of shape bounds. So, P is definitely out of shape.
984+ *
985+ * In case t0 is inside [0:1], we should calculate Pq(t0)
986+ * and Pl(t0). We have three points for now, and all of them
987+ * lie on one line. So, we just need to detect, is our point
988+ * of interest between points of intersections or not.
989+ *
990+ * If the denominator in the t0q and t0l equations is
991+ * zero, then the points must be collinear and so the
992+ * curve is degenerate and encloses no area. Thus the
993+ * result is false.
994+ */
995+ double kx = x1 - 2 * xc + x2;
996+ double ky = y1 - 2 * yc + y2;
997+ double dx = x - x1;
998+ double dy = y - y1;
999+ double dxl = x2 - x1;
1000+ double dyl = y2 - y1;
1001+
1002+ double t0 = (dx * ky - dy * kx) / (dxl * ky - dyl * kx);
1003+ if (t0 < 0 || t0 > 1 || t0 != t0) {
1004+ return false;
1005+ }
1006+
1007+ double xb = kx * t0 * t0 + 2 * (xc - x1) * t0 + x1;
1008+ double yb = ky * t0 * t0 + 2 * (yc - y1) * t0 + y1;
1009+ double xl = dxl * t0 + x1;
1010+ double yl = dyl * t0 + y1;
1011+
1012+ return (x >= xb && x < xl) ||
1013+ (x >= xl && x < xb) ||
1014+ (y >= yb && y < yl) ||
1015+ (y >= yl && y < yb);
1016+ }
1017+
1018+ /**
1019+ * {@inheritDoc}
1020+ * @since 1.2
1021+ */
1022+ public boolean contains(Point2D p) {
1023+ return contains(p.getX(), p.getY());
1024+ }
1025+
1026+ /**
1027+ * Fill an array with the coefficients of the parametric equation
1028+ * in t, ready for solving against val with solveQuadratic.
1029+ * We currently have:
1030+ * val = Py(t) = C1*(1-t)^2 + 2*CP*t*(1-t) + C2*t^2
1031+ * = C1 - 2*C1*t + C1*t^2 + 2*CP*t - 2*CP*t^2 + C2*t^2
1032+ * = C1 + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2
1033+ * 0 = (C1 - val) + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2
1034+ * 0 = C + Bt + At^2
1035+ * C = C1 - val
1036+ * B = 2*CP - 2*C1
1037+ * A = C1 - 2*CP + C2
1038+ */
1039+ private static void fillEqn(double eqn[], double val,
1040+ double c1, double cp, double c2) {
1041+ eqn[0] = c1 - val;
1042+ eqn[1] = cp + cp - c1 - c1;
1043+ eqn[2] = c1 - cp - cp + c2;
1044+ return;
1045+ }
1046+
1047+ /**
1048+ * Evaluate the t values in the first num slots of the vals[] array
1049+ * and place the evaluated values back into the same array. Only
1050+ * evaluate t values that are within the range <0, 1>, including
1051+ * the 0 and 1 ends of the range iff the include0 or include1
1052+ * booleans are true. If an "inflection" equation is handed in,
1053+ * then any points which represent a point of inflection for that
1054+ * quadratic equation are also ignored.
1055+ */
1056+ private static int evalQuadratic(double vals[], int num,
1057+ boolean include0,
1058+ boolean include1,
1059+ double inflect[],
1060+ double c1, double ctrl, double c2) {
1061+ int j = 0;
1062+ for (int i = 0; i < num; i++) {
1063+ double t = vals[i];
1064+ if ((include0 ? t >= 0 : t > 0) &&
1065+ (include1 ? t <= 1 : t < 1) &&
1066+ (inflect == null ||
1067+ inflect[1] + 2*inflect[2]*t != 0))
1068+ {
1069+ double u = 1 - t;
1070+ vals[j++] = c1*u*u + 2*ctrl*t*u + c2*t*t;
1071+ }
1072+ }
1073+ return j;
1074+ }
1075+
1076+ private static final int BELOW = -2;
1077+ private static final int LOWEDGE = -1;
1078+ private static final int INSIDE = 0;
1079+ private static final int HIGHEDGE = 1;
1080+ private static final int ABOVE = 2;
1081+
1082+ /**
1083+ * Determine where coord lies with respect to the range from
1084+ * low to high. It is assumed that low <= high. The return
1085+ * value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,
1086+ * or ABOVE.
1087+ */
1088+ private static int getTag(double coord, double low, double high) {
1089+ if (coord <= low) {
1090+ return (coord < low ? BELOW : LOWEDGE);
1091+ }
1092+ if (coord >= high) {
1093+ return (coord > high ? ABOVE : HIGHEDGE);
1094+ }
1095+ return INSIDE;
1096+ }
1097+
1098+ /**
1099+ * Determine if the pttag represents a coordinate that is already
1100+ * in its test range, or is on the border with either of the two
1101+ * opttags representing another coordinate that is "towards the
1102+ * inside" of that test range. In other words, are either of the
1103+ * two "opt" points "drawing the pt inward"?
1104+ */
1105+ private static boolean inwards(int pttag, int opt1tag, int opt2tag) {
1106+ switch (pttag) {
1107+ case BELOW:
1108+ case ABOVE:
1109+ default:
1110+ return false;
1111+ case LOWEDGE:
1112+ return (opt1tag >= INSIDE || opt2tag >= INSIDE);
1113+ case INSIDE:
1114+ return true;
1115+ case HIGHEDGE:
1116+ return (opt1tag <= INSIDE || opt2tag <= INSIDE);
1117+ }
1118+ }
1119+
1120+ /**
1121+ * {@inheritDoc}
1122+ * @since 1.2
1123+ */
1124+ public boolean intersects(double x, double y, double w, double h) {
1125+ // Trivially reject non-existant rectangles
1126+ if (w <= 0 || h <= 0) {
1127+ return false;
1128+ }
1129+
1130+ // Trivially accept if either endpoint is inside the rectangle
1131+ // (not on its border since it may end there and not go inside)
1132+ // Record where they lie with respect to the rectangle.
1133+ // -1 => left, 0 => inside, 1 => right
1134+ double x1 = getX1();
1135+ double y1 = getY1();
1136+ int x1tag = getTag(x1, x, x+w);
1137+ int y1tag = getTag(y1, y, y+h);
1138+ if (x1tag == INSIDE && y1tag == INSIDE) {
1139+ return true;
1140+ }
1141+ double x2 = getX2();
1142+ double y2 = getY2();
1143+ int x2tag = getTag(x2, x, x+w);
1144+ int y2tag = getTag(y2, y, y+h);
1145+ if (x2tag == INSIDE && y2tag == INSIDE) {
1146+ return true;
1147+ }
1148+ double ctrlx = getCtrlX();
1149+ double ctrly = getCtrlY();
1150+ int ctrlxtag = getTag(ctrlx, x, x+w);
1151+ int ctrlytag = getTag(ctrly, y, y+h);
1152+
1153+ // Trivially reject if all points are entirely to one side of
1154+ // the rectangle.
1155+ if (x1tag < INSIDE && x2tag < INSIDE && ctrlxtag < INSIDE) {
1156+ return false; // All points left
1157+ }
1158+ if (y1tag < INSIDE && y2tag < INSIDE && ctrlytag < INSIDE) {
1159+ return false; // All points above
1160+ }
1161+ if (x1tag > INSIDE && x2tag > INSIDE && ctrlxtag > INSIDE) {
1162+ return false; // All points right
1163+ }
1164+ if (y1tag > INSIDE && y2tag > INSIDE && ctrlytag > INSIDE) {
1165+ return false; // All points below
1166+ }
1167+
1168+ // Test for endpoints on the edge where either the segment
1169+ // or the curve is headed "inwards" from them
1170+ // Note: These tests are a superset of the fast endpoint tests
1171+ // above and thus repeat those tests, but take more time
1172+ // and cover more cases
1173+ if (inwards(x1tag, x2tag, ctrlxtag) &&
1174+ inwards(y1tag, y2tag, ctrlytag))
1175+ {
1176+ // First endpoint on border with either edge moving inside
1177+ return true;
1178+ }
1179+ if (inwards(x2tag, x1tag, ctrlxtag) &&
1180+ inwards(y2tag, y1tag, ctrlytag))
1181+ {
1182+ // Second endpoint on border with either edge moving inside
1183+ return true;
1184+ }
1185+
1186+ // Trivially accept if endpoints span directly across the rectangle
1187+ boolean xoverlap = (x1tag * x2tag <= 0);
1188+ boolean yoverlap = (y1tag * y2tag <= 0);
1189+ if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {
1190+ return true;
1191+ }
1192+ if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {
1193+ return true;
1194+ }
1195+
1196+ // We now know that both endpoints are outside the rectangle
1197+ // but the 3 points are not all on one side of the rectangle.
1198+ // Therefore the curve cannot be contained inside the rectangle,
1199+ // but the rectangle might be contained inside the curve, or
1200+ // the curve might intersect the boundary of the rectangle.
1201+
1202+ double[] eqn = new double[3];
1203+ double[] res = new double[3];
1204+ if (!yoverlap) {
1205+ // Both Y coordinates for the closing segment are above or
1206+ // below the rectangle which means that we can only intersect
1207+ // if the curve crosses the top (or bottom) of the rectangle
1208+ // in more than one place and if those crossing locations
1209+ // span the horizontal range of the rectangle.
1210+ fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly, y2);
1211+ return (solveQuadratic(eqn, res) == 2 &&
1212+ evalQuadratic(res, 2, true, true, null,
1213+ x1, ctrlx, x2) == 2 &&
1214+ getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0);
1215+ }
1216+
1217+ // Y ranges overlap. Now we examine the X ranges
1218+ if (!xoverlap) {
1219+ // Both X coordinates for the closing segment are left of
1220+ // or right of the rectangle which means that we can only
1221+ // intersect if the curve crosses the left (or right) edge
1222+ // of the rectangle in more than one place and if those
1223+ // crossing locations span the vertical range of the rectangle.
1224+ fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx, x2);
1225+ return (solveQuadratic(eqn, res) == 2 &&
1226+ evalQuadratic(res, 2, true, true, null,
1227+ y1, ctrly, y2) == 2 &&
1228+ getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0);
1229+ }
1230+
1231+ // The X and Y ranges of the endpoints overlap the X and Y
1232+ // ranges of the rectangle, now find out how the endpoint
1233+ // line segment intersects the Y range of the rectangle
1234+ double dx = x2 - x1;
1235+ double dy = y2 - y1;
1236+ double k = y2 * x1 - x2 * y1;
1237+ int c1tag, c2tag;
1238+ if (y1tag == INSIDE) {
1239+ c1tag = x1tag;
1240+ } else {
1241+ c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w);
1242+ }
1243+ if (y2tag == INSIDE) {
1244+ c2tag = x2tag;
1245+ } else {
1246+ c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w);
1247+ }
1248+ // If the part of the line segment that intersects the Y range
1249+ // of the rectangle crosses it horizontally - trivially accept
1250+ if (c1tag * c2tag <= 0) {
1251+ return true;
1252+ }
1253+
1254+ // Now we know that both the X and Y ranges intersect and that
1255+ // the endpoint line segment does not directly cross the rectangle.
1256+ //
1257+ // We can almost treat this case like one of the cases above
1258+ // where both endpoints are to one side, except that we will
1259+ // only get one intersection of the curve with the vertical
1260+ // side of the rectangle. This is because the endpoint segment
1261+ // accounts for the other intersection.
1262+ //
1263+ // (Remember there is overlap in both the X and Y ranges which
1264+ // means that the segment must cross at least one vertical edge
1265+ // of the rectangle - in particular, the "near vertical side" -
1266+ // leaving only one intersection for the curve.)
1267+ //
1268+ // Now we calculate the y tags of the two intersections on the
1269+ // "near vertical side" of the rectangle. We will have one with
1270+ // the endpoint segment, and one with the curve. If those two
1271+ // vertical intersections overlap the Y range of the rectangle,
1272+ // we have an intersection. Otherwise, we don't.
1273+
1274+ // c1tag = vertical intersection class of the endpoint segment
1275+ //
1276+ // Choose the y tag of the endpoint that was not on the same
1277+ // side of the rectangle as the subsegment calculated above.
1278+ // Note that we can "steal" the existing Y tag of that endpoint
1279+ // since it will be provably the same as the vertical intersection.
1280+ c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);
1281+
1282+ // c2tag = vertical intersection class of the curve
1283+ //
1284+ // We have to calculate this one the straightforward way.
1285+ // Note that the c2tag can still tell us which vertical edge
1286+ // to test against.
1287+ fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx, x2);
1288+ int num = solveQuadratic(eqn, res);
1289+
1290+ // Note: We should be able to assert(num == 2); since the
1291+ // X range "crosses" (not touches) the vertical boundary,
1292+ // but we pass num to evalQuadratic for completeness.
1293+ evalQuadratic(res, num, true, true, null, y1, ctrly, y2);
1294+
1295+ // Note: We can assert(num evals == 1); since one of the
1296+ // 2 crossings will be out of the [0,1] range.
1297+ c2tag = getTag(res[0], y, y+h);
1298+
1299+ // Finally, we have an intersection if the two crossings
1300+ // overlap the Y range of the rectangle.
1301+ return (c1tag * c2tag <= 0);
1302+ }
1303+
1304+ /**
1305+ * {@inheritDoc}
1306+ * @since 1.2
1307+ */
1308+ public boolean intersects(Rectangle2D r) {
1309+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1310+ }
1311+
1312+ /**
1313+ * {@inheritDoc}
1314+ * @since 1.2
1315+ */
1316+ public boolean contains(double x, double y, double w, double h) {
1317+ if (w <= 0 || h <= 0) {
1318+ return false;
1319+ }
1320+ // Assertion: Quadratic curves closed by connecting their
1321+ // endpoints are always convex.
1322+ return (contains(x, y) &&
1323+ contains(x + w, y) &&
1324+ contains(x + w, y + h) &&
1325+ contains(x, y + h));
1326+ }
1327+
1328+ /**
1329+ * {@inheritDoc}
1330+ * @since 1.2
1331+ */
1332+ public boolean contains(Rectangle2D r) {
1333+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1334+ }
1335+
1336+ /**
1337+ * {@inheritDoc}
1338+ * @since 1.2
1339+ */
1340+ public Rectangle getBounds() {
1341+ return getBounds2D().getBounds();
1342+ }
1343+
1344+ /**
1345+ * Returns an iteration object that defines the boundary of the
1346+ * shape of this <code>QuadCurve2D</code>.
1347+ * The iterator for this class is not multi-threaded safe,
1348+ * which means that this <code>QuadCurve2D</code> class does not
1349+ * guarantee that modifications to the geometry of this
1350+ * <code>QuadCurve2D</code> object do not affect any iterations of
1351+ * that geometry that are already in process.
1352+ * @param at an optional {@link AffineTransform} to apply to the
1353+ * shape boundary
1354+ * @return a {@link PathIterator} object that defines the boundary
1355+ * of the shape.
1356+ * @since 1.2
1357+ */
1358+ public PathIterator getPathIterator(AffineTransform at) {
1359+ return new QuadIterator(this, at);
1360+ }
1361+
1362+ /**
1363+ * Returns an iteration object that defines the boundary of the
1364+ * flattened shape of this <code>QuadCurve2D</code>.
1365+ * The iterator for this class is not multi-threaded safe,
1366+ * which means that this <code>QuadCurve2D</code> class does not
1367+ * guarantee that modifications to the geometry of this
1368+ * <code>QuadCurve2D</code> object do not affect any iterations of
1369+ * that geometry that are already in process.
1370+ * @param at an optional <code>AffineTransform</code> to apply
1371+ * to the boundary of the shape
1372+ * @param flatness the maximum distance that the control points for a
1373+ * subdivided curve can be with respect to a line connecting
1374+ * the end points of this curve before this curve is
1375+ * replaced by a straight line connecting the end points.
1376+ * @return a <code>PathIterator</code> object that defines the
1377+ * flattened boundary of the shape.
1378+ * @since 1.2
1379+ */
1380+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
1381+ return new FlatteningPathIterator(getPathIterator(at), flatness);
1382+ }
1383+
1384+ /**
1385+ * Creates a new object of the same class and with the same contents
1386+ * as this object.
1387+ *
1388+ * @return a clone of this instance.
1389+ * @exception OutOfMemoryError if there is not enough memory.
1390+ * @see java.lang.Cloneable
1391+ * @since 1.2
1392+ */
1393+ public Object clone() {
1394+ try {
1395+ return super.clone();
1396+ } catch (CloneNotSupportedException e) {
1397+ // this shouldn't happen, since we are Cloneable
1398+ throw new InternalError();
1399+ }
1400+ }
1401+}
java/pkg/java/awt/geom/QuadIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/QuadIterator.java+152−0
@@ -0,0 +1,152 @@
1+/*
2+ * Copyright (c) 1997, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of a quadratic curve
32+ * segment through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class QuadIterator implements PathIterator {
37+ QuadCurve2D quad;
38+ AffineTransform affine;
39+ int index;
40+
41+ QuadIterator(QuadCurve2D q, AffineTransform at) {
42+ this.quad = q;
43+ this.affine = at;
44+ }
45+
46+ /**
47+ * Return the winding rule for determining the insideness of the
48+ * path.
49+ * @see #WIND_EVEN_ODD
50+ * @see #WIND_NON_ZERO
51+ */
52+ public int getWindingRule() {
53+ return WIND_NON_ZERO;
54+ }
55+
56+ /**
57+ * Tests if there are more points to read.
58+ * @return true if there are more points to read
59+ */
60+ public boolean isDone() {
61+ return (index > 1);
62+ }
63+
64+ /**
65+ * Moves the iterator to the next segment of the path forwards
66+ * along the primary direction of traversal as long as there are
67+ * more points in that direction.
68+ */
69+ public void next() {
70+ index++;
71+ }
72+
73+ /**
74+ * Returns the coordinates and type of the current path segment in
75+ * the iteration.
76+ * The return value is the path segment type:
77+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
78+ * A float array of length 6 must be passed in and may be used to
79+ * store the coordinates of the point(s).
80+ * Each point is stored as a pair of float x,y coordinates.
81+ * SEG_MOVETO and SEG_LINETO types will return one point,
82+ * SEG_QUADTO will return two points,
83+ * SEG_CUBICTO will return 3 points
84+ * and SEG_CLOSE will not return any points.
85+ * @see #SEG_MOVETO
86+ * @see #SEG_LINETO
87+ * @see #SEG_QUADTO
88+ * @see #SEG_CUBICTO
89+ * @see #SEG_CLOSE
90+ */
91+ public int currentSegment(float[] coords) {
92+ if (isDone()) {
93+ throw new NoSuchElementException("quad iterator iterator out of bounds");
94+ }
95+ int type;
96+ if (index == 0) {
97+ coords[0] = (float) quad.getX1();
98+ coords[1] = (float) quad.getY1();
99+ type = SEG_MOVETO;
100+ } else {
101+ coords[0] = (float) quad.getCtrlX();
102+ coords[1] = (float) quad.getCtrlY();
103+ coords[2] = (float) quad.getX2();
104+ coords[3] = (float) quad.getY2();
105+ type = SEG_QUADTO;
106+ }
107+ if (affine != null) {
108+ affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 2);
109+ }
110+ return type;
111+ }
112+
113+ /**
114+ * Returns the coordinates and type of the current path segment in
115+ * the iteration.
116+ * The return value is the path segment type:
117+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
118+ * A double array of length 6 must be passed in and may be used to
119+ * store the coordinates of the point(s).
120+ * Each point is stored as a pair of double x,y coordinates.
121+ * SEG_MOVETO and SEG_LINETO types will return one point,
122+ * SEG_QUADTO will return two points,
123+ * SEG_CUBICTO will return 3 points
124+ * and SEG_CLOSE will not return any points.
125+ * @see #SEG_MOVETO
126+ * @see #SEG_LINETO
127+ * @see #SEG_QUADTO
128+ * @see #SEG_CUBICTO
129+ * @see #SEG_CLOSE
130+ */
131+ public int currentSegment(double[] coords) {
132+ if (isDone()) {
133+ throw new NoSuchElementException("quad iterator iterator out of bounds");
134+ }
135+ int type;
136+ if (index == 0) {
137+ coords[0] = quad.getX1();
138+ coords[1] = quad.getY1();
139+ type = SEG_MOVETO;
140+ } else {
141+ coords[0] = quad.getCtrlX();
142+ coords[1] = quad.getCtrlY();
143+ coords[2] = quad.getX2();
144+ coords[3] = quad.getY2();
145+ type = SEG_QUADTO;
146+ }
147+ if (affine != null) {
148+ affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 2);
149+ }
150+ return type;
151+ }
152+}
java/pkg/java/awt/geom/RectIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/RectIterator.java+156−0
@@ -0,0 +1,156 @@
1+/*
2+ * Copyright (c) 1997, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of a rectangle
32+ * through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class RectIterator implements PathIterator {
37+ double x, y, w, h;
38+ AffineTransform affine;
39+ int index;
40+
41+ RectIterator(Rectangle2D r, AffineTransform at) {
42+ this.x = r.getX();
43+ this.y = r.getY();
44+ this.w = r.getWidth();
45+ this.h = r.getHeight();
46+ this.affine = at;
47+ if (w < 0 || h < 0) {
48+ index = 6;
49+ }
50+ }
51+
52+ /**
53+ * Return the winding rule for determining the insideness of the
54+ * path.
55+ * @see #WIND_EVEN_ODD
56+ * @see #WIND_NON_ZERO
57+ */
58+ public int getWindingRule() {
59+ return WIND_NON_ZERO;
60+ }
61+
62+ /**
63+ * Tests if there are more points to read.
64+ * @return true if there are more points to read
65+ */
66+ public boolean isDone() {
67+ return index > 5;
68+ }
69+
70+ /**
71+ * Moves the iterator to the next segment of the path forwards
72+ * along the primary direction of traversal as long as there are
73+ * more points in that direction.
74+ */
75+ public void next() {
76+ index++;
77+ }
78+
79+ /**
80+ * Returns the coordinates and type of the current path segment in
81+ * the iteration.
82+ * The return value is the path segment type:
83+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
84+ * A float array of length 6 must be passed in and may be used to
85+ * store the coordinates of the point(s).
86+ * Each point is stored as a pair of float x,y coordinates.
87+ * SEG_MOVETO and SEG_LINETO types will return one point,
88+ * SEG_QUADTO will return two points,
89+ * SEG_CUBICTO will return 3 points
90+ * and SEG_CLOSE will not return any points.
91+ * @see #SEG_MOVETO
92+ * @see #SEG_LINETO
93+ * @see #SEG_QUADTO
94+ * @see #SEG_CUBICTO
95+ * @see #SEG_CLOSE
96+ */
97+ public int currentSegment(float[] coords) {
98+ if (isDone()) {
99+ throw new NoSuchElementException("rect iterator out of bounds");
100+ }
101+ if (index == 5) {
102+ return SEG_CLOSE;
103+ }
104+ coords[0] = (float) x;
105+ coords[1] = (float) y;
106+ if (index == 1 || index == 2) {
107+ coords[0] += (float) w;
108+ }
109+ if (index == 2 || index == 3) {
110+ coords[1] += (float) h;
111+ }
112+ if (affine != null) {
113+ affine.transform(coords, 0, coords, 0, 1);
114+ }
115+ return (index == 0 ? SEG_MOVETO : SEG_LINETO);
116+ }
117+
118+ /**
119+ * Returns the coordinates and type of the current path segment in
120+ * the iteration.
121+ * The return value is the path segment type:
122+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
123+ * A double array of length 6 must be passed in and may be used to
124+ * store the coordinates of the point(s).
125+ * Each point is stored as a pair of double x,y coordinates.
126+ * SEG_MOVETO and SEG_LINETO types will return one point,
127+ * SEG_QUADTO will return two points,
128+ * SEG_CUBICTO will return 3 points
129+ * and SEG_CLOSE will not return any points.
130+ * @see #SEG_MOVETO
131+ * @see #SEG_LINETO
132+ * @see #SEG_QUADTO
133+ * @see #SEG_CUBICTO
134+ * @see #SEG_CLOSE
135+ */
136+ public int currentSegment(double[] coords) {
137+ if (isDone()) {
138+ throw new NoSuchElementException("rect iterator out of bounds");
139+ }
140+ if (index == 5) {
141+ return SEG_CLOSE;
142+ }
143+ coords[0] = x;
144+ coords[1] = y;
145+ if (index == 1 || index == 2) {
146+ coords[0] += w;
147+ }
148+ if (index == 2 || index == 3) {
149+ coords[1] += h;
150+ }
151+ if (affine != null) {
152+ affine.transform(coords, 0, coords, 0, 1);
153+ }
154+ return (index == 0 ? SEG_MOVETO : SEG_LINETO);
155+ }
156+}
java/pkg/java/awt/geom/Rectangle2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Rectangle2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Rectangle2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/Rectangle2D.java+930−0
@@ -0,0 +1,930 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.io.Serializable;
29+
30+/**
31+ * The <code>Rectangle2D</code> class describes a rectangle
32+ * defined by a location {@code (x,y)} and dimension
33+ * {@code (w x h)}.
34+ * <p>
35+ * This class is only the abstract superclass for all objects that
36+ * store a 2D rectangle.
37+ * The actual storage representation of the coordinates is left to
38+ * the subclass.
39+ *
40+ * @author Jim Graham
41+ * @since 1.2
42+ */
43+public abstract class Rectangle2D extends RectangularShape {
44+ /**
45+ * The bitmask that indicates that a point lies to the left of
46+ * this <code>Rectangle2D</code>.
47+ * @since 1.2
48+ */
49+ public static final int OUT_LEFT = 1;
50+
51+ /**
52+ * The bitmask that indicates that a point lies above
53+ * this <code>Rectangle2D</code>.
54+ * @since 1.2
55+ */
56+ public static final int OUT_TOP = 2;
57+
58+ /**
59+ * The bitmask that indicates that a point lies to the right of
60+ * this <code>Rectangle2D</code>.
61+ * @since 1.2
62+ */
63+ public static final int OUT_RIGHT = 4;
64+
65+ /**
66+ * The bitmask that indicates that a point lies below
67+ * this <code>Rectangle2D</code>.
68+ * @since 1.2
69+ */
70+ public static final int OUT_BOTTOM = 8;
71+
72+ /**
73+ * The <code>Float</code> class defines a rectangle specified in float
74+ * coordinates.
75+ * @since 1.2
76+ */
77+ public static class Float extends Rectangle2D implements Serializable {
78+ /**
79+ * The X coordinate of this <code>Rectangle2D</code>.
80+ * @since 1.2
81+ * @serial
82+ */
83+ public float x;
84+
85+ /**
86+ * The Y coordinate of this <code>Rectangle2D</code>.
87+ * @since 1.2
88+ * @serial
89+ */
90+ public float y;
91+
92+ /**
93+ * The width of this <code>Rectangle2D</code>.
94+ * @since 1.2
95+ * @serial
96+ */
97+ public float width;
98+
99+ /**
100+ * The height of this <code>Rectangle2D</code>.
101+ * @since 1.2
102+ * @serial
103+ */
104+ public float height;
105+
106+ /**
107+ * Constructs a new <code>Rectangle2D</code>, initialized to
108+ * location (0.0,&nbsp;0.0) and size (0.0,&nbsp;0.0).
109+ * @since 1.2
110+ */
111+ public Float() {
112+ }
113+
114+ /**
115+ * Constructs and initializes a <code>Rectangle2D</code>
116+ * from the specified <code>float</code> coordinates.
117+ *
118+ * @param x the X coordinate of the upper-left corner
119+ * of the newly constructed <code>Rectangle2D</code>
120+ * @param y the Y coordinate of the upper-left corner
121+ * of the newly constructed <code>Rectangle2D</code>
122+ * @param w the width of the newly constructed
123+ * <code>Rectangle2D</code>
124+ * @param h the height of the newly constructed
125+ * <code>Rectangle2D</code>
126+ * @since 1.2
127+ */
128+ public Float(float x, float y, float w, float h) {
129+ setRect(x, y, w, h);
130+ }
131+
132+ /**
133+ * {@inheritDoc}
134+ * @since 1.2
135+ */
136+ public double getX() {
137+ return (double) x;
138+ }
139+
140+ /**
141+ * {@inheritDoc}
142+ * @since 1.2
143+ */
144+ public double getY() {
145+ return (double) y;
146+ }
147+
148+ /**
149+ * {@inheritDoc}
150+ * @since 1.2
151+ */
152+ public double getWidth() {
153+ return (double) width;
154+ }
155+
156+ /**
157+ * {@inheritDoc}
158+ * @since 1.2
159+ */
160+ public double getHeight() {
161+ return (double) height;
162+ }
163+
164+ /**
165+ * {@inheritDoc}
166+ * @since 1.2
167+ */
168+ public boolean isEmpty() {
169+ return (width <= 0.0f) || (height <= 0.0f);
170+ }
171+
172+ /**
173+ * Sets the location and size of this <code>Rectangle2D</code>
174+ * to the specified <code>float</code> values.
175+ *
176+ * @param x the X coordinate of the upper-left corner
177+ * of this <code>Rectangle2D</code>
178+ * @param y the Y coordinate of the upper-left corner
179+ * of this <code>Rectangle2D</code>
180+ * @param w the width of this <code>Rectangle2D</code>
181+ * @param h the height of this <code>Rectangle2D</code>
182+ * @since 1.2
183+ */
184+ public void setRect(float x, float y, float w, float h) {
185+ this.x = x;
186+ this.y = y;
187+ this.width = w;
188+ this.height = h;
189+ }
190+
191+ /**
192+ * {@inheritDoc}
193+ * @since 1.2
194+ */
195+ public void setRect(double x, double y, double w, double h) {
196+ this.x = (float) x;
197+ this.y = (float) y;
198+ this.width = (float) w;
199+ this.height = (float) h;
200+ }
201+
202+ /**
203+ * {@inheritDoc}
204+ * @since 1.2
205+ */
206+ public void setRect(Rectangle2D r) {
207+ this.x = (float) r.getX();
208+ this.y = (float) r.getY();
209+ this.width = (float) r.getWidth();
210+ this.height = (float) r.getHeight();
211+ }
212+
213+ /**
214+ * {@inheritDoc}
215+ * @since 1.2
216+ */
217+ public int outcode(double x, double y) {
218+ /*
219+ * Note on casts to double below. If the arithmetic of
220+ * x+w or y+h is done in float, then some bits may be
221+ * lost if the binary exponents of x/y and w/h are not
222+ * similar. By converting to double before the addition
223+ * we force the addition to be carried out in double to
224+ * avoid rounding error in the comparison.
225+ *
226+ * See bug 4320890 for problems that this inaccuracy causes.
227+ */
228+ int out = 0;
229+ if (this.width <= 0) {
230+ out |= OUT_LEFT | OUT_RIGHT;
231+ } else if (x < this.x) {
232+ out |= OUT_LEFT;
233+ } else if (x > this.x + (double) this.width) {
234+ out |= OUT_RIGHT;
235+ }
236+ if (this.height <= 0) {
237+ out |= OUT_TOP | OUT_BOTTOM;
238+ } else if (y < this.y) {
239+ out |= OUT_TOP;
240+ } else if (y > this.y + (double) this.height) {
241+ out |= OUT_BOTTOM;
242+ }
243+ return out;
244+ }
245+
246+ /**
247+ * {@inheritDoc}
248+ * @since 1.2
249+ */
250+ public Rectangle2D getBounds2D() {
251+ return new Float(x, y, width, height);
252+ }
253+
254+ /**
255+ * {@inheritDoc}
256+ * @since 1.2
257+ */
258+ public Rectangle2D createIntersection(Rectangle2D r) {
259+ Rectangle2D dest;
260+ if (r instanceof Float) {
261+ dest = new Rectangle2D.Float();
262+ } else {
263+ dest = new Rectangle2D.Double();
264+ }
265+ Rectangle2D.intersect(this, r, dest);
266+ return dest;
267+ }
268+
269+ /**
270+ * {@inheritDoc}
271+ * @since 1.2
272+ */
273+ public Rectangle2D createUnion(Rectangle2D r) {
274+ Rectangle2D dest;
275+ if (r instanceof Float) {
276+ dest = new Rectangle2D.Float();
277+ } else {
278+ dest = new Rectangle2D.Double();
279+ }
280+ Rectangle2D.union(this, r, dest);
281+ return dest;
282+ }
283+
284+ /**
285+ * Returns the <code>String</code> representation of this
286+ * <code>Rectangle2D</code>.
287+ * @return a <code>String</code> representing this
288+ * <code>Rectangle2D</code>.
289+ * @since 1.2
290+ */
291+ public String toString() {
292+ return getClass().getName()
293+ + "[x=" + x +
294+ ",y=" + y +
295+ ",w=" + width +
296+ ",h=" + height + "]";
297+ }
298+
299+ /*
300+ * JDK 1.6 serialVersionUID
301+ */
302+ private static final long serialVersionUID = 3798716824173675777L;
303+ }
304+
305+ /**
306+ * The <code>Double</code> class defines a rectangle specified in
307+ * double coordinates.
308+ * @since 1.2
309+ */
310+ public static class Double extends Rectangle2D implements Serializable {
311+ /**
312+ * The X coordinate of this <code>Rectangle2D</code>.
313+ * @since 1.2
314+ * @serial
315+ */
316+ public double x;
317+
318+ /**
319+ * The Y coordinate of this <code>Rectangle2D</code>.
320+ * @since 1.2
321+ * @serial
322+ */
323+ public double y;
324+
325+ /**
326+ * The width of this <code>Rectangle2D</code>.
327+ * @since 1.2
328+ * @serial
329+ */
330+ public double width;
331+
332+ /**
333+ * The height of this <code>Rectangle2D</code>.
334+ * @since 1.2
335+ * @serial
336+ */
337+ public double height;
338+
339+ /**
340+ * Constructs a new <code>Rectangle2D</code>, initialized to
341+ * location (0,&nbsp;0) and size (0,&nbsp;0).
342+ * @since 1.2
343+ */
344+ public Double() {
345+ }
346+
347+ /**
348+ * Constructs and initializes a <code>Rectangle2D</code>
349+ * from the specified <code>double</code> coordinates.
350+ *
351+ * @param x the X coordinate of the upper-left corner
352+ * of the newly constructed <code>Rectangle2D</code>
353+ * @param y the Y coordinate of the upper-left corner
354+ * of the newly constructed <code>Rectangle2D</code>
355+ * @param w the width of the newly constructed
356+ * <code>Rectangle2D</code>
357+ * @param h the height of the newly constructed
358+ * <code>Rectangle2D</code>
359+ * @since 1.2
360+ */
361+ public Double(double x, double y, double w, double h) {
362+ setRect(x, y, w, h);
363+ }
364+
365+ /**
366+ * {@inheritDoc}
367+ * @since 1.2
368+ */
369+ public double getX() {
370+ return x;
371+ }
372+
373+ /**
374+ * {@inheritDoc}
375+ * @since 1.2
376+ */
377+ public double getY() {
378+ return y;
379+ }
380+
381+ /**
382+ * {@inheritDoc}
383+ * @since 1.2
384+ */
385+ public double getWidth() {
386+ return width;
387+ }
388+
389+ /**
390+ * {@inheritDoc}
391+ * @since 1.2
392+ */
393+ public double getHeight() {
394+ return height;
395+ }
396+
397+ /**
398+ * {@inheritDoc}
399+ * @since 1.2
400+ */
401+ public boolean isEmpty() {
402+ return (width <= 0.0) || (height <= 0.0);
403+ }
404+
405+ /**
406+ * {@inheritDoc}
407+ * @since 1.2
408+ */
409+ public void setRect(double x, double y, double w, double h) {
410+ this.x = x;
411+ this.y = y;
412+ this.width = w;
413+ this.height = h;
414+ }
415+
416+ /**
417+ * {@inheritDoc}
418+ * @since 1.2
419+ */
420+ public void setRect(Rectangle2D r) {
421+ this.x = r.getX();
422+ this.y = r.getY();
423+ this.width = r.getWidth();
424+ this.height = r.getHeight();
425+ }
426+
427+ /**
428+ * {@inheritDoc}
429+ * @since 1.2
430+ */
431+ public int outcode(double x, double y) {
432+ int out = 0;
433+ if (this.width <= 0) {
434+ out |= OUT_LEFT | OUT_RIGHT;
435+ } else if (x < this.x) {
436+ out |= OUT_LEFT;
437+ } else if (x > this.x + this.width) {
438+ out |= OUT_RIGHT;
439+ }
440+ if (this.height <= 0) {
441+ out |= OUT_TOP | OUT_BOTTOM;
442+ } else if (y < this.y) {
443+ out |= OUT_TOP;
444+ } else if (y > this.y + this.height) {
445+ out |= OUT_BOTTOM;
446+ }
447+ return out;
448+ }
449+
450+ /**
451+ * {@inheritDoc}
452+ * @since 1.2
453+ */
454+ public Rectangle2D getBounds2D() {
455+ return new Double(x, y, width, height);
456+ }
457+
458+ /**
459+ * {@inheritDoc}
460+ * @since 1.2
461+ */
462+ public Rectangle2D createIntersection(Rectangle2D r) {
463+ Rectangle2D dest = new Rectangle2D.Double();
464+ Rectangle2D.intersect(this, r, dest);
465+ return dest;
466+ }
467+
468+ /**
469+ * {@inheritDoc}
470+ * @since 1.2
471+ */
472+ public Rectangle2D createUnion(Rectangle2D r) {
473+ Rectangle2D dest = new Rectangle2D.Double();
474+ Rectangle2D.union(this, r, dest);
475+ return dest;
476+ }
477+
478+ /**
479+ * Returns the <code>String</code> representation of this
480+ * <code>Rectangle2D</code>.
481+ * @return a <code>String</code> representing this
482+ * <code>Rectangle2D</code>.
483+ * @since 1.2
484+ */
485+ public String toString() {
486+ return getClass().getName()
487+ + "[x=" + x +
488+ ",y=" + y +
489+ ",w=" + width +
490+ ",h=" + height + "]";
491+ }
492+
493+ /*
494+ * JDK 1.6 serialVersionUID
495+ */
496+ private static final long serialVersionUID = 7771313791441850493L;
497+ }
498+
499+ /**
500+ * This is an abstract class that cannot be instantiated directly.
501+ * Type-specific implementation subclasses are available for
502+ * instantiation and provide a number of formats for storing
503+ * the information necessary to satisfy the various accessor
504+ * methods below.
505+ *
506+ * @see java.awt.geom.Rectangle2D.Float
507+ * @see java.awt.geom.Rectangle2D.Double
508+ * @see java.awt.Rectangle
509+ * @since 1.2
510+ */
511+ protected Rectangle2D() {
512+ }
513+
514+ /**
515+ * Sets the location and size of this <code>Rectangle2D</code>
516+ * to the specified <code>double</code> values.
517+ *
518+ * @param x the X coordinate of the upper-left corner
519+ * of this <code>Rectangle2D</code>
520+ * @param y the Y coordinate of the upper-left corner
521+ * of this <code>Rectangle2D</code>
522+ * @param w the width of this <code>Rectangle2D</code>
523+ * @param h the height of this <code>Rectangle2D</code>
524+ * @since 1.2
525+ */
526+ public abstract void setRect(double x, double y, double w, double h);
527+
528+ /**
529+ * Sets this <code>Rectangle2D</code> to be the same as the specified
530+ * <code>Rectangle2D</code>.
531+ * @param r the specified <code>Rectangle2D</code>
532+ * @since 1.2
533+ */
534+ public void setRect(Rectangle2D r) {
535+ setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
536+ }
537+
538+ /**
539+ * Tests if the specified line segment intersects the interior of this
540+ * <code>Rectangle2D</code>.
541+ *
542+ * @param x1 the X coordinate of the start point of the specified
543+ * line segment
544+ * @param y1 the Y coordinate of the start point of the specified
545+ * line segment
546+ * @param x2 the X coordinate of the end point of the specified
547+ * line segment
548+ * @param y2 the Y coordinate of the end point of the specified
549+ * line segment
550+ * @return <code>true</code> if the specified line segment intersects
551+ * the interior of this <code>Rectangle2D</code>; <code>false</code>
552+ * otherwise.
553+ * @since 1.2
554+ */
555+ public boolean intersectsLine(double x1, double y1, double x2, double y2) {
556+ int out1, out2;
557+ if ((out2 = outcode(x2, y2)) == 0) {
558+ return true;
559+ }
560+ while ((out1 = outcode(x1, y1)) != 0) {
561+ if ((out1 & out2) != 0) {
562+ return false;
563+ }
564+ if ((out1 & (OUT_LEFT | OUT_RIGHT)) != 0) {
565+ double x = getX();
566+ if ((out1 & OUT_RIGHT) != 0) {
567+ x += getWidth();
568+ }
569+ y1 = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
570+ x1 = x;
571+ } else {
572+ double y = getY();
573+ if ((out1 & OUT_BOTTOM) != 0) {
574+ y += getHeight();
575+ }
576+ x1 = x1 + (y - y1) * (x2 - x1) / (y2 - y1);
577+ y1 = y;
578+ }
579+ }
580+ return true;
581+ }
582+
583+ /**
584+ * Tests if the specified line segment intersects the interior of this
585+ * <code>Rectangle2D</code>.
586+ * @param l the specified {@link Line2D} to test for intersection
587+ * with the interior of this <code>Rectangle2D</code>
588+ * @return <code>true</code> if the specified <code>Line2D</code>
589+ * intersects the interior of this <code>Rectangle2D</code>;
590+ * <code>false</code> otherwise.
591+ * @since 1.2
592+ */
593+ public boolean intersectsLine(Line2D l) {
594+ return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
595+ }
596+
597+ /**
598+ * Determines where the specified coordinates lie with respect
599+ * to this <code>Rectangle2D</code>.
600+ * This method computes a binary OR of the appropriate mask values
601+ * indicating, for each side of this <code>Rectangle2D</code>,
602+ * whether or not the specified coordinates are on the same side
603+ * of the edge as the rest of this <code>Rectangle2D</code>.
604+ * @param x the specified X coordinate
605+ * @param y the specified Y coordinate
606+ * @return the logical OR of all appropriate out codes.
607+ * @see #OUT_LEFT
608+ * @see #OUT_TOP
609+ * @see #OUT_RIGHT
610+ * @see #OUT_BOTTOM
611+ * @since 1.2
612+ */
613+ public abstract int outcode(double x, double y);
614+
615+ /**
616+ * Determines where the specified {@link Point2D} lies with
617+ * respect to this <code>Rectangle2D</code>.
618+ * This method computes a binary OR of the appropriate mask values
619+ * indicating, for each side of this <code>Rectangle2D</code>,
620+ * whether or not the specified <code>Point2D</code> is on the same
621+ * side of the edge as the rest of this <code>Rectangle2D</code>.
622+ * @param p the specified <code>Point2D</code>
623+ * @return the logical OR of all appropriate out codes.
624+ * @see #OUT_LEFT
625+ * @see #OUT_TOP
626+ * @see #OUT_RIGHT
627+ * @see #OUT_BOTTOM
628+ * @since 1.2
629+ */
630+ public int outcode(Point2D p) {
631+ return outcode(p.getX(), p.getY());
632+ }
633+
634+ /**
635+ * Sets the location and size of the outer bounds of this
636+ * <code>Rectangle2D</code> to the specified rectangular values.
637+ *
638+ * @param x the X coordinate of the upper-left corner
639+ * of this <code>Rectangle2D</code>
640+ * @param y the Y coordinate of the upper-left corner
641+ * of this <code>Rectangle2D</code>
642+ * @param w the width of this <code>Rectangle2D</code>
643+ * @param h the height of this <code>Rectangle2D</code>
644+ * @since 1.2
645+ */
646+ public void setFrame(double x, double y, double w, double h) {
647+ setRect(x, y, w, h);
648+ }
649+
650+ /**
651+ * {@inheritDoc}
652+ * @since 1.2
653+ */
654+ public Rectangle2D getBounds2D() {
655+ return (Rectangle2D) clone();
656+ }
657+
658+ /**
659+ * {@inheritDoc}
660+ * @since 1.2
661+ */
662+ public boolean contains(double x, double y) {
663+ double x0 = getX();
664+ double y0 = getY();
665+ return (x >= x0 &&
666+ y >= y0 &&
667+ x < x0 + getWidth() &&
668+ y < y0 + getHeight());
669+ }
670+
671+ /**
672+ * {@inheritDoc}
673+ * @since 1.2
674+ */
675+ public boolean intersects(double x, double y, double w, double h) {
676+ if (isEmpty() || w <= 0 || h <= 0) {
677+ return false;
678+ }
679+ double x0 = getX();
680+ double y0 = getY();
681+ return (x + w > x0 &&
682+ y + h > y0 &&
683+ x < x0 + getWidth() &&
684+ y < y0 + getHeight());
685+ }
686+
687+ /**
688+ * {@inheritDoc}
689+ * @since 1.2
690+ */
691+ public boolean contains(double x, double y, double w, double h) {
692+ if (isEmpty() || w <= 0 || h <= 0) {
693+ return false;
694+ }
695+ double x0 = getX();
696+ double y0 = getY();
697+ return (x >= x0 &&
698+ y >= y0 &&
699+ (x + w) <= x0 + getWidth() &&
700+ (y + h) <= y0 + getHeight());
701+ }
702+
703+ /**
704+ * Returns a new <code>Rectangle2D</code> object representing the
705+ * intersection of this <code>Rectangle2D</code> with the specified
706+ * <code>Rectangle2D</code>.
707+ * @param r the <code>Rectangle2D</code> to be intersected with
708+ * this <code>Rectangle2D</code>
709+ * @return the largest <code>Rectangle2D</code> contained in both
710+ * the specified <code>Rectangle2D</code> and in this
711+ * <code>Rectangle2D</code>.
712+ * @since 1.2
713+ */
714+ public abstract Rectangle2D createIntersection(Rectangle2D r);
715+
716+ /**
717+ * Intersects the pair of specified source <code>Rectangle2D</code>
718+ * objects and puts the result into the specified destination
719+ * <code>Rectangle2D</code> object. One of the source rectangles
720+ * can also be the destination to avoid creating a third Rectangle2D
721+ * object, but in this case the original points of this source
722+ * rectangle will be overwritten by this method.
723+ * @param src1 the first of a pair of <code>Rectangle2D</code>
724+ * objects to be intersected with each other
725+ * @param src2 the second of a pair of <code>Rectangle2D</code>
726+ * objects to be intersected with each other
727+ * @param dest the <code>Rectangle2D</code> that holds the
728+ * results of the intersection of <code>src1</code> and
729+ * <code>src2</code>
730+ * @since 1.2
731+ */
732+ public static void intersect(Rectangle2D src1,
733+ Rectangle2D src2,
734+ Rectangle2D dest) {
735+ double x1 = Math.max(src1.getMinX(), src2.getMinX());
736+ double y1 = Math.max(src1.getMinY(), src2.getMinY());
737+ double x2 = Math.min(src1.getMaxX(), src2.getMaxX());
738+ double y2 = Math.min(src1.getMaxY(), src2.getMaxY());
739+ dest.setFrame(x1, y1, x2-x1, y2-y1);
740+ }
741+
742+ /**
743+ * Returns a new <code>Rectangle2D</code> object representing the
744+ * union of this <code>Rectangle2D</code> with the specified
745+ * <code>Rectangle2D</code>.
746+ * @param r the <code>Rectangle2D</code> to be combined with
747+ * this <code>Rectangle2D</code>
748+ * @return the smallest <code>Rectangle2D</code> containing both
749+ * the specified <code>Rectangle2D</code> and this
750+ * <code>Rectangle2D</code>.
751+ * @since 1.2
752+ */
753+ public abstract Rectangle2D createUnion(Rectangle2D r);
754+
755+ /**
756+ * Unions the pair of source <code>Rectangle2D</code> objects
757+ * and puts the result into the specified destination
758+ * <code>Rectangle2D</code> object. One of the source rectangles
759+ * can also be the destination to avoid creating a third Rectangle2D
760+ * object, but in this case the original points of this source
761+ * rectangle will be overwritten by this method.
762+ * @param src1 the first of a pair of <code>Rectangle2D</code>
763+ * objects to be combined with each other
764+ * @param src2 the second of a pair of <code>Rectangle2D</code>
765+ * objects to be combined with each other
766+ * @param dest the <code>Rectangle2D</code> that holds the
767+ * results of the union of <code>src1</code> and
768+ * <code>src2</code>
769+ * @since 1.2
770+ */
771+ public static void union(Rectangle2D src1,
772+ Rectangle2D src2,
773+ Rectangle2D dest) {
774+ double x1 = Math.min(src1.getMinX(), src2.getMinX());
775+ double y1 = Math.min(src1.getMinY(), src2.getMinY());
776+ double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
777+ double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
778+ dest.setFrameFromDiagonal(x1, y1, x2, y2);
779+ }
780+
781+ /**
782+ * Adds a point, specified by the double precision arguments
783+ * <code>newx</code> and <code>newy</code>, to this
784+ * <code>Rectangle2D</code>. The resulting <code>Rectangle2D</code>
785+ * is the smallest <code>Rectangle2D</code> that
786+ * contains both the original <code>Rectangle2D</code> and the
787+ * specified point.
788+ * <p>
789+ * After adding a point, a call to <code>contains</code> with the
790+ * added point as an argument does not necessarily return
791+ * <code>true</code>. The <code>contains</code> method does not
792+ * return <code>true</code> for points on the right or bottom
793+ * edges of a rectangle. Therefore, if the added point falls on
794+ * the left or bottom edge of the enlarged rectangle,
795+ * <code>contains</code> returns <code>false</code> for that point.
796+ * @param newx the X coordinate of the new point
797+ * @param newy the Y coordinate of the new point
798+ * @since 1.2
799+ */
800+ public void add(double newx, double newy) {
801+ double x1 = Math.min(getMinX(), newx);
802+ double x2 = Math.max(getMaxX(), newx);
803+ double y1 = Math.min(getMinY(), newy);
804+ double y2 = Math.max(getMaxY(), newy);
805+ setRect(x1, y1, x2 - x1, y2 - y1);
806+ }
807+
808+ /**
809+ * Adds the <code>Point2D</code> object <code>pt</code> to this
810+ * <code>Rectangle2D</code>.
811+ * The resulting <code>Rectangle2D</code> is the smallest
812+ * <code>Rectangle2D</code> that contains both the original
813+ * <code>Rectangle2D</code> and the specified <code>Point2D</code>.
814+ * <p>
815+ * After adding a point, a call to <code>contains</code> with the
816+ * added point as an argument does not necessarily return
817+ * <code>true</code>. The <code>contains</code>
818+ * method does not return <code>true</code> for points on the right
819+ * or bottom edges of a rectangle. Therefore, if the added point falls
820+ * on the left or bottom edge of the enlarged rectangle,
821+ * <code>contains</code> returns <code>false</code> for that point.
822+ * @param pt the new <code>Point2D</code> to add to this
823+ * <code>Rectangle2D</code>.
824+ * @since 1.2
825+ */
826+ public void add(Point2D pt) {
827+ add(pt.getX(), pt.getY());
828+ }
829+
830+ /**
831+ * Adds a <code>Rectangle2D</code> object to this
832+ * <code>Rectangle2D</code>. The resulting <code>Rectangle2D</code>
833+ * is the union of the two <code>Rectangle2D</code> objects.
834+ * @param r the <code>Rectangle2D</code> to add to this
835+ * <code>Rectangle2D</code>.
836+ * @since 1.2
837+ */
838+ public void add(Rectangle2D r) {
839+ double x1 = Math.min(getMinX(), r.getMinX());
840+ double x2 = Math.max(getMaxX(), r.getMaxX());
841+ double y1 = Math.min(getMinY(), r.getMinY());
842+ double y2 = Math.max(getMaxY(), r.getMaxY());
843+ setRect(x1, y1, x2 - x1, y2 - y1);
844+ }
845+
846+ /**
847+ * Returns an iteration object that defines the boundary of this
848+ * <code>Rectangle2D</code>.
849+ * The iterator for this class is multi-threaded safe, which means
850+ * that this <code>Rectangle2D</code> class guarantees that
851+ * modifications to the geometry of this <code>Rectangle2D</code>
852+ * object do not affect any iterations of that geometry that
853+ * are already in process.
854+ * @param at an optional <code>AffineTransform</code> to be applied to
855+ * the coordinates as they are returned in the iteration, or
856+ * <code>null</code> if untransformed coordinates are desired
857+ * @return the <code>PathIterator</code> object that returns the
858+ * geometry of the outline of this
859+ * <code>Rectangle2D</code>, one segment at a time.
860+ * @since 1.2
861+ */
862+ public PathIterator getPathIterator(AffineTransform at) {
863+ return new RectIterator(this, at);
864+ }
865+
866+ /**
867+ * Returns an iteration object that defines the boundary of the
868+ * flattened <code>Rectangle2D</code>. Since rectangles are already
869+ * flat, the <code>flatness</code> parameter is ignored.
870+ * The iterator for this class is multi-threaded safe, which means
871+ * that this <code>Rectangle2D</code> class guarantees that
872+ * modifications to the geometry of this <code>Rectangle2D</code>
873+ * object do not affect any iterations of that geometry that
874+ * are already in process.
875+ * @param at an optional <code>AffineTransform</code> to be applied to
876+ * the coordinates as they are returned in the iteration, or
877+ * <code>null</code> if untransformed coordinates are desired
878+ * @param flatness the maximum distance that the line segments used to
879+ * approximate the curved segments are allowed to deviate from any
880+ * point on the original curve. Since rectangles are already flat,
881+ * the <code>flatness</code> parameter is ignored.
882+ * @return the <code>PathIterator</code> object that returns the
883+ * geometry of the outline of this
884+ * <code>Rectangle2D</code>, one segment at a time.
885+ * @since 1.2
886+ */
887+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
888+ return new RectIterator(this, at);
889+ }
890+
891+ /**
892+ * Returns the hashcode for this <code>Rectangle2D</code>.
893+ * @return the hashcode for this <code>Rectangle2D</code>.
894+ * @since 1.2
895+ */
896+ public int hashCode() {
897+ long bits = java.lang.Double.doubleToLongBits(getX());
898+ bits += java.lang.Double.doubleToLongBits(getY()) * 37;
899+ bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
900+ bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
901+ return (((int) bits) ^ ((int) (bits >> 32)));
902+ }
903+
904+ /**
905+ * Determines whether or not the specified <code>Object</code> is
906+ * equal to this <code>Rectangle2D</code>. The specified
907+ * <code>Object</code> is equal to this <code>Rectangle2D</code>
908+ * if it is an instance of <code>Rectangle2D</code> and if its
909+ * location and size are the same as this <code>Rectangle2D</code>.
910+ * @param obj an <code>Object</code> to be compared with this
911+ * <code>Rectangle2D</code>.
912+ * @return <code>true</code> if <code>obj</code> is an instance
913+ * of <code>Rectangle2D</code> and has
914+ * the same values; <code>false</code> otherwise.
915+ * @since 1.2
916+ */
917+ public boolean equals(Object obj) {
918+ if (obj == this) {
919+ return true;
920+ }
921+ if (obj instanceof Rectangle2D) {
922+ Rectangle2D r2d = (Rectangle2D) obj;
923+ return ((getX() == r2d.getX()) &&
924+ (getY() == r2d.getY()) &&
925+ (getWidth() == r2d.getWidth()) &&
926+ (getHeight() == r2d.getHeight()));
927+ }
928+ return false;
929+ }
930+}
java/pkg/java/awt/geom/RectangularShape.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/RectangularShape.java+397−0
@@ -0,0 +1,397 @@
1+/*
2+ * Copyright (c) 1997, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.awt.Shape;
29+import java.awt.Rectangle;
30+import java.beans.Transient;
31+
32+/**
33+ * <code>RectangularShape</code> is the base class for a number of
34+ * {@link Shape} objects whose geometry is defined by a rectangular frame.
35+ * This class does not directly specify any specific geometry by
36+ * itself, but merely provides manipulation methods inherited by
37+ * a whole category of <code>Shape</code> objects.
38+ * The manipulation methods provided by this class can be used to
39+ * query and modify the rectangular frame, which provides a reference
40+ * for the subclasses to define their geometry.
41+ *
42+ * @author Jim Graham
43+ * @since 1.2
44+ */
45+public abstract class RectangularShape implements Shape, Cloneable {
46+
47+ /**
48+ * This is an abstract class that cannot be instantiated directly.
49+ *
50+ * @see Arc2D
51+ * @see Ellipse2D
52+ * @see Rectangle2D
53+ * @see RoundRectangle2D
54+ * @since 1.2
55+ */
56+ protected RectangularShape() {
57+ }
58+
59+ /**
60+ * Returns the X coordinate of the upper-left corner of
61+ * the framing rectangle in <code>double</code> precision.
62+ * @return the X coordinate of the upper-left corner of
63+ * the framing rectangle.
64+ * @since 1.2
65+ */
66+ public abstract double getX();
67+
68+ /**
69+ * Returns the Y coordinate of the upper-left corner of
70+ * the framing rectangle in <code>double</code> precision.
71+ * @return the Y coordinate of the upper-left corner of
72+ * the framing rectangle.
73+ * @since 1.2
74+ */
75+ public abstract double getY();
76+
77+ /**
78+ * Returns the width of the framing rectangle in
79+ * <code>double</code> precision.
80+ * @return the width of the framing rectangle.
81+ * @since 1.2
82+ */
83+ public abstract double getWidth();
84+
85+ /**
86+ * Returns the height of the framing rectangle
87+ * in <code>double</code> precision.
88+ * @return the height of the framing rectangle.
89+ * @since 1.2
90+ */
91+ public abstract double getHeight();
92+
93+ /**
94+ * Returns the smallest X coordinate of the framing
95+ * rectangle of the <code>Shape</code> in <code>double</code>
96+ * precision.
97+ * @return the smallest X coordinate of the framing
98+ * rectangle of the <code>Shape</code>.
99+ * @since 1.2
100+ */
101+ public double getMinX() {
102+ return getX();
103+ }
104+
105+ /**
106+ * Returns the smallest Y coordinate of the framing
107+ * rectangle of the <code>Shape</code> in <code>double</code>
108+ * precision.
109+ * @return the smallest Y coordinate of the framing
110+ * rectangle of the <code>Shape</code>.
111+ * @since 1.2
112+ */
113+ public double getMinY() {
114+ return getY();
115+ }
116+
117+ /**
118+ * Returns the largest X coordinate of the framing
119+ * rectangle of the <code>Shape</code> in <code>double</code>
120+ * precision.
121+ * @return the largest X coordinate of the framing
122+ * rectangle of the <code>Shape</code>.
123+ * @since 1.2
124+ */
125+ public double getMaxX() {
126+ return getX() + getWidth();
127+ }
128+
129+ /**
130+ * Returns the largest Y coordinate of the framing
131+ * rectangle of the <code>Shape</code> in <code>double</code>
132+ * precision.
133+ * @return the largest Y coordinate of the framing
134+ * rectangle of the <code>Shape</code>.
135+ * @since 1.2
136+ */
137+ public double getMaxY() {
138+ return getY() + getHeight();
139+ }
140+
141+ /**
142+ * Returns the X coordinate of the center of the framing
143+ * rectangle of the <code>Shape</code> in <code>double</code>
144+ * precision.
145+ * @return the X coordinate of the center of the framing rectangle
146+ * of the <code>Shape</code>.
147+ * @since 1.2
148+ */
149+ public double getCenterX() {
150+ return getX() + getWidth() / 2.0;
151+ }
152+
153+ /**
154+ * Returns the Y coordinate of the center of the framing
155+ * rectangle of the <code>Shape</code> in <code>double</code>
156+ * precision.
157+ * @return the Y coordinate of the center of the framing rectangle
158+ * of the <code>Shape</code>.
159+ * @since 1.2
160+ */
161+ public double getCenterY() {
162+ return getY() + getHeight() / 2.0;
163+ }
164+
165+ /**
166+ * Returns the framing {@link Rectangle2D}
167+ * that defines the overall shape of this object.
168+ * @return a <code>Rectangle2D</code>, specified in
169+ * <code>double</code> coordinates.
170+ * @see #setFrame(double, double, double, double)
171+ * @see #setFrame(Point2D, Dimension2D)
172+ * @see #setFrame(Rectangle2D)
173+ * @since 1.2
174+ */
175+ @Transient
176+ public Rectangle2D getFrame() {
177+ return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
178+ }
179+
180+ /**
181+ * Determines whether the <code>RectangularShape</code> is empty.
182+ * When the <code>RectangularShape</code> is empty, it encloses no
183+ * area.
184+ * @return <code>true</code> if the <code>RectangularShape</code> is empty;
185+ * <code>false</code> otherwise.
186+ * @since 1.2
187+ */
188+ public abstract boolean isEmpty();
189+
190+ /**
191+ * Sets the location and size of the framing rectangle of this
192+ * <code>Shape</code> to the specified rectangular values.
193+ *
194+ * @param x the X coordinate of the upper-left corner of the
195+ * specified rectangular shape
196+ * @param y the Y coordinate of the upper-left corner of the
197+ * specified rectangular shape
198+ * @param w the width of the specified rectangular shape
199+ * @param h the height of the specified rectangular shape
200+ * @see #getFrame
201+ * @since 1.2
202+ */
203+ public abstract void setFrame(double x, double y, double w, double h);
204+
205+ /**
206+ * Sets the location and size of the framing rectangle of this
207+ * <code>Shape</code> to the specified {@link Point2D} and
208+ * {@link Dimension2D}, respectively. The framing rectangle is used
209+ * by the subclasses of <code>RectangularShape</code> to define
210+ * their geometry.
211+ * @param loc the specified <code>Point2D</code>
212+ * @param size the specified <code>Dimension2D</code>
213+ * @see #getFrame
214+ * @since 1.2
215+ */
216+ public void setFrame(Point2D loc, Dimension2D size) {
217+ setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
218+ }
219+
220+ /**
221+ * Sets the framing rectangle of this <code>Shape</code> to
222+ * be the specified <code>Rectangle2D</code>. The framing rectangle is
223+ * used by the subclasses of <code>RectangularShape</code> to define
224+ * their geometry.
225+ * @param r the specified <code>Rectangle2D</code>
226+ * @see #getFrame
227+ * @since 1.2
228+ */
229+ public void setFrame(Rectangle2D r) {
230+ setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
231+ }
232+
233+ /**
234+ * Sets the diagonal of the framing rectangle of this <code>Shape</code>
235+ * based on the two specified coordinates. The framing rectangle is
236+ * used by the subclasses of <code>RectangularShape</code> to define
237+ * their geometry.
238+ *
239+ * @param x1 the X coordinate of the start point of the specified diagonal
240+ * @param y1 the Y coordinate of the start point of the specified diagonal
241+ * @param x2 the X coordinate of the end point of the specified diagonal
242+ * @param y2 the Y coordinate of the end point of the specified diagonal
243+ * @since 1.2
244+ */
245+ public void setFrameFromDiagonal(double x1, double y1,
246+ double x2, double y2) {
247+ if (x2 < x1) {
248+ double t = x1;
249+ x1 = x2;
250+ x2 = t;
251+ }
252+ if (y2 < y1) {
253+ double t = y1;
254+ y1 = y2;
255+ y2 = t;
256+ }
257+ setFrame(x1, y1, x2 - x1, y2 - y1);
258+ }
259+
260+ /**
261+ * Sets the diagonal of the framing rectangle of this <code>Shape</code>
262+ * based on two specified <code>Point2D</code> objects. The framing
263+ * rectangle is used by the subclasses of <code>RectangularShape</code>
264+ * to define their geometry.
265+ *
266+ * @param p1 the start <code>Point2D</code> of the specified diagonal
267+ * @param p2 the end <code>Point2D</code> of the specified diagonal
268+ * @since 1.2
269+ */
270+ public void setFrameFromDiagonal(Point2D p1, Point2D p2) {
271+ setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
272+ }
273+
274+ /**
275+ * Sets the framing rectangle of this <code>Shape</code>
276+ * based on the specified center point coordinates and corner point
277+ * coordinates. The framing rectangle is used by the subclasses of
278+ * <code>RectangularShape</code> to define their geometry.
279+ *
280+ * @param centerX the X coordinate of the specified center point
281+ * @param centerY the Y coordinate of the specified center point
282+ * @param cornerX the X coordinate of the specified corner point
283+ * @param cornerY the Y coordinate of the specified corner point
284+ * @since 1.2
285+ */
286+ public void setFrameFromCenter(double centerX, double centerY,
287+ double cornerX, double cornerY) {
288+ double halfW = Math.abs(cornerX - centerX);
289+ double halfH = Math.abs(cornerY - centerY);
290+ setFrame(centerX - halfW, centerY - halfH, halfW * 2.0, halfH * 2.0);
291+ }
292+
293+ /**
294+ * Sets the framing rectangle of this <code>Shape</code> based on a
295+ * specified center <code>Point2D</code> and corner
296+ * <code>Point2D</code>. The framing rectangle is used by the subclasses
297+ * of <code>RectangularShape</code> to define their geometry.
298+ * @param center the specified center <code>Point2D</code>
299+ * @param corner the specified corner <code>Point2D</code>
300+ * @since 1.2
301+ */
302+ public void setFrameFromCenter(Point2D center, Point2D corner) {
303+ setFrameFromCenter(center.getX(), center.getY(),
304+ corner.getX(), corner.getY());
305+ }
306+
307+ /**
308+ * {@inheritDoc}
309+ * @since 1.2
310+ */
311+ public boolean contains(Point2D p) {
312+ return contains(p.getX(), p.getY());
313+ }
314+
315+ /**
316+ * {@inheritDoc}
317+ * @since 1.2
318+ */
319+ public boolean intersects(Rectangle2D r) {
320+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
321+ }
322+
323+ /**
324+ * {@inheritDoc}
325+ * @since 1.2
326+ */
327+ public boolean contains(Rectangle2D r) {
328+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
329+ }
330+
331+ /**
332+ * {@inheritDoc}
333+ * @since 1.2
334+ */
335+ public Rectangle getBounds() {
336+ double width = getWidth();
337+ double height = getHeight();
338+ if (width < 0 || height < 0) {
339+ return new Rectangle();
340+ }
341+ double x = getX();
342+ double y = getY();
343+ double x1 = Math.floor(x);
344+ double y1 = Math.floor(y);
345+ double x2 = Math.ceil(x + width);
346+ double y2 = Math.ceil(y + height);
347+ return new Rectangle((int) x1, (int) y1,
348+ (int) (x2 - x1), (int) (y2 - y1));
349+ }
350+
351+ /**
352+ * Returns an iterator object that iterates along the
353+ * <code>Shape</code> object's boundary and provides access to a
354+ * flattened view of the outline of the <code>Shape</code>
355+ * object's geometry.
356+ * <p>
357+ * Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point types will
358+ * be returned by the iterator.
359+ * <p>
360+ * The amount of subdivision of the curved segments is controlled
361+ * by the <code>flatness</code> parameter, which specifies the
362+ * maximum distance that any point on the unflattened transformed
363+ * curve can deviate from the returned flattened path segments.
364+ * An optional {@link AffineTransform} can
365+ * be specified so that the coordinates returned in the iteration are
366+ * transformed accordingly.
367+ * @param at an optional <code>AffineTransform</code> to be applied to the
368+ * coordinates as they are returned in the iteration,
369+ * or <code>null</code> if untransformed coordinates are desired.
370+ * @param flatness the maximum distance that the line segments used to
371+ * approximate the curved segments are allowed to deviate
372+ * from any point on the original curve
373+ * @return a <code>PathIterator</code> object that provides access to
374+ * the <code>Shape</code> object's flattened geometry.
375+ * @since 1.2
376+ */
377+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
378+ return new FlatteningPathIterator(getPathIterator(at), flatness);
379+ }
380+
381+ /**
382+ * Creates a new object of the same class and with the same
383+ * contents as this object.
384+ * @return a clone of this instance.
385+ * @exception OutOfMemoryError if there is not enough memory.
386+ * @see java.lang.Cloneable
387+ * @since 1.2
388+ */
389+ public Object clone() {
390+ try {
391+ return super.clone();
392+ } catch (CloneNotSupportedException e) {
393+ // this shouldn't happen, since we are Cloneable
394+ throw new InternalError();
395+ }
396+ }
397+}
java/pkg/java/awt/geom/RoundRectIterator.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/RoundRectIterator.java+189−0
@@ -0,0 +1,189 @@
1+/*
2+ * Copyright (c) 1997, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.util.*;
29+
30+/**
31+ * A utility class to iterate over the path segments of an rounded rectangle
32+ * through the PathIterator interface.
33+ *
34+ * @author Jim Graham
35+ */
36+class RoundRectIterator implements PathIterator {
37+ double x, y, w, h, aw, ah;
38+ AffineTransform affine;
39+ int index;
40+
41+ RoundRectIterator(RoundRectangle2D rr, AffineTransform at) {
42+ this.x = rr.getX();
43+ this.y = rr.getY();
44+ this.w = rr.getWidth();
45+ this.h = rr.getHeight();
46+ this.aw = Math.min(w, Math.abs(rr.getArcWidth()));
47+ this.ah = Math.min(h, Math.abs(rr.getArcHeight()));
48+ this.affine = at;
49+ if (aw < 0 || ah < 0) {
50+ // Don't draw anything...
51+ index = ctrlpts.length;
52+ }
53+ }
54+
55+ /**
56+ * Return the winding rule for determining the insideness of the
57+ * path.
58+ * @see #WIND_EVEN_ODD
59+ * @see #WIND_NON_ZERO
60+ */
61+ public int getWindingRule() {
62+ return WIND_NON_ZERO;
63+ }
64+
65+ /**
66+ * Tests if there are more points to read.
67+ * @return true if there are more points to read
68+ */
69+ public boolean isDone() {
70+ return index >= ctrlpts.length;
71+ }
72+
73+ /**
74+ * Moves the iterator to the next segment of the path forwards
75+ * along the primary direction of traversal as long as there are
76+ * more points in that direction.
77+ */
78+ public void next() {
79+ index++;
80+ }
81+
82+ private static final double angle = Math.PI / 4.0;
83+ private static final double a = 1.0 - Math.cos(angle);
84+ private static final double b = Math.tan(angle);
85+ private static final double c = Math.sqrt(1.0 + b * b) - 1 + a;
86+ private static final double cv = 4.0 / 3.0 * a * b / c;
87+ private static final double acv = (1.0 - cv) / 2.0;
88+
89+ // For each array:
90+ // 4 values for each point {v0, v1, v2, v3}:
91+ // point = (x + v0 * w + v1 * arcWidth,
92+ // y + v2 * h + v3 * arcHeight);
93+ private static double ctrlpts[][] = {
94+ { 0.0, 0.0, 0.0, 0.5 },
95+ { 0.0, 0.0, 1.0, -0.5 },
96+ { 0.0, 0.0, 1.0, -acv,
97+ 0.0, acv, 1.0, 0.0,
98+ 0.0, 0.5, 1.0, 0.0 },
99+ { 1.0, -0.5, 1.0, 0.0 },
100+ { 1.0, -acv, 1.0, 0.0,
101+ 1.0, 0.0, 1.0, -acv,
102+ 1.0, 0.0, 1.0, -0.5 },
103+ { 1.0, 0.0, 0.0, 0.5 },
104+ { 1.0, 0.0, 0.0, acv,
105+ 1.0, -acv, 0.0, 0.0,
106+ 1.0, -0.5, 0.0, 0.0 },
107+ { 0.0, 0.5, 0.0, 0.0 },
108+ { 0.0, acv, 0.0, 0.0,
109+ 0.0, 0.0, 0.0, acv,
110+ 0.0, 0.0, 0.0, 0.5 },
111+ {},
112+ };
113+ private static int types[] = {
114+ SEG_MOVETO,
115+ SEG_LINETO, SEG_CUBICTO,
116+ SEG_LINETO, SEG_CUBICTO,
117+ SEG_LINETO, SEG_CUBICTO,
118+ SEG_LINETO, SEG_CUBICTO,
119+ SEG_CLOSE,
120+ };
121+
122+ /**
123+ * Returns the coordinates and type of the current path segment in
124+ * the iteration.
125+ * The return value is the path segment type:
126+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
127+ * A float array of length 6 must be passed in and may be used to
128+ * store the coordinates of the point(s).
129+ * Each point is stored as a pair of float x,y coordinates.
130+ * SEG_MOVETO and SEG_LINETO types will return one point,
131+ * SEG_QUADTO will return two points,
132+ * SEG_CUBICTO will return 3 points
133+ * and SEG_CLOSE will not return any points.
134+ * @see #SEG_MOVETO
135+ * @see #SEG_LINETO
136+ * @see #SEG_QUADTO
137+ * @see #SEG_CUBICTO
138+ * @see #SEG_CLOSE
139+ */
140+ public int currentSegment(float[] coords) {
141+ if (isDone()) {
142+ throw new NoSuchElementException("roundrect iterator out of bounds");
143+ }
144+ double ctrls[] = ctrlpts[index];
145+ int nc = 0;
146+ for (int i = 0; i < ctrls.length; i += 4) {
147+ coords[nc++] = (float) (x + ctrls[i + 0] * w + ctrls[i + 1] * aw);
148+ coords[nc++] = (float) (y + ctrls[i + 2] * h + ctrls[i + 3] * ah);
149+ }
150+ if (affine != null) {
151+ affine.transform(coords, 0, coords, 0, nc / 2);
152+ }
153+ return types[index];
154+ }
155+
156+ /**
157+ * Returns the coordinates and type of the current path segment in
158+ * the iteration.
159+ * The return value is the path segment type:
160+ * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
161+ * A double array of length 6 must be passed in and may be used to
162+ * store the coordinates of the point(s).
163+ * Each point is stored as a pair of double x,y coordinates.
164+ * SEG_MOVETO and SEG_LINETO types will return one point,
165+ * SEG_QUADTO will return two points,
166+ * SEG_CUBICTO will return 3 points
167+ * and SEG_CLOSE will not return any points.
168+ * @see #SEG_MOVETO
169+ * @see #SEG_LINETO
170+ * @see #SEG_QUADTO
171+ * @see #SEG_CUBICTO
172+ * @see #SEG_CLOSE
173+ */
174+ public int currentSegment(double[] coords) {
175+ if (isDone()) {
176+ throw new NoSuchElementException("roundrect iterator out of bounds");
177+ }
178+ double ctrls[] = ctrlpts[index];
179+ int nc = 0;
180+ for (int i = 0; i < ctrls.length; i += 4) {
181+ coords[nc++] = (x + ctrls[i + 0] * w + ctrls[i + 1] * aw);
182+ coords[nc++] = (y + ctrls[i + 2] * h + ctrls[i + 3] * ah);
183+ }
184+ if (affine != null) {
185+ affine.transform(coords, 0, coords, 0, nc / 2);
186+ }
187+ return types[index];
188+ }
189+}
java/pkg/java/awt/geom/RoundRectangle2D$Double.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/RoundRectangle2D$Float.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/RoundRectangle2D.class+0−0

Binary file not shown.

java/pkg/java/awt/geom/RoundRectangle2D.java+681−0
@@ -0,0 +1,681 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt.geom;
27+
28+import java.io.Serializable;
29+
30+/**
31+ * The <code>RoundRectangle2D</code> class defines a rectangle with
32+ * rounded corners defined by a location {@code (x,y)}, a
33+ * dimension {@code (w x h)}, and the width and height of an arc
34+ * with which to round the corners.
35+ * <p>
36+ * This class is the abstract superclass for all objects that
37+ * store a 2D rounded rectangle.
38+ * The actual storage representation of the coordinates is left to
39+ * the subclass.
40+ *
41+ * @author Jim Graham
42+ * @since 1.2
43+ */
44+public abstract class RoundRectangle2D extends RectangularShape {
45+
46+ /**
47+ * The <code>Float</code> class defines a rectangle with rounded
48+ * corners all specified in <code>float</code> coordinates.
49+ * @since 1.2
50+ */
51+ public static class Float extends RoundRectangle2D
52+ implements Serializable
53+ {
54+ /**
55+ * The X coordinate of this <code>RoundRectangle2D</code>.
56+ * @since 1.2
57+ * @serial
58+ */
59+ public float x;
60+
61+ /**
62+ * The Y coordinate of this <code>RoundRectangle2D</code>.
63+ * @since 1.2
64+ * @serial
65+ */
66+ public float y;
67+
68+ /**
69+ * The width of this <code>RoundRectangle2D</code>.
70+ * @since 1.2
71+ * @serial
72+ */
73+ public float width;
74+
75+ /**
76+ * The height of this <code>RoundRectangle2D</code>.
77+ * @since 1.2
78+ * @serial
79+ */
80+ public float height;
81+
82+ /**
83+ * The width of the arc that rounds off the corners.
84+ * @since 1.2
85+ * @serial
86+ */
87+ public float arcwidth;
88+
89+ /**
90+ * The height of the arc that rounds off the corners.
91+ * @since 1.2
92+ * @serial
93+ */
94+ public float archeight;
95+
96+ /**
97+ * Constructs a new <code>RoundRectangle2D</code>, initialized to
98+ * location (0.0,&nbsp;0.0), size (0.0,&nbsp;0.0), and corner arcs
99+ * of radius 0.0.
100+ * @since 1.2
101+ */
102+ public Float() {
103+ }
104+
105+ /**
106+ * Constructs and initializes a <code>RoundRectangle2D</code>
107+ * from the specified <code>float</code> coordinates.
108+ *
109+ * @param x the X coordinate of the newly
110+ * constructed <code>RoundRectangle2D</code>
111+ * @param y the Y coordinate of the newly
112+ * constructed <code>RoundRectangle2D</code>
113+ * @param w the width to which to set the newly
114+ * constructed <code>RoundRectangle2D</code>
115+ * @param h the height to which to set the newly
116+ * constructed <code>RoundRectangle2D</code>
117+ * @param arcw the width of the arc to use to round off the
118+ * corners of the newly constructed
119+ * <code>RoundRectangle2D</code>
120+ * @param arch the height of the arc to use to round off the
121+ * corners of the newly constructed
122+ * <code>RoundRectangle2D</code>
123+ * @since 1.2
124+ */
125+ public Float(float x, float y, float w, float h,
126+ float arcw, float arch)
127+ {
128+ setRoundRect(x, y, w, h, arcw, arch);
129+ }
130+
131+ /**
132+ * {@inheritDoc}
133+ * @since 1.2
134+ */
135+ public double getX() {
136+ return (double) x;
137+ }
138+
139+ /**
140+ * {@inheritDoc}
141+ * @since 1.2
142+ */
143+ public double getY() {
144+ return (double) y;
145+ }
146+
147+ /**
148+ * {@inheritDoc}
149+ * @since 1.2
150+ */
151+ public double getWidth() {
152+ return (double) width;
153+ }
154+
155+ /**
156+ * {@inheritDoc}
157+ * @since 1.2
158+ */
159+ public double getHeight() {
160+ return (double) height;
161+ }
162+
163+ /**
164+ * {@inheritDoc}
165+ * @since 1.2
166+ */
167+ public double getArcWidth() {
168+ return (double) arcwidth;
169+ }
170+
171+ /**
172+ * {@inheritDoc}
173+ * @since 1.2
174+ */
175+ public double getArcHeight() {
176+ return (double) archeight;
177+ }
178+
179+ /**
180+ * {@inheritDoc}
181+ * @since 1.2
182+ */
183+ public boolean isEmpty() {
184+ return (width <= 0.0f) || (height <= 0.0f);
185+ }
186+
187+ /**
188+ * Sets the location, size, and corner radii of this
189+ * <code>RoundRectangle2D</code> to the specified
190+ * <code>float</code> values.
191+ *
192+ * @param x the X coordinate to which to set the
193+ * location of this <code>RoundRectangle2D</code>
194+ * @param y the Y coordinate to which to set the
195+ * location of this <code>RoundRectangle2D</code>
196+ * @param w the width to which to set this
197+ * <code>RoundRectangle2D</code>
198+ * @param h the height to which to set this
199+ * <code>RoundRectangle2D</code>
200+ * @param arcw the width to which to set the arc of this
201+ * <code>RoundRectangle2D</code>
202+ * @param arch the height to which to set the arc of this
203+ * <code>RoundRectangle2D</code>
204+ * @since 1.2
205+ */
206+ public void setRoundRect(float x, float y, float w, float h,
207+ float arcw, float arch)
208+ {
209+ this.x = x;
210+ this.y = y;
211+ this.width = w;
212+ this.height = h;
213+ this.arcwidth = arcw;
214+ this.archeight = arch;
215+ }
216+
217+ /**
218+ * {@inheritDoc}
219+ * @since 1.2
220+ */
221+ public void setRoundRect(double x, double y, double w, double h,
222+ double arcw, double arch)
223+ {
224+ this.x = (float) x;
225+ this.y = (float) y;
226+ this.width = (float) w;
227+ this.height = (float) h;
228+ this.arcwidth = (float) arcw;
229+ this.archeight = (float) arch;
230+ }
231+
232+ /**
233+ * {@inheritDoc}
234+ * @since 1.2
235+ */
236+ public void setRoundRect(RoundRectangle2D rr) {
237+ this.x = (float) rr.getX();
238+ this.y = (float) rr.getY();
239+ this.width = (float) rr.getWidth();
240+ this.height = (float) rr.getHeight();
241+ this.arcwidth = (float) rr.getArcWidth();
242+ this.archeight = (float) rr.getArcHeight();
243+ }
244+
245+ /**
246+ * {@inheritDoc}
247+ * @since 1.2
248+ */
249+ public Rectangle2D getBounds2D() {
250+ return new Rectangle2D.Float(x, y, width, height);
251+ }
252+
253+ /*
254+ * JDK 1.6 serialVersionUID
255+ */
256+ private static final long serialVersionUID = -3423150618393866922L;
257+ }
258+
259+ /**
260+ * The <code>Double</code> class defines a rectangle with rounded
261+ * corners all specified in <code>double</code> coordinates.
262+ * @since 1.2
263+ */
264+ public static class Double extends RoundRectangle2D
265+ implements Serializable
266+ {
267+ /**
268+ * The X coordinate of this <code>RoundRectangle2D</code>.
269+ * @since 1.2
270+ * @serial
271+ */
272+ public double x;
273+
274+ /**
275+ * The Y coordinate of this <code>RoundRectangle2D</code>.
276+ * @since 1.2
277+ * @serial
278+ */
279+ public double y;
280+
281+ /**
282+ * The width of this <code>RoundRectangle2D</code>.
283+ * @since 1.2
284+ * @serial
285+ */
286+ public double width;
287+
288+ /**
289+ * The height of this <code>RoundRectangle2D</code>.
290+ * @since 1.2
291+ * @serial
292+ */
293+ public double height;
294+
295+ /**
296+ * The width of the arc that rounds off the corners.
297+ * @since 1.2
298+ * @serial
299+ */
300+ public double arcwidth;
301+
302+ /**
303+ * The height of the arc that rounds off the corners.
304+ * @since 1.2
305+ * @serial
306+ */
307+ public double archeight;
308+
309+ /**
310+ * Constructs a new <code>RoundRectangle2D</code>, initialized to
311+ * location (0.0,&nbsp;0.0), size (0.0,&nbsp;0.0), and corner arcs
312+ * of radius 0.0.
313+ * @since 1.2
314+ */
315+ public Double() {
316+ }
317+
318+ /**
319+ * Constructs and initializes a <code>RoundRectangle2D</code>
320+ * from the specified <code>double</code> coordinates.
321+ *
322+ * @param x the X coordinate of the newly
323+ * constructed <code>RoundRectangle2D</code>
324+ * @param y the Y coordinate of the newly
325+ * constructed <code>RoundRectangle2D</code>
326+ * @param w the width to which to set the newly
327+ * constructed <code>RoundRectangle2D</code>
328+ * @param h the height to which to set the newly
329+ * constructed <code>RoundRectangle2D</code>
330+ * @param arcw the width of the arc to use to round off the
331+ * corners of the newly constructed
332+ * <code>RoundRectangle2D</code>
333+ * @param arch the height of the arc to use to round off the
334+ * corners of the newly constructed
335+ * <code>RoundRectangle2D</code>
336+ * @since 1.2
337+ */
338+ public Double(double x, double y, double w, double h,
339+ double arcw, double arch)
340+ {
341+ setRoundRect(x, y, w, h, arcw, arch);
342+ }
343+
344+ /**
345+ * {@inheritDoc}
346+ * @since 1.2
347+ */
348+ public double getX() {
349+ return x;
350+ }
351+
352+ /**
353+ * {@inheritDoc}
354+ * @since 1.2
355+ */
356+ public double getY() {
357+ return y;
358+ }
359+
360+ /**
361+ * {@inheritDoc}
362+ * @since 1.2
363+ */
364+ public double getWidth() {
365+ return width;
366+ }
367+
368+ /**
369+ * {@inheritDoc}
370+ * @since 1.2
371+ */
372+ public double getHeight() {
373+ return height;
374+ }
375+
376+ /**
377+ * {@inheritDoc}
378+ * @since 1.2
379+ */
380+ public double getArcWidth() {
381+ return arcwidth;
382+ }
383+
384+ /**
385+ * {@inheritDoc}
386+ * @since 1.2
387+ */
388+ public double getArcHeight() {
389+ return archeight;
390+ }
391+
392+ /**
393+ * {@inheritDoc}
394+ * @since 1.2
395+ */
396+ public boolean isEmpty() {
397+ return (width <= 0.0f) || (height <= 0.0f);
398+ }
399+
400+ /**
401+ * {@inheritDoc}
402+ * @since 1.2
403+ */
404+ public void setRoundRect(double x, double y, double w, double h,
405+ double arcw, double arch)
406+ {
407+ this.x = x;
408+ this.y = y;
409+ this.width = w;
410+ this.height = h;
411+ this.arcwidth = arcw;
412+ this.archeight = arch;
413+ }
414+
415+ /**
416+ * {@inheritDoc}
417+ * @since 1.2
418+ */
419+ public void setRoundRect(RoundRectangle2D rr) {
420+ this.x = rr.getX();
421+ this.y = rr.getY();
422+ this.width = rr.getWidth();
423+ this.height = rr.getHeight();
424+ this.arcwidth = rr.getArcWidth();
425+ this.archeight = rr.getArcHeight();
426+ }
427+
428+ /**
429+ * {@inheritDoc}
430+ * @since 1.2
431+ */
432+ public Rectangle2D getBounds2D() {
433+ return new Rectangle2D.Double(x, y, width, height);
434+ }
435+
436+ /*
437+ * JDK 1.6 serialVersionUID
438+ */
439+ private static final long serialVersionUID = 1048939333485206117L;
440+ }
441+
442+ /**
443+ * This is an abstract class that cannot be instantiated directly.
444+ * Type-specific implementation subclasses are available for
445+ * instantiation and provide a number of formats for storing
446+ * the information necessary to satisfy the various accessor
447+ * methods below.
448+ *
449+ * @see java.awt.geom.RoundRectangle2D.Float
450+ * @see java.awt.geom.RoundRectangle2D.Double
451+ * @since 1.2
452+ */
453+ protected RoundRectangle2D() {
454+ }
455+
456+ /**
457+ * Gets the width of the arc that rounds off the corners.
458+ * @return the width of the arc that rounds off the corners
459+ * of this <code>RoundRectangle2D</code>.
460+ * @since 1.2
461+ */
462+ public abstract double getArcWidth();
463+
464+ /**
465+ * Gets the height of the arc that rounds off the corners.
466+ * @return the height of the arc that rounds off the corners
467+ * of this <code>RoundRectangle2D</code>.
468+ * @since 1.2
469+ */
470+ public abstract double getArcHeight();
471+
472+ /**
473+ * Sets the location, size, and corner radii of this
474+ * <code>RoundRectangle2D</code> to the specified
475+ * <code>double</code> values.
476+ *
477+ * @param x the X coordinate to which to set the
478+ * location of this <code>RoundRectangle2D</code>
479+ * @param y the Y coordinate to which to set the
480+ * location of this <code>RoundRectangle2D</code>
481+ * @param w the width to which to set this
482+ * <code>RoundRectangle2D</code>
483+ * @param h the height to which to set this
484+ * <code>RoundRectangle2D</code>
485+ * @param arcWidth the width to which to set the arc of this
486+ * <code>RoundRectangle2D</code>
487+ * @param arcHeight the height to which to set the arc of this
488+ * <code>RoundRectangle2D</code>
489+ * @since 1.2
490+ */
491+ public abstract void setRoundRect(double x, double y, double w, double h,
492+ double arcWidth, double arcHeight);
493+
494+ /**
495+ * Sets this <code>RoundRectangle2D</code> to be the same as the
496+ * specified <code>RoundRectangle2D</code>.
497+ * @param rr the specified <code>RoundRectangle2D</code>
498+ * @since 1.2
499+ */
500+ public void setRoundRect(RoundRectangle2D rr) {
501+ setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(),
502+ rr.getArcWidth(), rr.getArcHeight());
503+ }
504+
505+ /**
506+ * {@inheritDoc}
507+ * @since 1.2
508+ */
509+ public void setFrame(double x, double y, double w, double h) {
510+ setRoundRect(x, y, w, h, getArcWidth(), getArcHeight());
511+ }
512+
513+ /**
514+ * {@inheritDoc}
515+ * @since 1.2
516+ */
517+ public boolean contains(double x, double y) {
518+ if (isEmpty()) {
519+ return false;
520+ }
521+ double rrx0 = getX();
522+ double rry0 = getY();
523+ double rrx1 = rrx0 + getWidth();
524+ double rry1 = rry0 + getHeight();
525+ // Check for trivial rejection - point is outside bounding rectangle
526+ if (x < rrx0 || y < rry0 || x >= rrx1 || y >= rry1) {
527+ return false;
528+ }
529+ double aw = Math.min(getWidth(), Math.abs(getArcWidth())) / 2.0;
530+ double ah = Math.min(getHeight(), Math.abs(getArcHeight())) / 2.0;
531+ // Check which corner point is in and do circular containment
532+ // test - otherwise simple acceptance
533+ if (x >= (rrx0 += aw) && x < (rrx0 = rrx1 - aw)) {
534+ return true;
535+ }
536+ if (y >= (rry0 += ah) && y < (rry0 = rry1 - ah)) {
537+ return true;
538+ }
539+ x = (x - rrx0) / aw;
540+ y = (y - rry0) / ah;
541+ return (x * x + y * y <= 1.0);
542+ }
543+
544+ private int classify(double coord, double left, double right,
545+ double arcsize)
546+ {
547+ if (coord < left) {
548+ return 0;
549+ } else if (coord < left + arcsize) {
550+ return 1;
551+ } else if (coord < right - arcsize) {
552+ return 2;
553+ } else if (coord < right) {
554+ return 3;
555+ } else {
556+ return 4;
557+ }
558+ }
559+
560+ /**
561+ * {@inheritDoc}
562+ * @since 1.2
563+ */
564+ public boolean intersects(double x, double y, double w, double h) {
565+ if (isEmpty() || w <= 0 || h <= 0) {
566+ return false;
567+ }
568+ double rrx0 = getX();
569+ double rry0 = getY();
570+ double rrx1 = rrx0 + getWidth();
571+ double rry1 = rry0 + getHeight();
572+ // Check for trivial rejection - bounding rectangles do not intersect
573+ if (x + w <= rrx0 || x >= rrx1 || y + h <= rry0 || y >= rry1) {
574+ return false;
575+ }
576+ double aw = Math.min(getWidth(), Math.abs(getArcWidth())) / 2.0;
577+ double ah = Math.min(getHeight(), Math.abs(getArcHeight())) / 2.0;
578+ int x0class = classify(x, rrx0, rrx1, aw);
579+ int x1class = classify(x + w, rrx0, rrx1, aw);
580+ int y0class = classify(y, rry0, rry1, ah);
581+ int y1class = classify(y + h, rry0, rry1, ah);
582+ // Trivially accept if any point is inside inner rectangle
583+ if (x0class == 2 || x1class == 2 || y0class == 2 || y1class == 2) {
584+ return true;
585+ }
586+ // Trivially accept if either edge spans inner rectangle
587+ if ((x0class < 2 && x1class > 2) || (y0class < 2 && y1class > 2)) {
588+ return true;
589+ }
590+ // Since neither edge spans the center, then one of the corners
591+ // must be in one of the rounded edges. We detect this case if
592+ // a [xy]0class is 3 or a [xy]1class is 1. One of those two cases
593+ // must be true for each direction.
594+ // We now find a "nearest point" to test for being inside a rounded
595+ // corner.
596+ x = (x1class == 1) ? (x = x + w - (rrx0 + aw)) : (x = x - (rrx1 - aw));
597+ y = (y1class == 1) ? (y = y + h - (rry0 + ah)) : (y = y - (rry1 - ah));
598+ x = x / aw;
599+ y = y / ah;
600+ return (x * x + y * y <= 1.0);
601+ }
602+
603+ /**
604+ * {@inheritDoc}
605+ * @since 1.2
606+ */
607+ public boolean contains(double x, double y, double w, double h) {
608+ if (isEmpty() || w <= 0 || h <= 0) {
609+ return false;
610+ }
611+ return (contains(x, y) &&
612+ contains(x + w, y) &&
613+ contains(x, y + h) &&
614+ contains(x + w, y + h));
615+ }
616+
617+ /**
618+ * Returns an iteration object that defines the boundary of this
619+ * <code>RoundRectangle2D</code>.
620+ * The iterator for this class is multi-threaded safe, which means
621+ * that this <code>RoundRectangle2D</code> class guarantees that
622+ * modifications to the geometry of this <code>RoundRectangle2D</code>
623+ * object do not affect any iterations of that geometry that
624+ * are already in process.
625+ * @param at an optional <code>AffineTransform</code> to be applied to
626+ * the coordinates as they are returned in the iteration, or
627+ * <code>null</code> if untransformed coordinates are desired
628+ * @return the <code>PathIterator</code> object that returns the
629+ * geometry of the outline of this
630+ * <code>RoundRectangle2D</code>, one segment at a time.
631+ * @since 1.2
632+ */
633+ public PathIterator getPathIterator(AffineTransform at) {
634+ return new RoundRectIterator(this, at);
635+ }
636+
637+ /**
638+ * Returns the hashcode for this <code>RoundRectangle2D</code>.
639+ * @return the hashcode for this <code>RoundRectangle2D</code>.
640+ * @since 1.6
641+ */
642+ public int hashCode() {
643+ long bits = java.lang.Double.doubleToLongBits(getX());
644+ bits += java.lang.Double.doubleToLongBits(getY()) * 37;
645+ bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
646+ bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
647+ bits += java.lang.Double.doubleToLongBits(getArcWidth()) * 53;
648+ bits += java.lang.Double.doubleToLongBits(getArcHeight()) * 59;
649+ return (((int) bits) ^ ((int) (bits >> 32)));
650+ }
651+
652+ /**
653+ * Determines whether or not the specified <code>Object</code> is
654+ * equal to this <code>RoundRectangle2D</code>. The specified
655+ * <code>Object</code> is equal to this <code>RoundRectangle2D</code>
656+ * if it is an instance of <code>RoundRectangle2D</code> and if its
657+ * location, size, and corner arc dimensions are the same as this
658+ * <code>RoundRectangle2D</code>.
659+ * @param obj an <code>Object</code> to be compared with this
660+ * <code>RoundRectangle2D</code>.
661+ * @return <code>true</code> if <code>obj</code> is an instance
662+ * of <code>RoundRectangle2D</code> and has the same values;
663+ * <code>false</code> otherwise.
664+ * @since 1.6
665+ */
666+ public boolean equals(Object obj) {
667+ if (obj == this) {
668+ return true;
669+ }
670+ if (obj instanceof RoundRectangle2D) {
671+ RoundRectangle2D rr2d = (RoundRectangle2D) obj;
672+ return ((getX() == rr2d.getX()) &&
673+ (getY() == rr2d.getY()) &&
674+ (getWidth() == rr2d.getWidth()) &&
675+ (getHeight() == rr2d.getHeight()) &&
676+ (getArcWidth() == rr2d.getArcWidth()) &&
677+ (getArcHeight() == rr2d.getArcHeight()));
678+ }
679+ return false;
680+ }
681+}
java/pkg/java/awt/geom/mkfile+32−0
@@ -0,0 +1,32 @@
1+<../../../../../mkconfig
2+
3+TARG=\
4+ AffineTransform.dis\
5+ Arc2D.dis\
6+ ArcIterator.dis\
7+ Area.dis\
8+ CubicCurve2D.dis\
9+ CubicIterator.dis\
10+ Dimension2D.dis\
11+ Ellipse2D.dis\
12+ EllipseIterator.dis\
13+ FlatteningPathIterator.dis\
14+ GeneralPath.dis\
15+ IllegalPathStateException.dis\
16+ Line2D.dis\
17+ LineIterator.dis\
18+ NoninvertibleTransformException.dis\
19+ Path2D.dis\
20+ PathIterator.dis\
21+ Point2D.dis\
22+ QuadCurve2D.dis\
23+ QuadIterator.dis\
24+ Rectangle2D.dis\
25+ RectangularShape.dis\
26+ RectIterator.dis\
27+ RoundRectangle2D.dis\
28+ RoundRectIterator.dis\
29+
30+DISBIN=$ROOT/java/dis/java/java/java/awt/geom
31+
32+<$ROOT/mkfiles/mkjava
java/pkg/java/awt/geom/package.html+62−0
@@ -0,0 +1,62 @@
1+<!--
2+ Copyright (c) 1998, 1999, Oracle and/or its affiliates. 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. Oracle designates this
8+ particular file as subject to the "Classpath" exception as provided
9+ by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ or visit www.oracle.com if you need additional information or have any
23+ questions.
24+-->
25+
26+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
27+<html>
28+<body bgcolor="white">
29+
30+Provides the Java 2D classes for defining and performing operations
31+on objects related to two-dimensional geometry. Some important features
32+of the package include:
33+<ul>
34+<li>classes for manipulating geometry, such as AffineTransform and
35+the PathIterator interface which is implemented by all Shape objects.
36+
37+<li>classes that implement the Shape interface, such as
38+CubicCurve2D, Ellipse2D, Line2D, Rectangle2D, and GeneralShape.
39+
40+<li>the Area class which provides mechanisms for add (union), subtract,
41+intersect, and exclusiveOR operations on other Shape objects.
42+</ul>
43+
44+<!--
45+<h2>Package Specification</h2>
46+
47+##### FILL IN ANY SPECS NEEDED BY JAVA COMPATIBILITY KIT #####
48+<ul>
49+ <li><a href="">##### REFER TO ANY FRAMEMAKER SPECIFICATION HERE #####</a>
50+</ul>
51+
52+<h2>Related Documentation</h2>
53+
54+For overviews, tutorials, examples, guides, and tool documentation, please see:
55+<ul>
56+ <li><a href="">##### REFER TO NON-SPEC DOCUMENTATION HERE #####</a>
57+</ul>
58+-->
59+
60+@since 1.2
61+</body>
62+</html>