2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / java / awt / geom / GeneralPath.java
blob05d98c762388df605fac7e074325331a7f63b1fa
1 /* GeneralPath.java -- represents a shape built from subpaths
2 Copyright (C) 2002, 2003 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.awt.geom;
41 import java.awt.Rectangle;
42 import java.awt.Shape;
44 /**
45 * STUBS ONLY
46 * XXX Implement and document. Note that Sun's implementation only expects
47 * float precision, not double.
49 public final class GeneralPath implements Shape, Cloneable
51 public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
52 public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
54 /** Initial size if not specified. */
55 private static final int INIT_SIZE = 20;
57 /** The winding rule. */
58 private int rule;
59 /**
60 * The path type in points. Note that points[index] maps to
61 * types[index >> 1]; the control points of quad and cubic paths map as
62 * well but are ignored.
64 private byte[] types;
65 /**
66 * The list of all points seen. Since you can only append floats, it makes
67 * sense for this to be a float[]. I have no idea why Sun didn't choose to
68 * allow a general path of double precision points.
70 private float[] points;
71 /** The index of the most recent moveto point, or null. */
72 private int subpath = -1;
73 /** The next available index into points. */
74 private int index;
76 public GeneralPath()
78 this(WIND_NON_ZERO, INIT_SIZE);
80 public GeneralPath(int rule)
82 this(rule, INIT_SIZE);
84 public GeneralPath(int rule, int capacity)
86 if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO)
87 throw new IllegalArgumentException();
88 this.rule = rule;
89 if (capacity < INIT_SIZE)
90 capacity = INIT_SIZE;
91 types = new byte[capacity >> 1];
92 points = new float[capacity];
94 public GeneralPath(Shape s)
96 types = new byte[INIT_SIZE >> 1];
97 points = new float[INIT_SIZE];
98 PathIterator pi = s.getPathIterator(null);
99 setWindingRule(pi.getWindingRule());
100 append(pi, false);
103 public void moveTo(float x, float y)
105 subpath = index;
106 ensureSize(index + 2);
107 types[index >> 1] = PathIterator.SEG_MOVETO;
108 points[index++] = x;
109 points[index++] = y;
111 public void lineTo(float x, float y)
113 ensureSize(index + 2);
114 types[index >> 1] = PathIterator.SEG_LINETO;
115 points[index++] = x;
116 points[index++] = y;
118 public void quadTo(float x1, float y1, float x2, float y2)
120 ensureSize(index + 4);
121 types[index >> 1] = PathIterator.SEG_QUADTO;
122 points[index++] = x1;
123 points[index++] = y1;
124 points[index++] = x2;
125 points[index++] = y2;
127 public void curveTo(float x1, float y1, float x2, float y2,
128 float x3, float y3)
130 ensureSize(index + 6);
131 types[index >> 1] = PathIterator.SEG_CUBICTO;
132 points[index++] = x1;
133 points[index++] = y1;
134 points[index++] = x2;
135 points[index++] = y2;
136 points[index++] = x3;
137 points[index++] = y3;
139 public void closePath()
141 ensureSize(index + 2);
142 types[index >> 1] = PathIterator.SEG_CLOSE;
143 points[index++] = points[subpath];
144 points[index++] = points[subpath + 1];
147 public void append(Shape s, boolean connect)
149 append(s.getPathIterator(null), connect);
154 * Appends the segments of a PathIterator to this GeneralPath.
155 * Optionally, the initial {@link PathIterator#SEG_MOVETO} segment
156 * of the appended path is changed into a {@link
157 * PathIterator#SEG_LINETO} segment.
159 * @param iter the PathIterator specifying which segments shall be
160 * appended.
162 * @param connect <code>true</code> for substituting the initial
163 * {@link PathIterator#SEG_MOVETO} segment by a {@link
164 * PathIterator#SEG_LINETO}, or <code>false</code> for not
165 * performing any substitution. If this GeneralPath is currently
166 * empty, <code>connect</code> is assumed to be <code>false</code>,
167 * thus leaving the initial {@link PathIterator#SEG_MOVETO}
168 * unchanged.
170 public void append(PathIterator iter, boolean connect)
172 // A bad implementation of this method had caused Classpath bug #6076.
173 float[] f = new float[6];
174 while (!iter.isDone())
176 switch (iter.currentSegment(f))
178 case PathIterator.SEG_MOVETO:
179 if (!connect || (index == 0))
181 moveTo(f[0], f[1]);
182 break;
185 if ((index >= 2) && (types[(index - 2) >> 2] == PathIterator.SEG_CLOSE)
186 && (f[0] == points[index - 2]) && (f[1] == points[index - 1]))
187 break;
189 // Fall through.
191 case PathIterator.SEG_LINETO:
192 lineTo(f[0], f[1]);
193 break;
195 case PathIterator.SEG_QUADTO:
196 quadTo(f[0], f[1], f[2], f[3]);
197 break;
199 case PathIterator.SEG_CUBICTO:
200 curveTo(f[0], f[1], f[2], f[3], f[4], f[5]);
201 break;
203 case PathIterator.SEG_CLOSE:
204 closePath();
205 break;
208 connect = false;
209 iter.next();
214 public int getWindingRule()
216 return rule;
218 public void setWindingRule(int rule)
220 if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO)
221 throw new IllegalArgumentException();
222 this.rule = rule;
225 public Point2D getCurrentPoint()
227 if (subpath < 0)
228 return null;
229 return new Point2D.Float(points[index - 2], points[index - 1]);
231 public void reset()
233 subpath = -1;
234 index = 0;
237 public void transform(AffineTransform xform)
239 xform.transform(points, 0, points, 0, index >> 1);
241 public Shape createTransformedShape(AffineTransform xform)
243 GeneralPath p = new GeneralPath(this);
244 p.transform(xform);
245 return p;
248 public Rectangle getBounds()
250 return getBounds2D().getBounds();
252 public Rectangle2D getBounds2D()
254 // XXX Implement.
255 throw new Error("not implemented");
258 public boolean contains(double x, double y)
260 // XXX Implement.
261 throw new Error("not implemented");
263 public boolean contains(Point2D p)
265 return contains(p.getX(), p.getY());
267 public boolean contains(double x, double y, double w, double h)
269 // XXX Implement.
270 throw new Error("not implemented");
272 public boolean contains(Rectangle2D r)
274 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
277 public boolean intersects(double x, double y, double w, double h)
279 // XXX Implement.
280 throw new Error("not implemented");
282 public boolean intersects(Rectangle2D r)
284 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
289 * A PathIterator that iterates over the segments of a GeneralPath.
291 * @author Sascha Brawer (brawer@dandelis.ch)
293 private static class GeneralPathIterator
294 implements PathIterator
297 * The number of coordinate values for each segment type.
299 private static final int[] NUM_COORDS =
301 /* 0: SEG_MOVETO */ 2,
302 /* 1: SEG_LINETO */ 2,
303 /* 2: SEG_QUADTO */ 4,
304 /* 3: SEG_CUBICTO */ 6,
305 /* 4: SEG_CLOSE */ 0
310 * The GeneralPath whose segments are being iterated.
312 private final GeneralPath path;
316 * The affine transformation used to transform coordinates.
318 private final AffineTransform transform;
322 * The current position of the iterator.
324 private int pos;
328 * Constructs a new iterator for enumerating the segments of a
329 * GeneralPath.
331 * @param at an affine transformation for projecting the returned
332 * points, or <code>null</code> to return the original points
333 * without any mapping.
335 GeneralPathIterator(GeneralPath path, AffineTransform transform)
337 this.path = path;
338 this.transform = transform;
343 * Returns the current winding rule of the GeneralPath.
345 public int getWindingRule()
347 return path.rule;
352 * Determines whether the iterator has reached the last segment in
353 * the path.
355 public boolean isDone()
357 return pos >= path.index;
362 * Advances the iterator position by one segment.
364 public void next()
366 int seg;
368 /* Increment pos by the number of coordinate values. Note that
369 * we store two values even for a SEG_CLOSE segment, which is
370 * why we increment pos at least by 2.
372 seg = path.types[pos >> 1];
373 if (seg == SEG_CLOSE)
374 pos += 2;
375 else
376 pos += NUM_COORDS[seg];
381 * Returns the current segment in float coordinates.
383 public int currentSegment(float[] coords)
385 int seg, numCoords;
387 seg = path.types[pos >> 1];
388 numCoords = NUM_COORDS[seg];
389 if (numCoords > 0)
391 if (transform == null)
392 System.arraycopy(path.points, pos, coords, 0, numCoords);
393 else
394 transform.transform(/* src */ path.points, /* srcOffset */ pos,
395 /* dest */ coords, /* destOffset */ 0,
396 /* numPoints */ numCoords >> 1);
398 return seg;
403 * Returns the current segment in double coordinates.
405 public int currentSegment(double[] coords)
407 int seg, numCoords;
409 seg = path.types[pos >> 1];
410 numCoords = NUM_COORDS[seg];
411 if (numCoords > 0)
413 if (transform == null)
415 // System.arraycopy throws an exception if the source and destination
416 // array are not of the same primitive type.
417 for (int i = 0; i < numCoords; i++)
418 coords[i] = (double) path.points[pos + i];
420 else
421 transform.transform(/* src */ path.points, /* srcOffset */ pos,
422 /* dest */ coords, /* destOffset */ 0,
423 /* numPoints */ numCoords >> 1);
425 return seg;
431 * Creates a PathIterator for iterating along the segments of this path.
433 * @param at an affine transformation for projecting the returned
434 * points, or <code>null</code> to let the created iterator return
435 * the original points without any mapping.
437 public PathIterator getPathIterator(AffineTransform at)
439 return new GeneralPathIterator(this, at);
443 public PathIterator getPathIterator(AffineTransform at, double flatness)
445 return new FlatteningPathIterator(getPathIterator(at), flatness);
449 * Create a new shape of the same run-time type with the same contents as
450 * this one.
452 * @return the clone
454 * @exception OutOfMemoryError If there is not enough memory available.
456 * @since 1.2
458 public Object clone()
460 // This class is final; no need to use super.clone().
461 return new GeneralPath(this);
464 private void ensureSize(int size)
466 if (subpath < 0)
467 throw new IllegalPathStateException("need initial moveto");
468 if (size <= points.length)
469 return;
470 byte[] b = new byte[points.length];
471 System.arraycopy(types, 0, b, 0, index >> 1);
472 types = b;
473 float[] f = new float[points.length << 1];
474 System.arraycopy(points, 0, f, 0, index);
475 points = f;
477 } // class GeneralPath