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
26package java.awt.geom;
27
28import java.awt.Shape;
29import 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 */
115public 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
26package java.awt.geom;
27
28import 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 */
56public 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import java.util.Vector;
31import java.util.Enumeration;
32import java.util.NoSuchElementException;
33import sun.awt.geom.Curve;
34import sun.awt.geom.Crossings;
35import 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 */
99public 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
659class 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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import java.util.Arrays;
31import java.io.Serializable;
32import sun.awt.geom.Curve;
33
34import static java.lang.Math.abs;
35import static java.lang.Math.max;
36import 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 */
50public 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package 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 */
40public 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
26package java.awt.geom;
27
28import 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 */
42public 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package java.awt.geom;
27
28import 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 */
38public 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
26package java.awt.geom;
27
28import 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 */
51public 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
26package 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
37public 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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import 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 */
49public 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package 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
35public 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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import sun.awt.geom.Curve;
31import java.io.Serializable;
32import java.io.StreamCorruptedException;
33import 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 */
70public 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
26package 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 */
60public 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
26package java.awt.geom;
27
28import 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 */
42public 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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import java.io.Serializable;
31import 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 */
45public 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package java.awt.geom;
27
28import 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 */
43public 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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import 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 */
45public 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
26package java.awt.geom;
27
28import 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 */
36class 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
26package java.awt.geom;
27
28import 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 */
44public 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
3TARG=\
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
30DISBIN=$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
30Provides the Java 2D classes for defining and performing operations
31on objects related to two-dimensional geometry. Some important features
32of the package include:
33<ul>
34<li>classes for manipulating geometry, such as AffineTransform and
35the PathIterator interface which is implemented by all Shape objects.
36
37<li>classes that implement the Shape interface, such as
38CubicCurve2D, Ellipse2D, Line2D, Rectangle2D, and GeneralShape.
39
40<li>the Area class which provides mechanisms for add (union), subtract,
41intersect, 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
54For 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>