package com.kreative.paint.material.stroke;
import java.awt.BasicStroke;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;
import java.util.Arrays;
public class PowerStroke implements Stroke {
public static final PowerStroke DEFAULT = new PowerStroke(
/* lineWidth = */ 1.0f,
/* multiplicity = */ 1,
/* dashArray = */ null,
/* dashPhase = */ 0.0f,
/* arrowOnStart = */ null,
/* arrowOnEnd = */ null,
/* endCap = */ EndCap.SQUARE,
/* lineJoin = */ LineJoin.MITER,
/* miterLimit = */ 10.0f,
/* name = */ "Default"
);
private final BasicStroke base;
public final float lineWidth;
public final int multiplicity;
public final float[] dashArray;
public final float dashPhase;
public final Arrowhead arrowOnStart;
public final Arrowhead arrowOnEnd;
public final EndCap endCap;
public final LineJoin lineJoin;
public final float miterLimit;
public final String name;
public PowerStroke(
float lineWidth, int multiplicity,
float[] dashArray, float dashPhase,
Arrowhead arrowOnStart, Arrowhead arrowOnEnd,
EndCap endCap, LineJoin lineJoin, float miterLimit,
String name
) {
this.base = new BasicStroke(
lineWidth,
((endCap != null) ? endCap.awtValue : 0),
((lineJoin != null) ? lineJoin.awtValue : 0),
miterLimit,
dashArray,
dashPhase
);
this.lineWidth = lineWidth;
this.multiplicity = multiplicity;
this.dashArray = dashArray;
this.dashPhase = dashPhase;
this.arrowOnStart = arrowOnStart;
this.arrowOnEnd = arrowOnEnd;
this.endCap = endCap;
this.lineJoin = lineJoin;
this.miterLimit = miterLimit;
this.name = name;
}
public Shape createStrokedShape(Shape shape) {
Shape originalShape = shape;
Shape strokedShape = shape;
for (int i = 0; i < multiplicity; i++) {
strokedShape = base.createStrokedShape(strokedShape);
}
if (arrowOnStart == null && arrowOnEnd == null) {
return strokedShape;
}
float sx1 = 0.0f;
float sy1 = 0.0f;
float sx2 = 0.0f;
float sy2 = 0.0f;
boolean startset = false;
float ex1 = 0.0f;
float ey1 = 0.0f;
float ex2 = 0.0f;
float ey2 = 0.0f;
boolean endset = false;
float mx = 0.0f;
float my = 0.0f;
float cx = 0.0f;
float cy = 0.0f;
float[] coords = new float[6];
PathIterator i = originalShape.getPathIterator(null);
while (!i.isDone()) {
switch (i.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
mx = coords[0]; my = coords[1];
cx = coords[0]; cy = coords[1];
break;
case PathIterator.SEG_LINETO:
if (!startset) {
sx1 = cx; sy1 = cy;
sx2 = coords[0]; sy2 = coords[1];
startset = true;
}
ex1 = cx; ey1 = cy;
ex2 = coords[0]; ey2 = coords[1];
endset = true;
cx = coords[0]; cy = coords[1];
break;
case PathIterator.SEG_QUADTO:
if (!startset) {
sx1 = cx; sy1 = cy;
sx2 = coords[0]; sy2 = coords[1];
startset = true;
}
ex1 = coords[0]; ey1 = coords[1];
ex2 = coords[2]; ey2 = coords[3];
endset = true;
cx = coords[2]; cy = coords[3];
break;
case PathIterator.SEG_CUBICTO:
if (!startset) {
sx1 = cx; sy1 = cy;
sx2 = coords[0]; sy2 = coords[1];
startset = true;
}
ex1 = coords[2]; ey1 = coords[3];
ex2 = coords[4]; ey2 = coords[5];
endset = true;
cx = coords[4]; cy = coords[5];
break;
case PathIterator.SEG_CLOSE:
if (!startset) {
sx1 = cx; sy1 = cy;
sx2 = mx; sy2 = my;
startset = true;
}
ex1 = cx; ey1 = cy;
ex2 = mx; ey2 = my;
endset = true;
cx = mx; cy = my;
break;
}
i.next();
}
if (startset && endset && sx1 == ex2 && sy1 == ey2) {
return strokedShape;
}
Area a = new Area(strokedShape);
if (startset && arrowOnStart != null) {
Shape arrow = arrowOnStart.createArrowhead(sx2, sy2, sx1, sy1, lineWidth);
a.add(new Area(arrow));
}
if (endset && arrowOnEnd != null) {
Shape arrow = arrowOnEnd.createArrowhead(ex1, ey1, ex2, ey2, lineWidth);
a.add(new Area(arrow));
}
return a;
}
@Override
public boolean equals(Object that) {
if (that instanceof PowerStroke) {
return this.equals((PowerStroke)that, false);
} else {
return false;
}
}
public boolean equals(PowerStroke that, boolean withName) {
if (this.lineWidth != that.lineWidth) return false;
if (this.multiplicity != that.multiplicity) return false;
if (!Arrays.equals(this.dashArray, that.dashArray)) return false;
if (this.dashPhase != that.dashPhase) return false;
if (!arrowheadEquals(this.arrowOnStart, that.arrowOnStart)) return false;
if (!arrowheadEquals(this.arrowOnEnd, that.arrowOnEnd)) return false;
if (this.endCap != that.endCap) return false;
if (this.lineJoin != that.lineJoin) return false;
if (this.miterLimit != that.miterLimit) return false;
if (!withName) return true;
if (this.name != null) return this.name.equals(that.name);
if (that.name != null) return that.name.equals(this.name);
return true;
}
@Override
public int hashCode() {
int hashCode = 0;
hashCode ^= Float.floatToIntBits(lineWidth);
hashCode ^= multiplicity;
hashCode ^= Arrays.hashCode(dashArray);
hashCode ^= Float.floatToIntBits(dashPhase);
if (arrowOnStart != null) hashCode ^= arrowOnStart.hashCode();
if (arrowOnEnd != null) hashCode ^= arrowOnEnd.hashCode();
if (endCap != null) hashCode ^= endCap.awtValue;
if (lineJoin != null) hashCode ^= lineJoin.awtValue;
hashCode ^= Float.floatToIntBits(miterLimit);
return hashCode;
}
public PowerStroke deriveBasicStroke(BasicStroke stroke) {
return new PowerStroke(
stroke.getLineWidth(), multiplicity,
stroke.getDashArray(), stroke.getDashPhase(),
arrowOnStart, arrowOnEnd,
EndCap.forAWTValue(stroke.getEndCap()),
LineJoin.forAWTValue(stroke.getLineJoin()),
stroke.getMiterLimit(),
null
);
}
public PowerStroke deriveLineWidth(float lineWidth) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveMultiplicity(int multiplicity) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveDashArray(float[] dashArray) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveDashPhase(float dashPhase) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveArrowOnStart(Arrowhead arrowOnStart) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveArrowOnEnd(Arrowhead arrowOnEnd) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveEndCap(EndCap endCap) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveLineJoin(LineJoin lineJoin) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveMiterLimit(float miterLimit) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
null
);
}
public PowerStroke deriveName(String name) {
return new PowerStroke(
lineWidth, multiplicity,
dashArray, dashPhase,
arrowOnStart, arrowOnEnd,
endCap, lineJoin, miterLimit,
name
);
}
private static boolean arrowheadEquals(Arrowhead a, Arrowhead b) {
if (a == null) return (b == null);
if (b == null) return (a == null);
return a.equals(b);
}
}