最近项目需要解析svg中的path.直线和贝塞尔曲线都好办,唯独arc不太好办.
svg中的arc是由弧上两点,角度确定的,而java中的arc是由弧的外接矩形和角度决定的.
所有中间需要一个转换工作.
好吧,我自己是转化不来的,apache的batik提供了全套的svg解析,它肯定转化过来了.于是去拔它的算法.
中间辛苦不用说,找到了相关的计算类.
仿照PathIterator做一个遍历接口
- import java.awt.geom.PathIterator;
- /**
- * The <code>ExtendedPathIterator</code> class represents a geometric
- * path constructed from straight lines, quadratic and cubic (Bezier)
- * curves and elliptical arcs. This interface is identical to that of
- * PathIterator except it can return SEG_ARCTO from currentSegment,
- * also the array of values passed to currentSegment must be of length
- * 7 or an error will be thrown.
- *
- * This does not extend PathIterator as it would break the interface
- * contract for that class.
- *
- * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
- * @version $Id: ExtendedPathIterator.java,v 1.1 2011/05/27 03:01:11 zhengll Exp $
- */
- public interface ExtendedPathIterator {
- /**
- * The segment type constant that specifies that the preceding
- * subpath should be closed by appending a line segment back to
- * the point corresponding to the most recent SEG_MOVETO.
- */
- int SEG_CLOSE = PathIterator.SEG_CLOSE;
- /**
- * The segment type constant for a point that specifies the end
- * point of a line to be drawn from the most recently specified
- * point. */
- int SEG_MOVETO = PathIterator.SEG_MOVETO;
- /**
- * The segment type constant for a point that specifies the end
- * point of a line to be drawn from the most recently specified
- * point.
- */
- int SEG_LINETO = PathIterator.SEG_LINETO;
- /**
- * The segment type constant for the pair of points that specify a
- * quadratic parametric curve to be drawn from the most recently
- * specified point. The curve is interpolated by solving the
- * parametric control equation in the range (t=[0..1]) using the
- * most recently specified (current) point (CP), the first control
- * point (P1), and the final interpolated control point (P2).
- */
- int SEG_QUADTO = PathIterator.SEG_QUADTO;
- /**
- * The segment type constant for the set of 3 points that specify
- * a cubic parametric curve to be drawn from the most recently
- * specified point. The curve is interpolated by solving the
- * parametric control equation in the range (t=[0..1]) using the
- * most recently specified (current) point (CP), the first control
- * point (P1), the second control point (P2), and the final
- * interpolated control point (P3).
- */
- int SEG_CUBICTO = PathIterator.SEG_CUBICTO;
- /** The segment type constant for an elliptical arc. This consists of
- * Seven values [rx, ry, angle, largeArcFlag, sweepFlag, x, y].
- * rx, ry are the radious of the ellipse.
- * angle is angle of the x axis of the ellipse.
- * largeArcFlag is zero if the smaller of the two arcs are to be used.
- * sweepFlag is zero if the 'left' branch is taken one otherwise.
- * x and y are the destination for the ellipse. */
- int SEG_ARCTO = 4321;
- /** The winding rule constant for specifying an even-odd rule for
- * determining the interior of a path. The even-odd rule specifies
- * that a point lies inside the path if a ray drawn in any
- * direction from that point to infinity is crossed by path
- * segments an odd number of times.
- */
- int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
- /**
- * The winding rule constant for specifying a non-zero rule for
- * determining the interior of a path. The non-zero rule specifies
- * that a point lies inside the path if a ray drawn in any
- * direction from that point to infinity is crossed by path
- * segments a different number of times in the counter-clockwise
- * direction than the clockwise direction.
- */
- int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
- int currentSegment();
- int currentSegment(double[] coords);
- int currentSegment(float[] coords);
- int getWindingRule();
- boolean isDone();
- void next();
- }
再做一个保存信息的中间集合图形
- import java.awt.Shape;
- /**
- * The <code>ExtendedShape</code> class represents a geometric
- * path constructed from straight lines, quadratic and cubic (Bezier)
- * curves and elliptical arcs.
- * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
- * @version $Id: ExtendedShape.java,v 1.1 2011/05/27 03:01:11 zhengll Exp $
- */
- public interface ExtendedShape extends Shape {
- /**
- * Get an extended Path iterator that may return SEG_ARCTO commands
- */
- ExtendedPathIterator getExtendedPathIterator();
- }
重头戏来了,计算逻辑
- import java.awt.Shape;
- import java.awt.Rectangle;
- import java.awt.geom.AffineTransform;
- import java.awt.geom.Arc2D;
- import java.awt.geom.GeneralPath;
- import java.awt.geom.PathIterator;
- import java.awt.geom.Point2D;
- import java.awt.geom.Rectangle2D;
- import java.util.Arrays;
- /**
- * The <code>ExtendedGeneralPath</code> class represents a geometric
- * path constructed from straight lines, quadratic and cubic (Bezier)
- * curves and elliptical arc. This class delegates lines and curves to
- * an enclosed <code>GeneralPath</code>. Elliptical arc is implemented
- * using an <code>Arc2D</code> in float precision.
- *
- * <p><b>Warning</b> : An elliptical arc may be composed of several
- * path segments. For futher details, see the SVG Appendix F.6
- *
- * @author <a href="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a>
- * @version $Id: ExtendedGeneralPath.java,v 1.1 2011/05/27 03:01:11 zhengll Exp $
- */
- public class ExtendedGeneralPath implements ExtendedShape, Cloneable {
- /** The enclosed general path. */
- protected GeneralPath path;
- int numVals = 0;
- int numSeg = 0;
- float [] values = null;
- int [] types = null;
- float mx, my, cx, cy;
- /**
- * Constructs a new <code>ExtendedGeneralPath</code>.
- */
- public ExtendedGeneralPath() {
- path = new GeneralPath();
- }
- /**
- * Constructs a new <code>ExtendedGeneralPath</code> with the
- * specified winding rule to control operations that require the
- * interior of the path to be defined.
- */
- public ExtendedGeneralPath(int rule) {
- path = new GeneralPath(rule);
- }
- /**
- * Constructs a new <code>ExtendedGeneralPath</code> object with
- * the specified winding rule and the specified initial capacity
- * to store path coordinates.
- */
- public ExtendedGeneralPath(int rule, int initialCapacity) {
- path = new GeneralPath(rule, initialCapacity);
- }
- /**
- * Constructs a new <code>ExtendedGeneralPath</code> object from
- * an arbitrary <code>Shape</code> object.
- */
- public ExtendedGeneralPath(Shape s) {
- this();
- append(s, false);
- }
- /**
- * Adds an elliptical arc, defined by two radii, an angle from the
- * x-axis, a flag to choose the large arc or not, a flag to
- * indicate if we increase or decrease the angles and the final
- * point of the arc.
- *
- * @param rx the x radius of the ellipse
- * @param ry the y radius of the ellipse
- *
- * @param angle the angle from the x-axis of the current
- * coordinate system to the x-axis of the ellipse in degrees.
- *
- * @param largeArcFlag the large arc flag. If true the arc
- * spanning less than or equal to 180 degrees is chosen, otherwise
- * the arc spanning greater than 180 degrees is chosen
- *
- * @param sweepFlag the sweep flag. If true the line joining
- * center to arc sweeps through decreasing angles otherwise it
- * sweeps through increasing angles
- *
- * @param x the absolute x coordinate of the final point of the arc.
- * @param y the absolute y coordinate of the final point of the arc.
- */
- public synchronized void arcTo(float rx, float ry,
- float angle,
- boolean largeArcFlag,
- boolean sweepFlag,
- float x, float y) {
- // Ensure radii are valid
- if (rx == 0 || ry == 0) {
- lineTo(x, y);
- return;
- }
- checkMoveTo(); // check if prev command was moveto
- // Get the current (x, y) coordinates of the path
- double x0 = cx;
- double y0 = cy;
- if (x0 == x && y0 == y) {
- // If the endpoints (x, y) and (x0, y0) are identical, then this
- // is equivalent to omitting the elliptical arc segment entirely.
- return;
- }
- Arc2D arc = computeArc(x0, y0, rx, ry, angle,
- largeArcFlag, sweepFlag, x, y);
- if (arc == null) return;
- AffineTransform t = AffineTransform.getRotateInstance
- (Math.toRadians(angle), arc.getCenterX(), arc.getCenterY());
- Shape s = t.createTransformedShape(arc);
- path.append(s, true);
- makeRoom(7);
- types [numSeg++] = ExtendedPathIterator.SEG_ARCTO;
- values[numVals++] = rx;
- values[numVals++] = ry;
- values[numVals++] = angle;
- values[numVals++] = largeArcFlag?1:0;
- values[numVals++] = sweepFlag?1:0;
- cx = values[numVals++] = x;
- cy = values[numVals++] = y;
- }
- /**
- * This constructs an unrotated Arc2D from the SVG specification of an
- * Elliptical arc. To get the final arc you need to apply a rotation
- * transform such as:
- *
- * AffineTransform.getRotateInstance
- * (angle, arc.getX()+arc.getWidth()/2, arc.getY()+arc.getHeight()/2);
- */
- public static Arc2D computeArc(double x0, double y0,
- double rx, double ry,
- double angle,
- boolean largeArcFlag,
- boolean sweepFlag,
- double x, double y) {
- //
- // Elliptical arc implementation based on the SVG specification notes
- //
- // Compute the half distance between the current and the final point
- double dx2 = (x0 - x) / 2.0;
- double dy2 = (y0 - y) / 2.0;
- // Convert angle from degrees to radians
- angle = Math.toRadians(angle % 360.0);
- double cosAngle = Math.cos(angle);
- double sinAngle = Math.sin(angle);
- //
- // Step 1 : Compute (x1, y1)
- //
- double x1 = (cosAngle * dx2 + sinAngle * dy2);
- double y1 = (-sinAngle * dx2 + cosAngle * dy2);
- // Ensure radii are large enough
- rx = Math.abs(rx);
- ry = Math.abs(ry);
- double Prx = rx * rx;
- double Pry = ry * ry;
- double Px1 = x1 * x1;
- double Py1 = y1 * y1;
- // check that radii are large enough
- double radiiCheck = Px1/Prx + Py1/Pry;
- if (radiiCheck > 1) {
- rx = Math.sqrt(radiiCheck) * rx;
- ry = Math.sqrt(radiiCheck) * ry;
- Prx = rx * rx;
- Pry = ry * ry;
- }
- //
- // Step 2 : Compute (cx1, cy1)
- //
- double sign = (largeArcFlag == sweepFlag) ? -1 : 1;
- double sq = ((Prx*Pry)-(Prx*Py1)-(Pry*Px1)) / ((Prx*Py1)+(Pry*Px1));
- sq = (sq < 0) ? 0 : sq;
- double coef = (sign * Math.sqrt(sq));
- double cx1 = coef * ((rx * y1) / ry);
- double cy1 = coef * -((ry * x1) / rx);
- //
- // Step 3 : Compute (cx, cy) from (cx1, cy1)
- //
- double sx2 = (x0 + x) / 2.0;
- double sy2 = (y0 + y) / 2.0;
- double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);
- double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);
- //
- // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)
- //
- double ux = (x1 - cx1) / rx;
- double uy = (y1 - cy1) / ry;
- double vx = (-x1 - cx1) / rx;
- double vy = (-y1 - cy1) / ry;
- double p, n;
- // Compute the angle start
- n = Math.sqrt((ux * ux) + (uy * uy));
- p = ux; // (1 * ux) + (0 * uy)
- sign = (uy < 0) ? -1.0 : 1.0;
- double angleStart = Math.toDegrees(sign * Math.acos(p / n));
- // Compute the angle extent
- n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
- p = ux * vx + uy * vy;
- sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;
- double angleExtent = Math.toDegrees(sign * Math.acos(p / n));
- if(!sweepFlag && angleExtent > 0) {
- angleExtent -= 360f;
- } else if (sweepFlag && angleExtent < 0) {
- angleExtent += 360f;
- }
- angleExtent %= 360f;
- angleStart %= 360f;
- //
- // We can now build the resulting Arc2D in double precision
- //
- Arc2D.Double arc = new Arc2D.Double();
- arc.x = cx - rx;
- arc.y = cy - ry;
- arc.width = rx * 2.0;
- arc.height = ry * 2.0;
- arc.start = -angleStart;
- arc.extent = -angleExtent;
- return arc;
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized void moveTo(float x, float y) {
- // Don't add moveto to general path unless there is a reason.
- makeRoom(2);
- types [numSeg++] = PathIterator.SEG_MOVETO;
- cx = mx = values[numVals++] = x;
- cy = my = values[numVals++] = y;
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized void lineTo(float x, float y) {
- checkMoveTo(); // check if prev command was moveto
- path.lineTo(x, y);
- makeRoom(2);
- types [numSeg++] = PathIterator.SEG_LINETO;
- cx = values[numVals++] = x;
- cy = values[numVals++] = y;
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized void quadTo(float x1, float y1, float x2, float y2) {
- checkMoveTo(); // check if prev command was moveto
- path.quadTo(x1, y1, x2, y2);
- makeRoom(4);
- types [numSeg++] = PathIterator.SEG_QUADTO;
- values[numVals++] = x1;
- values[numVals++] = y1;
- cx = values[numVals++] = x2;
- cy = values[numVals++] = y2;
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized void curveTo(float x1, float y1,
- float x2, float y2,
- float x3, float y3) {
- checkMoveTo(); // check if prev command was moveto
- path.curveTo(x1, y1, x2, y2, x3, y3);
- makeRoom(6);
- types [numSeg++] = PathIterator.SEG_CUBICTO;
- values[numVals++] = x1;
- values[numVals++] = y1;
- values[numVals++] = x2;
- values[numVals++] = y2;
- cx = values[numVals++] = x3;
- cy = values[numVals++] = y3;
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized void closePath() {
- // Don't double close path.
- if ((numSeg != 0) && (types[numSeg-1] == PathIterator.SEG_CLOSE))
- return;
- // Only close path if the previous command wasn't a moveto
- if ((numSeg != 0) && (types[numSeg-1] != PathIterator.SEG_MOVETO))
- path.closePath();
- makeRoom(0);
- types [numSeg++] = PathIterator.SEG_CLOSE;
- cx = mx;
- cy = my;
- }
- /**
- * Checks if previous command was a moveto command,
- * skipping a close command (if present).
- */
- protected void checkMoveTo() {
- if (numSeg == 0) return;
- switch(types[numSeg-1]) {
- case PathIterator.SEG_MOVETO:
- path.moveTo(values[numVals-2], values[numVals-1]);
- break;
- case PathIterator.SEG_CLOSE:
- if (numSeg == 1) return;
- if (types[numSeg-2] == PathIterator.SEG_MOVETO)
- path.moveTo(values[numVals-2], values[numVals-1]);
- break;
- default:
- break;
- }
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public void append(Shape s, boolean connect) {
- append(s.getPathIterator(new AffineTransform()), connect);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public void append(PathIterator pi, boolean connect) {
- double [] vals = new double[6];
- while (!pi.isDone()) {
- Arrays.fill( vals, 0 );
- int type = pi.currentSegment(vals);
- pi.next();
- if (connect && (numVals != 0)) {
- if (type == PathIterator.SEG_MOVETO) {
- double x = vals[0];
- double y = vals[1];
- if ((x != cx) ||
- (y != cy)) {
- // Change MOVETO to LINETO.
- type = PathIterator.SEG_LINETO;
- } else {
- // Redundent segment (move to current loc) drop it...
- if (pi.isDone()) break; // Nothing interesting
- type = pi.currentSegment(vals);
- pi.next();
- }
- }
- connect = false;
- }
- switch(type) {
- case PathIterator.SEG_CLOSE: closePath(); break;
- case PathIterator.SEG_MOVETO:
- moveTo ((float)vals[0], (float)vals[1]); break;
- case PathIterator.SEG_LINETO:
- lineTo ((float)vals[0], (float)vals[1]); break;
- case PathIterator.SEG_QUADTO:
- quadTo ((float)vals[0], (float)vals[1],
- (float)vals[2], (float)vals[3]); break;
- case PathIterator.SEG_CUBICTO:
- curveTo((float)vals[0], (float)vals[1],
- (float)vals[2], (float)vals[3],
- (float)vals[4], (float)vals[5]); break;
- }
- }
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public void append(ExtendedPathIterator epi, boolean connect) {
- float[] vals = new float[ 7 ];
- while (!epi.isDone()) {
- Arrays.fill( vals, 0 );
- int type = epi.currentSegment(vals);
- epi.next();
- if (connect && (numVals != 0)) {
- if (type == PathIterator.SEG_MOVETO) {
- float x = vals[0];
- float y = vals[1];
- if ((x != cx) ||
- (y != cy)) {
- // Change MOVETO to LINETO.
- type = PathIterator.SEG_LINETO;
- } else {
- // Redundant segment (move to current loc) drop it...
- if (epi.isDone()) break; // Nothing interesting
- type = epi.currentSegment(vals);
- epi.next();
- }
- }
- connect = false;
- }
- switch(type) {
- case PathIterator.SEG_CLOSE: closePath(); break;
- case PathIterator.SEG_MOVETO:
- moveTo (vals[0], vals[1]); break;
- case PathIterator.SEG_LINETO:
- lineTo (vals[0], vals[1]); break;
- case PathIterator.SEG_QUADTO:
- quadTo (vals[0], vals[1],
- vals[2], vals[3]); break;
- case PathIterator.SEG_CUBICTO:
- curveTo(vals[0], vals[1],
- vals[2], vals[3],
- vals[4], vals[5]); break;
- case ExtendedPathIterator.SEG_ARCTO:
- arcTo (vals[0], vals[1], vals[2],
- (vals[3]!=0), (vals[4]!=0),
- vals[5], vals[6]); break;
- }
- }
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized int getWindingRule() {
- return path.getWindingRule();
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public void setWindingRule(int rule) {
- path.setWindingRule(rule);
- }
- /**
- * get the current position or <code>null</code>.
- */
- public synchronized Point2D getCurrentPoint() {
- if (numVals == 0) return null;
- return new Point2D.Double(cx, cy);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized void reset() {
- path.reset();
- numSeg = 0;
- numVals = 0;
- values = null;
- types = null;
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public void transform(AffineTransform at) {
- if (at.getType() != AffineTransform.TYPE_IDENTITY)
- throw new IllegalArgumentException
- ("ExtendedGeneralPaths can not be transformed");
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized Shape createTransformedShape(AffineTransform at) {
- return path.createTransformedShape(at);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized Rectangle getBounds() {
- return path.getBounds();
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public synchronized Rectangle2D getBounds2D() {
- return path.getBounds2D();
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public boolean contains(double x, double y) {
- return path.contains(x, y);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public boolean contains(Point2D p) {
- return path.contains(p);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public boolean contains(double x, double y, double w, double h) {
- return path.contains(x, y, w, h);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public boolean contains(Rectangle2D r) {
- return path.contains(r);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public boolean intersects(double x, double y, double w, double h) {
- return path.intersects(x, y, w, h);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public boolean intersects(Rectangle2D r) {
- return path.intersects(r);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public PathIterator getPathIterator(AffineTransform at) {
- return path.getPathIterator(at);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public PathIterator getPathIterator(AffineTransform at, double flatness) {
- return path.getPathIterator(at, flatness);
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public ExtendedPathIterator getExtendedPathIterator() {
- return new EPI();
- }
- class EPI implements ExtendedPathIterator {
- int segNum = 0;
- int valsIdx = 0;
- public int currentSegment() {
- return types[segNum];
- }
- public int currentSegment(double[] coords) {
- int ret = types[segNum];
- switch (ret) {
- case SEG_CLOSE: break;
- case SEG_MOVETO:
- case SEG_LINETO:
- coords[0] = values[valsIdx];
- coords[1] = values[valsIdx+1];
- break;
- case SEG_QUADTO:
- coords[0] = values[valsIdx];
- coords[1] = values[valsIdx+1];
- coords[2] = values[valsIdx+2];
- coords[3] = values[valsIdx+3];
- break;
- case SEG_CUBICTO:
- coords[0] = values[valsIdx];
- coords[1] = values[valsIdx+1];
- coords[2] = values[valsIdx+2];
- coords[3] = values[valsIdx+3];
- coords[4] = values[valsIdx+4];
- coords[5] = values[valsIdx+5];
- break;
- case SEG_ARCTO:
- coords[0] = values[valsIdx];
- coords[1] = values[valsIdx+1];
- coords[2] = values[valsIdx+2];
- coords[3] = values[valsIdx+3];
- coords[4] = values[valsIdx+4];
- coords[5] = values[valsIdx+5];
- coords[6] = values[valsIdx+6];
- break;
- }
- // System.out.println("Seg: [" + segNum + "] type: " + ret +
- // " vals: [" + coords[0] + ", " + coords[1] +
- // "]");
- return ret;
- }
- public int currentSegment(float[] coords) {
- int ret = types[segNum];
- switch (ret) {
- case SEG_CLOSE: break;
- case SEG_MOVETO:
- case SEG_LINETO:
- coords[0] = values[valsIdx];
- coords[1] = values[valsIdx+1];
- break;
- case SEG_QUADTO:
- System.arraycopy( values, valsIdx, coords, 0, 4 );
- break;
- case SEG_CUBICTO:
- System.arraycopy( values, valsIdx, coords, 0, 6 );
- break;
- case SEG_ARCTO:
- System.arraycopy( values, valsIdx, coords, 0, 7 );
- break;
- }
- return ret;
- }
- public int getWindingRule() {
- return path.getWindingRule();
- }
- public boolean isDone() {
- return segNum == numSeg;
- }
- public void next() {
- int type = types[segNum++];
- switch (type) {
- case SEG_CLOSE: break;
- case SEG_MOVETO: // fallthrough is intended
- case SEG_LINETO: valsIdx+=2; break;
- case SEG_QUADTO: valsIdx+=4; break;
- case SEG_CUBICTO:valsIdx+=6; break;
- case SEG_ARCTO: valsIdx+=7; break;
- }
- }
- }
- /**
- * Delegates to the enclosed <code>GeneralPath</code>.
- */
- public Object clone() {
- try {
- ExtendedGeneralPath result = (ExtendedGeneralPath) super.clone();
- result.path = (GeneralPath) path.clone();
- if ( values != null ){
- result.values = new float[values.length];
- System.arraycopy(values, 0, result.values, 0, values.length);
- }
- result.numVals = numVals;
- if ( types != null ){
- result.types = new int[types.length];
- System.arraycopy(types, 0, result.types, 0, types.length);
- }
- result.numSeg = numSeg;
- return result;
- } catch (CloneNotSupportedException ex) {}
- return null;
- }
- /**
- * Make sure, that the requested number of slots in vales[] are available.
- * Must be called even for numValues = 0, because it is also
- * used for initialization of those arrays.
- *
- * @param numValues number of requested coordinates
- */
- private void makeRoom(int numValues) {
- if (values == null) {
- values = new float[2*numValues];
- types = new int[2];
- numVals = 0;
- numSeg = 0;
- return;
- }
- int newSize = numVals + numValues;
- if ( newSize > values.length) {
- int nlen = values.length*2;
- if ( nlen < newSize )
- nlen = newSize;
- float [] nvals = new float[nlen];
- System.arraycopy(values, 0, nvals, 0, numVals);
- values = nvals;
- }
- if (numSeg == types.length) {
- int [] ntypes = new int[types.length*2];
- System.arraycopy(types, 0, ntypes, 0, types.length);
- types = ntypes;
- }
- }
- }