summaryrefslogtreecommitdiffstats
path: root/awt/java/awt/BasicStroke.java
diff options
context:
space:
mode:
Diffstat (limited to 'awt/java/awt/BasicStroke.java')
-rw-r--r--awt/java/awt/BasicStroke.java2443
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;
- }
-
- }
-
-}