diff options
Diffstat (limited to 'awt/java/awt/BasicStroke.java')
-rw-r--r-- | awt/java/awt/BasicStroke.java | 2443 |
1 files changed, 0 insertions, 2443 deletions
diff --git a/awt/java/awt/BasicStroke.java b/awt/java/awt/BasicStroke.java deleted file mode 100644 index 2457815..0000000 --- a/awt/java/awt/BasicStroke.java +++ /dev/null @@ -1,2443 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Denis M. Kishenko - * @version $Revision$ - */ - -package java.awt; - -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; - -import org.apache.harmony.awt.internal.nls.Messages; -import org.apache.harmony.misc.HashCode; - -/** - * The BasicStroke class specifies a set of rendering attributes for the - * outlines of graphics primitives. The BasicStroke attributes describe the - * shape of the pen which draws the outline of a Shape and the decorations - * applied at the ends and joins of path segments of the Shape. The BasicStroke - * has the following rendering attributes: - * <p> - * <ul> - * <li>line width -the pen width which draws the outlines.</li> - * <li>end caps - indicates the decoration applied to the ends of unclosed - * subpaths and dash segments. The BasicStroke defines three different - * decorations: CAP_BUTT, CAP_ROUND, and CAP_SQUARE.</li> - * <li>line joins - indicates the decoration applied at the intersection of two - * path segments and at the intersection of the endpoints of a subpath. The - * BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER, and - * JOIN_ROUND.</li> - * <li>miter limit - the limit to trim a line join that has a JOIN_MITER - * decoration.</li> - * <li>dash attributes - the definition of how to make a dash pattern by - * alternating between opaque and transparent sections</li> - * </ul> - * </p> - * - * @since Android 1.0 - */ -public class BasicStroke implements Stroke { - - /** - * The Constant CAP_BUTT indicates the ends of unclosed subpaths and dash - * segments have no added decoration. - */ - public static final int CAP_BUTT = 0; - - /** - * The Constant CAP_ROUND indicates the ends of unclosed subpaths and dash - * segments have a round decoration. - */ - public static final int CAP_ROUND = 1; - - /** - * The Constant CAP_SQUARE indicates the ends of unclosed subpaths and dash - * segments have a square projection. - */ - public static final int CAP_SQUARE = 2; - - /** - * The Constant JOIN_MITER indicates that path segments are joined by - * extending their outside edges until they meet. - */ - public static final int JOIN_MITER = 0; - - /** - * The Constant JOIN_ROUND indicates that path segments are joined by - * rounding off the corner at a radius of half the line width. - */ - public static final int JOIN_ROUND = 1; - - /** - * The Constant JOIN_BEVEL indicates that path segments are joined by - * connecting the outer corners of their wide outlines with a straight - * segment. - */ - public static final int JOIN_BEVEL = 2; - - /** - * Constants for calculating. - */ - static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision - - /** - * The Constant CURVE_DELTA. - */ - static final double CURVE_DELTA = 2.0; // Width tolerance - - /** - * The Constant CORNER_ANGLE. - */ - static final double CORNER_ANGLE = 4.0; // Minimum corner angle - - /** - * The Constant CORNER_ZERO. - */ - static final double CORNER_ZERO = 0.01; // Zero angle - - /** - * The Constant CUBIC_ARC. - */ - static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1); - - /** - * Stroke width. - */ - float width; - - /** - * Stroke cap type. - */ - int cap; - - /** - * Stroke join type. - */ - int join; - - /** - * Stroke miter limit. - */ - float miterLimit; - - /** - * Stroke dashes array. - */ - float dash[]; - - /** - * Stroke dash phase. - */ - float dashPhase; - - /** - * The temporary pre-calculated values. - */ - double curveDelta; - - /** - * The corner delta. - */ - double cornerDelta; - - /** - * The zero delta. - */ - double zeroDelta; - - /** - * The w2. - */ - double w2; - - /** - * The fmy. - */ - double fmx, fmy; - - /** - * The smy. - */ - double scx, scy, smx, smy; - - /** - * The cy. - */ - double mx, my, cx, cy; - - /** - * The temporary indicators. - */ - boolean isMove; - - /** - * The is first. - */ - boolean isFirst; - - /** - * The check move. - */ - boolean checkMove; - - /** - * The temporary and destination work paths. - */ - BufferedPath dst, lp, rp, sp; - - /** - * Stroke dasher class. - */ - Dasher dasher; - - /** - * Instantiates a new BasicStroke with default width, cap, join, limit, dash - * attributes parameters. The default parameters are a solid line of width - * 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes, - * and a dash phase of 0.0f. - */ - public BasicStroke() { - this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); - } - - /** - * Instantiates a new BasicStroke with the specified width, caps, joins, - * limit, dash attributes, dash phase parameters. - * - * @param width - * the width of BasikStroke. - * @param cap - * the end decoration of BasikStroke. - * @param join - * the join segments decoration. - * @param miterLimit - * the limit to trim the miter join. - * @param dash - * the array with the dashing pattern. - * @param dashPhase - * the offset to start the dashing pattern. - */ - public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, - float dashPhase) { - if (width < 0.0f) { - // awt.133=Negative width - throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$ - } - if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { - // awt.134=Illegal cap - throw new IllegalArgumentException(Messages.getString("awt.134")); //$NON-NLS-1$ - } - if (join != JOIN_MITER && join != JOIN_ROUND && join != JOIN_BEVEL) { - // awt.135=Illegal join - throw new IllegalArgumentException(Messages.getString("awt.135")); //$NON-NLS-1$ - } - if (join == JOIN_MITER && miterLimit < 1.0f) { - // awt.136=miterLimit less than 1.0f - throw new IllegalArgumentException(Messages.getString("awt.136")); //$NON-NLS-1$ - } - if (dash != null) { - if (dashPhase < 0.0f) { - // awt.137=Negative dashPhase - throw new IllegalArgumentException(Messages.getString("awt.137")); //$NON-NLS-1$ - } - if (dash.length == 0) { - // awt.138=Zero dash length - throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$ - } - ZERO: { - for (int i = 0; i < dash.length; i++) { - if (dash[i] < 0.0) { - // awt.139=Negative dash[{0}] - throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$ - } - if (dash[i] > 0.0) { - break ZERO; - } - } - // awt.13A=All dash lengths zero - throw new IllegalArgumentException(Messages.getString("awt.13A")); //$NON-NLS-1$ - } - } - this.width = width; - this.cap = cap; - this.join = join; - this.miterLimit = miterLimit; - this.dash = dash; - this.dashPhase = dashPhase; - } - - /** - * Instantiates a new BasicStroke with specified width, cap, join, limit and - * default dash attributes parameters. - * - * @param width - * the width of BasikStroke. - * @param cap - * the end decoration of BasikStroke. - * @param join - * the join segments decoration. - * @param miterLimit - * the limit to trim the miter join. - */ - public BasicStroke(float width, int cap, int join, float miterLimit) { - this(width, cap, join, miterLimit, null, 0.0f); - } - - /** - * Instantiates a new BasicStroke with specified width, cap, join and - * default limit and dash attributes parameters. - * - * @param width - * the width of BasikStroke. - * @param cap - * the end decoration of BasikStroke. - * @param join - * the join segments decoration. - */ - public BasicStroke(float width, int cap, int join) { - this(width, cap, join, 10.0f, null, 0.0f); - } - - /** - * Instantiates a new BasicStroke with specified width and default cap, - * join, limit, dash attributes parameters. - * - * @param width - * the width of BasicStroke. - */ - public BasicStroke(float width) { - this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); - } - - /** - * Gets the line width of the BasicStroke. - * - * @return the line width of the BasicStroke. - */ - public float getLineWidth() { - return width; - } - - /** - * Gets the end cap style of the BasicStroke. - * - * @return the end cap style of the BasicStroke. - */ - public int getEndCap() { - return cap; - } - - /** - * Gets the line join style of the BasicStroke. - * - * @return the line join style of the BasicStroke. - */ - public int getLineJoin() { - return join; - } - - /** - * Gets the miter limit of the BasicStroke (the limit to trim the miter - * join). - * - * @return the miter limit of the BasicStroke. - */ - public float getMiterLimit() { - return miterLimit; - } - - /** - * Gets the dash attributes array of the BasicStroke. - * - * @return the dash attributes array of the BasicStroke. - */ - public float[] getDashArray() { - return dash; - } - - /** - * Gets the dash phase of the BasicStroke. - * - * @return the dash phase of the BasicStroke. - */ - public float getDashPhase() { - return dashPhase; - } - - /** - * Returns hash code of this BasicStroke. - * - * @return the hash code of this BasicStroke. - */ - @Override - public int hashCode() { - HashCode hash = new HashCode(); - hash.append(width); - hash.append(cap); - hash.append(join); - hash.append(miterLimit); - if (dash != null) { - hash.append(dashPhase); - for (float element : dash) { - hash.append(element); - } - } - return hash.hashCode(); - } - - /** - * Compares this BasicStroke object with the specified Object. - * - * @param obj - * the Object to be compared. - * @return true, if the Object is a BasicStroke with the same data values as - * this BasicStroke; false otherwise. - */ - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (obj instanceof BasicStroke) { - BasicStroke bs = (BasicStroke)obj; - return bs.width == width && bs.cap == cap && bs.join == join - && bs.miterLimit == miterLimit && bs.dashPhase == dashPhase - && java.util.Arrays.equals(bs.dash, dash); - } - return false; - } - - /** - * Calculates allowable curve derivation. - * - * @param width - * the width. - * @return the curve delta. - */ - double getCurveDelta(double width) { - double a = width + CURVE_DELTA; - double cos = 1.0 - 2.0 * width * width / (a * a); - double sin = Math.sqrt(1.0 - cos * cos); - return Math.abs(sin / cos); - } - - /** - * Calculates the value to detect a small angle. - * - * @param width - * the width. - * @return the corner delta. - */ - double getCornerDelta(double width) { - return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0); - } - - /** - * Calculates value to detect a zero angle. - * - * @param width - * the width. - * @return the zero delta. - */ - double getZeroDelta(double width) { - return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0); - } - - /** - * Creates a Shape from the outline of the specified shape drawn with this - * BasicStroke. - * - * @param s - * the specified Shape to be stroked. - * @return the Shape of the stroked outline. - * @see java.awt.Stroke#createStrokedShape(java.awt.Shape) - */ - public Shape createStrokedShape(Shape s) { - w2 = width / 2.0; - curveDelta = getCurveDelta(w2); - cornerDelta = getCornerDelta(w2); - zeroDelta = getZeroDelta(w2); - - dst = new BufferedPath(); - lp = new BufferedPath(); - rp = new BufferedPath(); - - if (dash == null) { - createSolidShape(s.getPathIterator(null)); - } else { - createDashedShape(s.getPathIterator(null)); - } - - return dst.createGeneralPath(); - } - - /** - * Generates a shape with a solid (not dashed) outline. - * - * @param p - * the PathIterator of source shape. - */ - void createSolidShape(PathIterator p) { - double coords[] = new double[6]; - mx = my = cx = cy = 0.0; - isMove = false; - isFirst = false; - checkMove = true; - boolean isClosed = true; - - while (!p.isDone()) { - switch (p.currentSegment(coords)) { - case PathIterator.SEG_MOVETO: - if (!isClosed) { - closeSolidShape(); - } - rp.clean(); - mx = cx = coords[0]; - my = cy = coords[1]; - isMove = true; - isClosed = false; - break; - case PathIterator.SEG_LINETO: - addLine(cx, cy, cx = coords[0], cy = coords[1], true); - break; - case PathIterator.SEG_QUADTO: - addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); - break; - case PathIterator.SEG_CUBICTO: - addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], - cy = coords[5]); - break; - case PathIterator.SEG_CLOSE: - addLine(cx, cy, mx, my, false); - addJoin(lp, mx, my, lp.xMove, lp.yMove, true); - addJoin(rp, mx, my, rp.xMove, rp.yMove, false); - lp.closePath(); - rp.closePath(); - lp.appendReverse(rp); - isClosed = true; - break; - } - p.next(); - } - if (!isClosed) { - closeSolidShape(); - } - - dst = lp; - } - - /** - * Closes solid shape path. - */ - void closeSolidShape() { - addCap(lp, cx, cy, rp.xLast, rp.yLast); - lp.combine(rp); - addCap(lp, mx, my, lp.xMove, lp.yMove); - lp.closePath(); - } - - /** - * Generates dashed stroked shape. - * - * @param p - * the PathIterator of source shape. - */ - void createDashedShape(PathIterator p) { - double coords[] = new double[6]; - mx = my = cx = cy = 0.0; - smx = smy = scx = scy = 0.0; - isMove = false; - checkMove = false; - boolean isClosed = true; - - while (!p.isDone()) { - switch (p.currentSegment(coords)) { - case PathIterator.SEG_MOVETO: - - if (!isClosed) { - closeDashedShape(); - } - - dasher = new Dasher(dash, dashPhase); - lp.clean(); - rp.clean(); - sp = null; - isFirst = true; - isMove = true; - isClosed = false; - mx = cx = coords[0]; - my = cy = coords[1]; - break; - case PathIterator.SEG_LINETO: - addDashLine(cx, cy, cx = coords[0], cy = coords[1]); - break; - case PathIterator.SEG_QUADTO: - addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); - break; - case PathIterator.SEG_CUBICTO: - addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], - cx = coords[4], cy = coords[5]); - break; - case PathIterator.SEG_CLOSE: - addDashLine(cx, cy, cx = mx, cy = my); - - if (dasher.isConnected()) { - // Connect current and head segments - addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true); - lp.join(sp); - addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true); - lp.combine(rp); - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - dst.append(lp); - sp = null; - } else { - closeDashedShape(); - } - - isClosed = true; - break; - } - p.next(); - } - - if (!isClosed) { - closeDashedShape(); - } - - } - - /** - * Closes dashed shape path. - */ - void closeDashedShape() { - // Add head segment - if (sp != null) { - addCap(sp, fmx, fmy, sp.xMove, sp.yMove); - sp.closePath(); - dst.append(sp); - } - if (lp.typeSize > 0) { - // Close current segment - if (!dasher.isClosed()) { - addCap(lp, scx, scy, rp.xLast, rp.yLast); - lp.combine(rp); - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - dst.append(lp); - } - } - - /** - * Adds cap to the work path. - * - * @param p - * the BufferedPath object of work path. - * @param x0 - * the x coordinate of the source path. - * @param y0 - * the y coordinate on the source path. - * @param x2 - * the x coordinate of the next point on the work path. - * @param y2 - * the y coordinate of the next point on the work path. - */ - void addCap(BufferedPath p, double x0, double y0, double x2, double y2) { - double x1 = p.xLast; - double y1 = p.yLast; - double x10 = x1 - x0; - double y10 = y1 - y0; - double x20 = x2 - x0; - double y20 = y2 - y0; - - switch (cap) { - case CAP_BUTT: - p.lineTo(x2, y2); - break; - case CAP_ROUND: - double mx = x10 * CUBIC_ARC; - double my = y10 * CUBIC_ARC; - - double x3 = x0 + y10; - double y3 = y0 - x10; - - x10 *= CUBIC_ARC; - y10 *= CUBIC_ARC; - x20 *= CUBIC_ARC; - y20 *= CUBIC_ARC; - - p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3); - p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2); - break; - case CAP_SQUARE: - p.lineTo(x1 + y10, y1 - x10); - p.lineTo(x2 - y20, y2 + x20); - p.lineTo(x2, y2); - break; - } - } - - /** - * Adds bevel and miter join to the work path. - * - * @param p - * the BufferedPath object of work path. - * @param x0 - * the x coordinate of the source path. - * @param y0 - * the y coordinate on the source path. - * @param x2 - * the x coordinate of the next point on the work path. - * @param y2 - * the y coordinate of the next point on the work path. - * @param isLeft - * the orientation of work path, true if work path lies to the - * left from source path, false otherwise. - */ - void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { - double x1 = p.xLast; - double y1 = p.yLast; - double x10 = x1 - x0; - double y10 = y1 - y0; - double x20 = x2 - x0; - double y20 = y2 - y0; - double sin0 = x10 * y20 - y10 * x20; - - // Small corner - if (-cornerDelta < sin0 && sin0 < cornerDelta) { - double cos0 = x10 * x20 + y10 * y20; - if (cos0 > 0.0) { - // if zero corner do nothing - if (-zeroDelta > sin0 || sin0 > zeroDelta) { - double x3 = x0 + w2 * w2 * (y20 - y10) / sin0; - double y3 = y0 + w2 * w2 * (x10 - x20) / sin0; - p.setLast(x3, y3); - } - return; - } - // Zero corner - if (-zeroDelta < sin0 && sin0 < zeroDelta) { - p.lineTo(x2, y2); - } - return; - } - - if (isLeft ^ (sin0 < 0.0)) { - // Twisted corner - p.lineTo(x0, y0); - p.lineTo(x2, y2); - } else { - switch (join) { - case JOIN_BEVEL: - p.lineTo(x2, y2); - break; - case JOIN_MITER: - double s1 = x1 * x10 + y1 * y10; - double s2 = x2 * x20 + y2 * y20; - double x3 = (s1 * y20 - s2 * y10) / sin0; - double y3 = (s2 * x10 - s1 * x20) / sin0; - double x30 = x3 - x0; - double y30 = y3 - y0; - double miterLength = Math.sqrt(x30 * x30 + y30 * y30); - if (miterLength < miterLimit * w2) { - p.lineTo(x3, y3); - } - p.lineTo(x2, y2); - break; - case JOIN_ROUND: - addRoundJoin(p, x0, y0, x2, y2, isLeft); - break; - } - } - } - - /** - * Adds round join to the work path. - * - * @param p - * the BufferedPath object of work path. - * @param x0 - * the x coordinate of the source path. - * @param y0 - * the y coordinate on the source path. - * @param x2 - * the x coordinate of the next point on the work path. - * @param y2 - * the y coordinate of the next point on the work path. - * @param isLeft - * the orientation of work path, true if work path lies to the - * left from source path, false otherwise. - */ - void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { - double x1 = p.xLast; - double y1 = p.yLast; - double x10 = x1 - x0; - double y10 = y1 - y0; - double x20 = x2 - x0; - double y20 = y2 - y0; - - double x30 = x10 + x20; - double y30 = y10 + y20; - - double l30 = Math.sqrt(x30 * x30 + y30 * y30); - - if (l30 < 1E-5) { - p.lineTo(x2, y2); - return; - } - - double w = w2 / l30; - - x30 *= w; - y30 *= w; - - double x3 = x0 + x30; - double y3 = y0 + y30; - - double cos = x10 * x20 + y10 * y20; - double a = Math.acos(cos / (w2 * w2)); - if (cos >= 0.0) { - double k = 4.0 / 3.0 * Math.tan(a / 4.0); - if (isLeft) { - k = -k; - } - - x10 *= k; - y10 *= k; - x20 *= k; - y20 *= k; - - p.cubicTo(x1 - y10, y1 + x10, x2 + y20, y2 - x20, x2, y2); - } else { - double k = 4.0 / 3.0 * Math.tan(a / 8.0); - if (isLeft) { - k = -k; - } - - x10 *= k; - y10 *= k; - x20 *= k; - y20 *= k; - x30 *= k; - y30 *= k; - - p.cubicTo(x1 - y10, y1 + x10, x3 + y30, y3 - x30, x3, y3); - p.cubicTo(x3 - y30, y3 + x30, x2 + y20, y2 - x20, x2, y2); - } - - } - - /** - * Adds solid line segment to the work path. - * - * @param x1 - * the x coordinate of the start line point. - * @param y1 - * the y coordinate of the start line point. - * @param x2 - * the x coordinate of the end line point. - * @param y2 - * the y coordinate of the end line point. - * @param zero - * if true it's allowable to add zero length line segment. - */ - void addLine(double x1, double y1, double x2, double y2, boolean zero) { - double dx = x2 - x1; - double dy = y2 - y1; - - if (dx == 0.0 && dy == 0.0) { - if (!zero) { - return; - } - dx = w2; - dy = 0; - } else { - double w = w2 / Math.sqrt(dx * dx + dy * dy); - dx *= w; - dy *= w; - } - - double lx1 = x1 - dy; - double ly1 = y1 + dx; - double rx1 = x1 + dy; - double ry1 = y1 - dx; - - if (checkMove) { - if (isMove) { - isMove = false; - lp.moveTo(lx1, ly1); - rp.moveTo(rx1, ry1); - } else { - addJoin(lp, x1, y1, lx1, ly1, true); - addJoin(rp, x1, y1, rx1, ry1, false); - } - } - - lp.lineTo(x2 - dy, y2 + dx); - rp.lineTo(x2 + dy, y2 - dx); - } - - /** - * Adds solid quad segment to the work path. - * - * @param x1 - * the x coordinate of the first control point. - * @param y1 - * the y coordinate of the first control point. - * @param x2 - * the x coordinate of the second control point. - * @param y2 - * the y coordinate of the second control point. - * @param x3 - * the x coordinate of the third control point. - * @param y3 - * the y coordinate of the third control point. - */ - void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) { - double x21 = x2 - x1; - double y21 = y2 - y1; - double x23 = x2 - x3; - double y23 = y2 - y3; - - double l21 = Math.sqrt(x21 * x21 + y21 * y21); - double l23 = Math.sqrt(x23 * x23 + y23 * y23); - - if (l21 == 0.0 && l23 == 0.0) { - addLine(x1, y1, x3, y3, false); - return; - } - - if (l21 == 0.0) { - addLine(x2, y2, x3, y3, false); - return; - } - - if (l23 == 0.0) { - addLine(x1, y1, x2, y2, false); - return; - } - - double w; - w = w2 / l21; - double mx1 = -y21 * w; - double my1 = x21 * w; - w = w2 / l23; - double mx3 = y23 * w; - double my3 = -x23 * w; - - double lx1 = x1 + mx1; - double ly1 = y1 + my1; - double rx1 = x1 - mx1; - double ry1 = y1 - my1; - - if (checkMove) { - if (isMove) { - isMove = false; - lp.moveTo(lx1, ly1); - rp.moveTo(rx1, ry1); - } else { - addJoin(lp, x1, y1, lx1, ly1, true); - addJoin(rp, x1, y1, rx1, ry1, false); - } - } - - if (x21 * y23 - y21 * x23 == 0.0) { - // On line curve - if (x21 * x23 + y21 * y23 > 0.0) { - // Twisted curve - if (l21 == l23) { - double px = x1 + (x21 + x23) / 4.0; - double py = y1 + (y21 + y23) / 4.0; - lp.lineTo(px + mx1, py + my1); - rp.lineTo(px - mx1, py - my1); - lp.lineTo(px - mx1, py - my1); - rp.lineTo(px + mx1, py + my1); - lp.lineTo(x3 - mx1, y3 - my1); - rp.lineTo(x3 + mx1, y3 + my1); - } else { - double px1, py1; - double k = l21 / (l21 + l23); - double px = x1 + (x21 + x23) * k * k; - double py = y1 + (y21 + y23) * k * k; - px1 = (x1 + px) / 2.0; - py1 = (y1 + py) / 2.0; - lp.quadTo(px1 + mx1, py1 + my1, px + mx1, py + my1); - rp.quadTo(px1 - mx1, py1 - my1, px - mx1, py - my1); - lp.lineTo(px - mx1, py - my1); - rp.lineTo(px + mx1, py + my1); - px1 = (x3 + px) / 2.0; - py1 = (y3 + py) / 2.0; - lp.quadTo(px1 - mx1, py1 - my1, x3 - mx1, y3 - my1); - rp.quadTo(px1 + mx1, py1 + my1, x3 + mx1, y3 + my1); - } - } else { - // Simple curve - lp.quadTo(x2 + mx1, y2 + my1, x3 + mx3, y3 + my3); - rp.quadTo(x2 - mx1, y2 - my1, x3 - mx3, y3 - my3); - } - } else { - addSubQuad(x1, y1, x2, y2, x3, y3, 0); - } - } - - /** - * Subdivides solid quad curve to make outline for source quad segment and - * adds it to work path. - * - * @param x1 - * the x coordinate of the first control point. - * @param y1 - * the y coordinate of the first control point. - * @param x2 - * the x coordinate of the second control point. - * @param y2 - * the y coordinate of the second control point. - * @param x3 - * the x coordinate of the third control point. - * @param y3 - * the y coordinate of the third control point. - * @param level - * the maximum level of subdivision deepness. - */ - void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) { - double x21 = x2 - x1; - double y21 = y2 - y1; - double x23 = x2 - x3; - double y23 = y2 - y3; - - double cos = x21 * x23 + y21 * y23; - double sin = x21 * y23 - y21 * x23; - - if (level < MAX_LEVEL && (cos >= 0.0 || (Math.abs(sin / cos) > curveDelta))) { - double c1x = (x2 + x1) / 2.0; - double c1y = (y2 + y1) / 2.0; - double c2x = (x2 + x3) / 2.0; - double c2y = (y2 + y3) / 2.0; - double c3x = (c1x + c2x) / 2.0; - double c3y = (c1y + c2y) / 2.0; - addSubQuad(x1, y1, c1x, c1y, c3x, c3y, level + 1); - addSubQuad(c3x, c3y, c2x, c2y, x3, y3, level + 1); - } else { - double w; - double l21 = Math.sqrt(x21 * x21 + y21 * y21); - double l23 = Math.sqrt(x23 * x23 + y23 * y23); - w = w2 / sin; - double mx2 = (x21 * l23 + x23 * l21) * w; - double my2 = (y21 * l23 + y23 * l21) * w; - w = w2 / l23; - double mx3 = y23 * w; - double my3 = -x23 * w; - lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3); - rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3); - } - } - - /** - * Adds solid cubic segment to the work path. - * - * @param x1 - * the x coordinate of the first control point. - * @param y1 - * the y coordinate of the first control point. - * @param x2 - * the x coordinate of the second control point. - * @param y2 - * the y coordinate of the second control point. - * @param x3 - * the x coordinate of the third control point. - * @param y3 - * the y coordinate of the third control point. - * @param x4 - * the x coordinate of the fours control point. - * @param y4 - * the y coordinate of the fours control point. - */ - void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, - double y4) { - double x12 = x1 - x2; - double y12 = y1 - y2; - double x23 = x2 - x3; - double y23 = y2 - y3; - double x34 = x3 - x4; - double y34 = y3 - y4; - - double l12 = Math.sqrt(x12 * x12 + y12 * y12); - double l23 = Math.sqrt(x23 * x23 + y23 * y23); - double l34 = Math.sqrt(x34 * x34 + y34 * y34); - - // All edges are zero - if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) { - addLine(x1, y1, x4, y4, false); - return; - } - - // One zero edge - if (l12 == 0.0 && l23 == 0.0) { - addLine(x3, y3, x4, y4, false); - return; - } - - if (l23 == 0.0 && l34 == 0.0) { - addLine(x1, y1, x2, y2, false); - return; - } - - if (l12 == 0.0 && l34 == 0.0) { - addLine(x2, y2, x3, y3, false); - return; - } - - double w, mx1, my1, mx4, my4; - boolean onLine; - - if (l12 == 0.0) { - w = w2 / l23; - mx1 = y23 * w; - my1 = -x23 * w; - w = w2 / l34; - mx4 = y34 * w; - my4 = -x34 * w; - onLine = -x23 * y34 + y23 * x34 == 0.0; // sin3 - } else if (l34 == 0.0) { - w = w2 / l12; - mx1 = y12 * w; - my1 = -x12 * w; - w = w2 / l23; - mx4 = y23 * w; - my4 = -x23 * w; - onLine = -x12 * y23 + y12 * x23 == 0.0; // sin2 - } else { - w = w2 / l12; - mx1 = y12 * w; - my1 = -x12 * w; - w = w2 / l34; - mx4 = y34 * w; - my4 = -x34 * w; - if (l23 == 0.0) { - onLine = -x12 * y34 + y12 * x34 == 0.0; - } else { - onLine = -x12 * y34 + y12 * x34 == 0.0 && -x12 * y23 + y12 * x23 == 0.0 && // sin2 - -x23 * y34 + y23 * x34 == 0.0; // sin3 - } - } - - double lx1 = x1 + mx1; - double ly1 = y1 + my1; - double rx1 = x1 - mx1; - double ry1 = y1 - my1; - - if (checkMove) { - if (isMove) { - isMove = false; - lp.moveTo(lx1, ly1); - rp.moveTo(rx1, ry1); - } else { - addJoin(lp, x1, y1, lx1, ly1, true); - addJoin(rp, x1, y1, rx1, ry1, false); - } - } - - if (onLine) { - if ((x1 == x2 && y1 < y2) || x1 < x2) { - l12 = -l12; - } - if ((x2 == x3 && y2 < y3) || x2 < x3) { - l23 = -l23; - } - if ((x3 == x4 && y3 < y4) || x3 < x4) { - l34 = -l34; - } - double d = l23 * l23 - l12 * l34; - double roots[] = new double[3]; - int rc = 0; - if (d == 0.0) { - double t = (l12 - l23) / (l12 + l34 - l23 - l23); - if (0.0 < t && t < 1.0) { - roots[rc++] = t; - } - } else if (d > 0.0) { - d = Math.sqrt(d); - double z = l12 + l34 - l23 - l23; - double t; - t = (l12 - l23 + d) / z; - if (0.0 < t && t < 1.0) { - roots[rc++] = t; - } - t = (l12 - l23 - d) / z; - if (0.0 < t && t < 1.0) { - roots[rc++] = t; - } - } - - if (rc > 0) { - // Sort roots - if (rc == 2 && roots[0] > roots[1]) { - double tmp = roots[0]; - roots[0] = roots[1]; - roots[1] = tmp; - } - roots[rc++] = 1.0; - - double ax = -x34 - x12 + x23 + x23; - double ay = -y34 - y12 + y23 + y23; - double bx = 3.0 * (-x23 + x12); - double by = 3.0 * (-y23 + y12); - double cx = 3.0 * (-x12); - double cy = 3.0 * (-y12); - double xPrev = x1; - double yPrev = y1; - for (int i = 0; i < rc; i++) { - double t = roots[i]; - double px = t * (t * (t * ax + bx) + cx) + x1; - double py = t * (t * (t * ay + by) + cy) + y1; - double px1 = (xPrev + px) / 2.0; - double py1 = (yPrev + py) / 2.0; - lp.cubicTo(px1 + mx1, py1 + my1, px1 + mx1, py1 + my1, px + mx1, py + my1); - rp.cubicTo(px1 - mx1, py1 - my1, px1 - mx1, py1 - my1, px - mx1, py - my1); - if (i < rc - 1) { - lp.lineTo(px - mx1, py - my1); - rp.lineTo(px + mx1, py + my1); - } - xPrev = px; - yPrev = py; - mx1 = -mx1; - my1 = -my1; - } - } else { - lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4); - rp.cubicTo(x2 - mx1, y2 - my1, x3 - mx4, y3 - my4, x4 - mx4, y4 - my4); - } - } else { - addSubCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0); - } - } - - /** - * Subdivides solid cubic curve to make outline for source quad segment and - * adds it to work path. - * - * @param x1 - * the x coordinate of the first control point. - * @param y1 - * the y coordinate of the first control point. - * @param x2 - * the x coordinate of the second control point. - * @param y2 - * the y coordinate of the second control point. - * @param x3 - * the x coordinate of the third control point. - * @param y3 - * the y coordinate of the third control point. - * @param x4 - * the x coordinate of the fours control point. - * @param y4 - * the y coordinate of the fours control point. - * @param level - * the maximum level of subdivision deepness. - */ - void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, - double y4, int level) { - double x12 = x1 - x2; - double y12 = y1 - y2; - double x23 = x2 - x3; - double y23 = y2 - y3; - double x34 = x3 - x4; - double y34 = y3 - y4; - - double cos2 = -x12 * x23 - y12 * y23; - double cos3 = -x23 * x34 - y23 * y34; - double sin2 = -x12 * y23 + y12 * x23; - double sin3 = -x23 * y34 + y23 * x34; - double sin0 = -x12 * y34 + y12 * x34; - double cos0 = -x12 * x34 - y12 * y34; - - if (level < MAX_LEVEL - && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) - && (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 - || (Math.abs(sin2 / cos2) > curveDelta) - || (Math.abs(sin3 / cos3) > curveDelta) || (Math.abs(sin0 / cos0) > curveDelta))) { - double cx = (x2 + x3) / 2.0; - double cy = (y2 + y3) / 2.0; - double lx2 = (x2 + x1) / 2.0; - double ly2 = (y2 + y1) / 2.0; - double rx3 = (x3 + x4) / 2.0; - double ry3 = (y3 + y4) / 2.0; - double lx3 = (cx + lx2) / 2.0; - double ly3 = (cy + ly2) / 2.0; - double rx2 = (cx + rx3) / 2.0; - double ry2 = (cy + ry3) / 2.0; - cx = (lx3 + rx2) / 2.0; - cy = (ly3 + ry2) / 2.0; - addSubCubic(x1, y1, lx2, ly2, lx3, ly3, cx, cy, level + 1); - addSubCubic(cx, cy, rx2, ry2, rx3, ry3, x4, y4, level + 1); - } else { - double w, mx1, my1, mx2, my2, mx3, my3, mx4, my4; - double l12 = Math.sqrt(x12 * x12 + y12 * y12); - double l23 = Math.sqrt(x23 * x23 + y23 * y23); - double l34 = Math.sqrt(x34 * x34 + y34 * y34); - - if (l12 == 0.0) { - w = w2 / l23; - mx1 = y23 * w; - my1 = -x23 * w; - w = w2 / l34; - mx4 = y34 * w; - my4 = -x34 * w; - } else if (l34 == 0.0) { - w = w2 / l12; - mx1 = y12 * w; - my1 = -x12 * w; - w = w2 / l23; - mx4 = y23 * w; - my4 = -x23 * w; - } else { - // Common case - w = w2 / l12; - mx1 = y12 * w; - my1 = -x12 * w; - w = w2 / l34; - mx4 = y34 * w; - my4 = -x34 * w; - } - - if (sin2 == 0.0) { - mx2 = mx1; - my2 = my1; - } else { - w = w2 / sin2; - mx2 = -(x12 * l23 - x23 * l12) * w; - my2 = -(y12 * l23 - y23 * l12) * w; - } - if (sin3 == 0.0) { - mx3 = mx4; - my3 = my4; - } else { - w = w2 / sin3; - mx3 = -(x23 * l34 - x34 * l23) * w; - my3 = -(y23 * l34 - y34 * l23) * w; - } - - lp.cubicTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3, x4 + mx4, y4 + my4); - rp.cubicTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3, x4 - mx4, y4 - my4); - } - } - - /** - * Adds dashed line segment to the work path. - * - * @param x1 - * the x coordinate of the start line point. - * @param y1 - * the y coordinate of the start line point. - * @param x2 - * the x coordinate of the end line point. - * @param y2 - * the y coordinate of the end line point. - */ - void addDashLine(double x1, double y1, double x2, double y2) { - double x21 = x2 - x1; - double y21 = y2 - y1; - - double l21 = Math.sqrt(x21 * x21 + y21 * y21); - - if (l21 == 0.0) { - return; - } - - double px1, py1; - px1 = py1 = 0.0; - double w = w2 / l21; - double mx = -y21 * w; - double my = x21 * w; - - dasher.init(new DashIterator.Line(l21)); - - while (!dasher.eof()) { - double t = dasher.getValue(); - scx = x1 + t * x21; - scy = y1 + t * y21; - - if (dasher.isOpen()) { - px1 = scx; - py1 = scy; - double lx1 = px1 + mx; - double ly1 = py1 + my; - double rx1 = px1 - mx; - double ry1 = py1 - my; - if (isMove) { - isMove = false; - smx = px1; - smy = py1; - rp.clean(); - lp.moveTo(lx1, ly1); - rp.moveTo(rx1, ry1); - } else { - addJoin(lp, x1, y1, lx1, ly1, true); - addJoin(rp, x1, y1, rx1, ry1, false); - } - } else if (dasher.isContinue()) { - double px2 = scx; - double py2 = scy; - lp.lineTo(px2 + mx, py2 + my); - rp.lineTo(px2 - mx, py2 - my); - if (dasher.close) { - addCap(lp, px2, py2, rp.xLast, rp.yLast); - lp.combine(rp); - if (isFirst) { - isFirst = false; - fmx = smx; - fmy = smy; - sp = lp; - lp = new BufferedPath(); - } else { - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - isMove = true; - } - } - - dasher.next(); - } - } - - /** - * Adds dashed quad segment to the work path. - * - * @param x1 - * the x coordinate of the first control point. - * @param y1 - * the y coordinate of the first control point. - * @param x2 - * the x coordinate of the second control point. - * @param y2 - * the y coordinate of the second control point. - * @param x3 - * the x coordinate of the third control point. - * @param y3 - * the y coordinate of the third control point. - */ - void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) { - - double x21 = x2 - x1; - double y21 = y2 - y1; - double x23 = x2 - x3; - double y23 = y2 - y3; - - double l21 = Math.sqrt(x21 * x21 + y21 * y21); - double l23 = Math.sqrt(x23 * x23 + y23 * y23); - - if (l21 == 0.0 && l23 == 0.0) { - return; - } - - if (l21 == 0.0) { - addDashLine(x2, y2, x3, y3); - return; - } - - if (l23 == 0.0) { - addDashLine(x1, y1, x2, y2); - return; - } - - double ax = x1 + x3 - x2 - x2; - double ay = y1 + y3 - y2 - y2; - double bx = x2 - x1; - double by = y2 - y1; - double cx = x1; - double cy = y1; - - double px1, py1, dx1, dy1; - px1 = py1 = dx1 = dy1 = 0.0; - double prev = 0.0; - - dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3)); - - while (!dasher.eof()) { - double t = dasher.getValue(); - double dx = t * ax + bx; - double dy = t * ay + by; - scx = t * (dx + bx) + cx; // t^2 * ax + 2.0 * t * bx + cx - scy = t * (dy + by) + cy; // t^2 * ay + 2.0 * t * by + cy - if (dasher.isOpen()) { - px1 = scx; - py1 = scy; - dx1 = dx; - dy1 = dy; - double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); - double mx1 = -dy1 * w; - double my1 = dx1 * w; - double lx1 = px1 + mx1; - double ly1 = py1 + my1; - double rx1 = px1 - mx1; - double ry1 = py1 - my1; - if (isMove) { - isMove = false; - smx = px1; - smy = py1; - rp.clean(); - lp.moveTo(lx1, ly1); - rp.moveTo(rx1, ry1); - } else { - addJoin(lp, x1, y1, lx1, ly1, true); - addJoin(rp, x1, y1, rx1, ry1, false); - } - } else if (dasher.isContinue()) { - double px3 = scx; - double py3 = scy; - double sx = x2 - x23 * prev; - double sy = y2 - y23 * prev; - double t2 = (t - prev) / (1 - prev); - double px2 = px1 + (sx - px1) * t2; - double py2 = py1 + (sy - py1) * t2; - - addQuad(px1, py1, px2, py2, px3, py3); - if (dasher.isClosed()) { - addCap(lp, px3, py3, rp.xLast, rp.yLast); - lp.combine(rp); - if (isFirst) { - isFirst = false; - fmx = smx; - fmy = smy; - sp = lp; - lp = new BufferedPath(); - } else { - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - isMove = true; - } - } - - prev = t; - dasher.next(); - } - } - - /** - * Adds dashed cubic segment to the work path. - * - * @param x1 - * the x coordinate of the first control point. - * @param y1 - * the y coordinate of the first control point. - * @param x2 - * the x coordinate of the second control point. - * @param y2 - * the y coordinate of the second control point. - * @param x3 - * the x coordinate of the third control point. - * @param y3 - * the y coordinate of the third control point. - * @param x4 - * the x coordinate of the fours control point. - * @param y4 - * the y coordinate of the fours control point. - */ - void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, - double y4) { - - double x12 = x1 - x2; - double y12 = y1 - y2; - double x23 = x2 - x3; - double y23 = y2 - y3; - double x34 = x3 - x4; - double y34 = y3 - y4; - - double l12 = Math.sqrt(x12 * x12 + y12 * y12); - double l23 = Math.sqrt(x23 * x23 + y23 * y23); - double l34 = Math.sqrt(x34 * x34 + y34 * y34); - - // All edges are zero - if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) { - // NOTHING - return; - } - - // One zero edge - if (l12 == 0.0 && l23 == 0.0) { - addDashLine(x3, y3, x4, y4); - return; - } - - if (l23 == 0.0 && l34 == 0.0) { - addDashLine(x1, y1, x2, y2); - return; - } - - if (l12 == 0.0 && l34 == 0.0) { - addDashLine(x2, y2, x3, y3); - return; - } - - double ax = x4 - x1 + 3.0 * (x2 - x3); - double ay = y4 - y1 + 3.0 * (y2 - y3); - double bx = 3.0 * (x1 + x3 - x2 - x2); - double by = 3.0 * (y1 + y3 - y2 - y2); - double cx = 3.0 * (x2 - x1); - double cy = 3.0 * (y2 - y1); - double dx = x1; - double dy = y1; - - double px1 = 0.0; - double py1 = 0.0; - double prev = 0.0; - - dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4)); - - while (!dasher.eof()) { - - double t = dasher.getValue(); - scx = t * (t * (t * ax + bx) + cx) + dx; - scy = t * (t * (t * ay + by) + cy) + dy; - if (dasher.isOpen()) { - px1 = scx; - py1 = scy; - double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx; - double dy1 = t * (t * (ay + ay + ay) + by + by) + cy; - double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); - double mx1 = -dy1 * w; - double my1 = dx1 * w; - double lx1 = px1 + mx1; - double ly1 = py1 + my1; - double rx1 = px1 - mx1; - double ry1 = py1 - my1; - if (isMove) { - isMove = false; - smx = px1; - smy = py1; - rp.clean(); - lp.moveTo(lx1, ly1); - rp.moveTo(rx1, ry1); - } else { - addJoin(lp, x1, y1, lx1, ly1, true); - addJoin(rp, x1, y1, rx1, ry1, false); - } - } else if (dasher.isContinue()) { - double sx1 = x2 - x23 * prev; - double sy1 = y2 - y23 * prev; - double sx2 = x3 - x34 * prev; - double sy2 = y3 - y34 * prev; - double sx3 = sx1 + (sx2 - sx1) * prev; - double sy3 = sy1 + (sy2 - sy1) * prev; - double t2 = (t - prev) / (1 - prev); - double sx4 = sx3 + (sx2 - sx3) * t2; - double sy4 = sy3 + (sy2 - sy3) * t2; - - double px4 = scx; - double py4 = scy; - double px2 = px1 + (sx3 - px1) * t2; - double py2 = py1 + (sy3 - py1) * t2; - double px3 = px2 + (sx4 - px2) * t2; - double py3 = py2 + (sy4 - py2) * t2; - - addCubic(px1, py1, px2, py2, px3, py3, px4, py4); - if (dasher.isClosed()) { - addCap(lp, px4, py4, rp.xLast, rp.yLast); - lp.combine(rp); - if (isFirst) { - isFirst = false; - fmx = smx; - fmy = smy; - sp = lp; - lp = new BufferedPath(); - } else { - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - isMove = true; - } - } - - prev = t; - dasher.next(); - } - } - - /** - * Dasher class provides dashing for particular dash style. - */ - class Dasher { - - /** - * The pos. - */ - double pos; - - /** - * The first. - */ - boolean close, visible, first; - - /** - * The dash. - */ - float dash[]; - - /** - * The phase. - */ - float phase; - - /** - * The index. - */ - int index; - - /** - * The iter. - */ - DashIterator iter; - - /** - * Instantiates a new dasher. - * - * @param dash - * the dash. - * @param phase - * the phase. - */ - Dasher(float dash[], float phase) { - this.dash = dash; - this.phase = phase; - index = 0; - pos = phase; - visible = true; - while (pos >= dash[index]) { - visible = !visible; - pos -= dash[index]; - index = (index + 1) % dash.length; - } - pos = -pos; - first = visible; - } - - /** - * Inits the. - * - * @param iter - * the iter. - */ - void init(DashIterator iter) { - this.iter = iter; - close = true; - } - - /** - * Checks if is open. - * - * @return true, if is open. - */ - boolean isOpen() { - return visible && pos < iter.length; - } - - /** - * Checks if is continue. - * - * @return true, if is continue. - */ - boolean isContinue() { - return !visible && pos > 0; - } - - /** - * Checks if is closed. - * - * @return true, if is closed. - */ - boolean isClosed() { - return close; - } - - /** - * Checks if is connected. - * - * @return true, if is connected. - */ - boolean isConnected() { - return first && !close; - } - - /** - * Eof. - * - * @return true, if successful. - */ - boolean eof() { - if (!close) { - pos -= iter.length; - return true; - } - if (pos >= iter.length) { - if (visible) { - pos -= iter.length; - return true; - } - close = pos == iter.length; - } - return false; - } - - /** - * Next. - */ - void next() { - if (close) { - pos += dash[index]; - index = (index + 1) % dash.length; - } else { - // Go back - index = (index + dash.length - 1) % dash.length; - pos -= dash[index]; - } - visible = !visible; - } - - /** - * Gets the value. - * - * @return the value. - */ - double getValue() { - double t = iter.getNext(pos); - return t < 0 ? 0 : (t > 1 ? 1 : t); - } - - } - - /** - * DashIterator class provides dashing for particular segment type. - */ - static abstract class DashIterator { - - /** - * The Constant FLATNESS. - */ - static final double FLATNESS = 1.0; - - /** - * The Class Line. - */ - static class Line extends DashIterator { - - /** - * Instantiates a new line. - * - * @param len - * the len. - */ - Line(double len) { - length = len; - } - - @Override - double getNext(double dashPos) { - return dashPos / length; - } - - } - - /** - * The Class Quad. - */ - static class Quad extends DashIterator { - - /** - * The val size. - */ - int valSize; - - /** - * The val pos. - */ - int valPos; - - /** - * The cur len. - */ - double curLen; - - /** - * The prev len. - */ - double prevLen; - - /** - * The last len. - */ - double lastLen; - - /** - * The values. - */ - double[] values; - - /** - * The step. - */ - double step; - - /** - * Instantiates a new quad. - * - * @param x1 - * the x1. - * @param y1 - * the y1. - * @param x2 - * the x2. - * @param y2 - * the y2. - * @param x3 - * the x3. - * @param y3 - * the y3. - */ - Quad(double x1, double y1, double x2, double y2, double x3, double y3) { - - double nx = x1 + x3 - x2 - x2; - double ny = y1 + y3 - y2 - y2; - - int n = (int)(1 + Math.sqrt(0.75 * (Math.abs(nx) + Math.abs(ny)) * FLATNESS)); - step = 1.0 / n; - - double ax = x1 + x3 - x2 - x2; - double ay = y1 + y3 - y2 - y2; - double bx = 2.0 * (x2 - x1); - double by = 2.0 * (y2 - y1); - - double dx1 = step * (step * ax + bx); - double dy1 = step * (step * ay + by); - double dx2 = step * (step * ax * 2.0); - double dy2 = step * (step * ay * 2.0); - double vx = x1; - double vy = y1; - - valSize = n; - values = new double[valSize]; - double pvx = vx; - double pvy = vy; - length = 0.0; - for (int i = 0; i < n; i++) { - vx += dx1; - vy += dy1; - dx1 += dx2; - dy1 += dy2; - double lx = vx - pvx; - double ly = vy - pvy; - values[i] = Math.sqrt(lx * lx + ly * ly); - length += values[i]; - pvx = vx; - pvy = vy; - } - - valPos = 0; - curLen = 0.0; - prevLen = 0.0; - } - - @Override - double getNext(double dashPos) { - double t = 2.0; - while (curLen <= dashPos && valPos < valSize) { - prevLen = curLen; - curLen += lastLen = values[valPos++]; - } - if (curLen > dashPos) { - t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step; - } - return t; - } - - } - - /** - * The Class Cubic. - */ - static class Cubic extends DashIterator { - - /** - * The val size. - */ - int valSize; - - /** - * The val pos. - */ - int valPos; - - /** - * The cur len. - */ - double curLen; - - /** - * The prev len. - */ - double prevLen; - - /** - * The last len. - */ - double lastLen; - - /** - * The values. - */ - double[] values; - - /** - * The step. - */ - double step; - - /** - * Instantiates a new cubic. - * - * @param x1 - * the x1. - * @param y1 - * the y1. - * @param x2 - * the x2. - * @param y2 - * the y2. - * @param x3 - * the x3. - * @param y3 - * the y3. - * @param x4 - * the x4. - * @param y4 - * the y4. - */ - Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, - double y4) { - - double nx1 = x1 + x3 - x2 - x2; - double ny1 = y1 + y3 - y2 - y2; - double nx2 = x2 + x4 - x3 - x3; - double ny2 = y2 + y4 - y3 - y3; - - double max = Math.max(Math.abs(nx1) + Math.abs(ny1), Math.abs(nx2) + Math.abs(ny2)); - int n = (int)(1 + Math.sqrt(0.75 * max) * FLATNESS); - step = 1.0 / n; - - double ax = x4 - x1 + 3.0 * (x2 - x3); - double ay = y4 - y1 + 3.0 * (y2 - y3); - double bx = 3.0 * (x1 + x3 - x2 - x2); - double by = 3.0 * (y1 + y3 - y2 - y2); - double cx = 3.0 * (x2 - x1); - double cy = 3.0 * (y2 - y1); - - double dx1 = step * (step * (step * ax + bx) + cx); - double dy1 = step * (step * (step * ay + by) + cy); - double dx2 = step * (step * (step * ax * 6.0 + bx * 2.0)); - double dy2 = step * (step * (step * ay * 6.0 + by * 2.0)); - double dx3 = step * (step * (step * ax * 6.0)); - double dy3 = step * (step * (step * ay * 6.0)); - double vx = x1; - double vy = y1; - - valSize = n; - values = new double[valSize]; - double pvx = vx; - double pvy = vy; - length = 0.0; - for (int i = 0; i < n; i++) { - vx += dx1; - vy += dy1; - dx1 += dx2; - dy1 += dy2; - dx2 += dx3; - dy2 += dy3; - double lx = vx - pvx; - double ly = vy - pvy; - values[i] = Math.sqrt(lx * lx + ly * ly); - length += values[i]; - pvx = vx; - pvy = vy; - } - - valPos = 0; - curLen = 0.0; - prevLen = 0.0; - } - - @Override - double getNext(double dashPos) { - double t = 2.0; - while (curLen <= dashPos && valPos < valSize) { - prevLen = curLen; - curLen += lastLen = values[valPos++]; - } - if (curLen > dashPos) { - t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step; - } - return t; - } - - } - - /** - * The length. - */ - double length; - - /** - * Gets the next. - * - * @param dashPos - * the dash pos. - * @return the next. - */ - abstract double getNext(double dashPos); - - } - - /** - * BufferedPath class provides work path storing and processing. - */ - static class BufferedPath { - - /** - * The Constant bufCapacity. - */ - private static final int bufCapacity = 10; - - /** - * The point shift. - */ - static int pointShift[] = { - 2, // MOVETO - 2, // LINETO - 4, // QUADTO - 6, // CUBICTO - 0 - }; // CLOSE - - /** - * The types. - */ - byte[] types; - - /** - * The points. - */ - float[] points; - - /** - * The type size. - */ - int typeSize; - - /** - * The point size. - */ - int pointSize; - - /** - * The x last. - */ - float xLast; - - /** - * The y last. - */ - float yLast; - - /** - * The x move. - */ - float xMove; - - /** - * The y move. - */ - float yMove; - - /** - * Instantiates a new buffered path. - */ - public BufferedPath() { - types = new byte[bufCapacity]; - points = new float[bufCapacity * 2]; - } - - /** - * Check buf. - * - * @param typeCount - * the type count. - * @param pointCount - * the point count. - */ - void checkBuf(int typeCount, int pointCount) { - if (typeSize + typeCount > types.length) { - byte tmp[] = new byte[typeSize + Math.max(bufCapacity, typeCount)]; - System.arraycopy(types, 0, tmp, 0, typeSize); - types = tmp; - } - if (pointSize + pointCount > points.length) { - float tmp[] = new float[pointSize + Math.max(bufCapacity * 2, pointCount)]; - System.arraycopy(points, 0, tmp, 0, pointSize); - points = tmp; - } - } - - /** - * Checks if is empty. - * - * @return true, if is empty. - */ - boolean isEmpty() { - return typeSize == 0; - } - - /** - * Clean. - */ - void clean() { - typeSize = 0; - pointSize = 0; - } - - /** - * Move to. - * - * @param x - * the x. - * @param y - * the y. - */ - void moveTo(double x, double y) { - checkBuf(1, 2); - types[typeSize++] = PathIterator.SEG_MOVETO; - points[pointSize++] = xMove = (float)x; - points[pointSize++] = yMove = (float)y; - } - - /** - * Line to. - * - * @param x - * the x. - * @param y - * the y. - */ - void lineTo(double x, double y) { - checkBuf(1, 2); - types[typeSize++] = PathIterator.SEG_LINETO; - points[pointSize++] = xLast = (float)x; - points[pointSize++] = yLast = (float)y; - } - - /** - * Quad to. - * - * @param x1 - * the x1. - * @param y1 - * the y1. - * @param x2 - * the x2. - * @param y2 - * the y2. - */ - void quadTo(double x1, double y1, double x2, double y2) { - checkBuf(1, 4); - types[typeSize++] = PathIterator.SEG_QUADTO; - points[pointSize++] = (float)x1; - points[pointSize++] = (float)y1; - points[pointSize++] = xLast = (float)x2; - points[pointSize++] = yLast = (float)y2; - } - - /** - * Cubic to. - * - * @param x1 - * the x1. - * @param y1 - * the y1. - * @param x2 - * the x2. - * @param y2 - * the y2. - * @param x3 - * the x3. - * @param y3 - * the y3. - */ - void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) { - checkBuf(1, 6); - types[typeSize++] = PathIterator.SEG_CUBICTO; - points[pointSize++] = (float)x1; - points[pointSize++] = (float)y1; - points[pointSize++] = (float)x2; - points[pointSize++] = (float)y2; - points[pointSize++] = xLast = (float)x3; - points[pointSize++] = yLast = (float)y3; - } - - /** - * Close path. - */ - void closePath() { - checkBuf(1, 0); - types[typeSize++] = PathIterator.SEG_CLOSE; - } - - /** - * Sets the last. - * - * @param x - * the x. - * @param y - * the y. - */ - void setLast(double x, double y) { - points[pointSize - 2] = xLast = (float)x; - points[pointSize - 1] = yLast = (float)y; - } - - /** - * Append. - * - * @param p - * the p. - */ - void append(BufferedPath p) { - checkBuf(p.typeSize, p.pointSize); - System.arraycopy(p.points, 0, points, pointSize, p.pointSize); - System.arraycopy(p.types, 0, types, typeSize, p.typeSize); - pointSize += p.pointSize; - typeSize += p.typeSize; - xLast = points[pointSize - 2]; - yLast = points[pointSize - 1]; - } - - /** - * Append reverse. - * - * @param p - * the p. - */ - void appendReverse(BufferedPath p) { - checkBuf(p.typeSize, p.pointSize); - // Skip last point, beacause it's the first point of the second path - for (int i = p.pointSize - 2; i >= 0; i -= 2) { - points[pointSize++] = p.points[i + 0]; - points[pointSize++] = p.points[i + 1]; - } - // Skip first type, beacuse it's always MOVETO - int closeIndex = 0; - for (int i = p.typeSize - 1; i >= 0; i--) { - byte type = p.types[i]; - if (type == PathIterator.SEG_MOVETO) { - types[closeIndex] = PathIterator.SEG_MOVETO; - types[typeSize++] = PathIterator.SEG_CLOSE; - } else { - if (type == PathIterator.SEG_CLOSE) { - closeIndex = typeSize; - } - types[typeSize++] = type; - } - } - xLast = points[pointSize - 2]; - yLast = points[pointSize - 1]; - } - - /** - * Join. - * - * @param p - * the p. - */ - void join(BufferedPath p) { - // Skip MOVETO - checkBuf(p.typeSize - 1, p.pointSize - 2); - System.arraycopy(p.points, 2, points, pointSize, p.pointSize - 2); - System.arraycopy(p.types, 1, types, typeSize, p.typeSize - 1); - pointSize += p.pointSize - 2; - typeSize += p.typeSize - 1; - xLast = points[pointSize - 2]; - yLast = points[pointSize - 1]; - } - - /** - * Combine. - * - * @param p - * the p. - */ - void combine(BufferedPath p) { - checkBuf(p.typeSize - 1, p.pointSize - 2); - // Skip last point, beacause it's the first point of the second path - for (int i = p.pointSize - 4; i >= 0; i -= 2) { - points[pointSize++] = p.points[i + 0]; - points[pointSize++] = p.points[i + 1]; - } - // Skip first type, beacuse it's always MOVETO - for (int i = p.typeSize - 1; i >= 1; i--) { - types[typeSize++] = p.types[i]; - } - xLast = points[pointSize - 2]; - yLast = points[pointSize - 1]; - } - - /** - * Creates the general path. - * - * @return the general path. - */ - GeneralPath createGeneralPath() { - GeneralPath p = new GeneralPath(); - int j = 0; - for (int i = 0; i < typeSize; i++) { - int type = types[i]; - switch (type) { - case PathIterator.SEG_MOVETO: - p.moveTo(points[j], points[j + 1]); - break; - case PathIterator.SEG_LINETO: - p.lineTo(points[j], points[j + 1]); - break; - case PathIterator.SEG_QUADTO: - p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]); - break; - case PathIterator.SEG_CUBICTO: - p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], - points[j + 4], points[j + 5]); - break; - case PathIterator.SEG_CLOSE: - p.closePath(); - break; - } - j += pointShift[type]; - } - return p; - } - - } - -} |