FileDocCategorySizeDatePackage
BasicStroke.javaAPI DocAndroid 1.5 API73368Wed May 06 22:41:54 BST 2009java.awt

BasicStroke

public class BasicStroke extends Object implements Stroke
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:

  • line width -the pen width which draws the outlines.
  • 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.
  • 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.
  • miter limit - the limit to trim a line join that has a JOIN_MITER decoration.
  • dash attributes - the definition of how to make a dash pattern by alternating between opaque and transparent sections

since
Android 1.0

Fields Summary
public static final int
CAP_BUTT
The Constant CAP_BUTT indicates the ends of unclosed subpaths and dash segments have no added decoration.
public static final int
CAP_ROUND
The Constant CAP_ROUND indicates the ends of unclosed subpaths and dash segments have a round decoration.
public static final int
CAP_SQUARE
The Constant CAP_SQUARE indicates the ends of unclosed subpaths and dash segments have a square projection.
public static final int
JOIN_MITER
The Constant JOIN_MITER indicates that path segments are joined by extending their outside edges until they meet.
public static final int
JOIN_ROUND
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_BEVEL
The Constant JOIN_BEVEL indicates that path segments are joined by connecting the outer corners of their wide outlines with a straight segment.
static final int
MAX_LEVEL
Constants for calculating.
static final double
CURVE_DELTA
The Constant CURVE_DELTA.
static final double
CORNER_ANGLE
The Constant CORNER_ANGLE.
static final double
CORNER_ZERO
The Constant CORNER_ZERO.
static final double
CUBIC_ARC
The Constant CUBIC_ARC.
float
width
Stroke width.
int
cap
Stroke cap type.
int
join
Stroke join type.
float
miterLimit
Stroke miter limit.
float[]
dash
Stroke dashes array.
float
dashPhase
Stroke dash phase.
double
curveDelta
The temporary pre-calculated values.
double
cornerDelta
The corner delta.
double
zeroDelta
The zero delta.
double
w2
The w2.
double
fmx
The fmy.
double
fmy
double
scx
The smy.
double
scy
double
smx
double
smy
double
mx
The cy.
double
my
double
cx
double
cy
boolean
isMove
The temporary indicators.
boolean
isFirst
The is first.
boolean
checkMove
The check move.
BufferedPath
dst
The temporary and destination work paths.
BufferedPath
lp
BufferedPath
rp
BufferedPath
sp
Dasher
dasher
Stroke dasher class.
Constructors Summary
public BasicStroke()
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.


                                                
      
        this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
    
public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, float dashPhase)
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.

        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;
    
public BasicStroke(float width, int cap, int join, float miterLimit)
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.

        this(width, cap, join, miterLimit, null, 0.0f);
    
public BasicStroke(float width, int cap, int join)
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.

        this(width, cap, join, 10.0f, null, 0.0f);
    
public BasicStroke(float width)
Instantiates a new BasicStroke with specified width and default cap, join, limit, dash attributes parameters.

param
width the width of BasicStroke.

        this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
    
Methods Summary
voidaddCap(java.awt.BasicStroke$BufferedPath p, double x0, double y0, double x2, double y2)
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.

        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;
        }
    
voidaddCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
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.

        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);
        }
    
voidaddDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
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.


        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();
        }
    
voidaddDashLine(double x1, double y1, double x2, double y2)
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.

        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();
        }
    
voidaddDashQuad(double x1, double y1, double x2, double y2, double x3, double y3)
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.


        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();
        }
    
voidaddJoin(java.awt.BasicStroke$BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft)
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.

        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;
            }
        }
    
voidaddLine(double x1, double y1, double x2, double y2, boolean zero)
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.

        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);
    
voidaddQuad(double x1, double y1, double x2, double y2, double x3, double y3)
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.

        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);
        }
    
voidaddRoundJoin(java.awt.BasicStroke$BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft)
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.

        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);
        }

    
voidaddSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, int level)
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.

        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);
        }
    
voidaddSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level)
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.

        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);
        }
    
voidcloseDashedShape()
Closes dashed shape path.

        // 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);
        }
    
voidcloseSolidShape()
Closes solid shape path.

        addCap(lp, cx, cy, rp.xLast, rp.yLast);
        lp.combine(rp);
        addCap(lp, mx, my, lp.xMove, lp.yMove);
        lp.closePath();
    
voidcreateDashedShape(java.awt.geom.PathIterator p)
Generates dashed stroked shape.

param
p the PathIterator of source shape.

        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();
        }

    
voidcreateSolidShape(java.awt.geom.PathIterator p)
Generates a shape with a solid (not dashed) outline.

param
p the PathIterator of source shape.

        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;
    
public java.awt.ShapecreateStrokedShape(java.awt.Shape s)
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)

        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();
    
public booleanequals(java.lang.Object obj)
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.

        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;
    
doublegetCornerDelta(double width)
Calculates the value to detect a small angle.

param
width the width.
return
the corner delta.

        return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0);
    
doublegetCurveDelta(double width)
Calculates allowable curve derivation.

param
width the width.
return
the curve delta.

        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);
    
public float[]getDashArray()
Gets the dash attributes array of the BasicStroke.

return
the dash attributes array of the BasicStroke.

        return dash;
    
public floatgetDashPhase()
Gets the dash phase of the BasicStroke.

return
the dash phase of the BasicStroke.

        return dashPhase;
    
public intgetEndCap()
Gets the end cap style of the BasicStroke.

return
the end cap style of the BasicStroke.

        return cap;
    
public intgetLineJoin()
Gets the line join style of the BasicStroke.

return
the line join style of the BasicStroke.

        return join;
    
public floatgetLineWidth()
Gets the line width of the BasicStroke.

return
the line width of the BasicStroke.

        return width;
    
public floatgetMiterLimit()
Gets the miter limit of the BasicStroke (the limit to trim the miter join).

return
the miter limit of the BasicStroke.

        return miterLimit;
    
doublegetZeroDelta(double width)
Calculates value to detect a zero angle.

param
width the width.
return
the zero delta.

        return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0);
    
public inthashCode()
Returns hash code of this BasicStroke.

return
the hash code of this BasicStroke.

        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();