/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package armyc2.c2sd.graphics2d; import java.util.ArrayList; import armyc2.c2sd.JavaLineArray.POINT2; import armyc2.c2sd.JavaLineArray.ref; import armyc2.c2sd.JavaLineArray.arraysupport; import armyc2.c2sd.JavaLineArray.lineutility; import armyc2.c2sd.JavaLineArray.TacticalLines; /** * * @author Michael Deutch */ public class BasicStroke implements Stroke, Shape{ /** * Joins path segments by extending their outside edges until they meet. */ public final static int JOIN_MITER = 0; /** * Joins path segments by rounding off the corner at a radius of half the * line width. */ public final static int JOIN_ROUND = 1; /** * Joins path segments by connecting the outer corners of their wide * outlines with a straight segment. */ public final static int JOIN_BEVEL = 2; /** * Ends unclosed subpaths and dash segments with no added decoration. */ public final static int CAP_BUTT = 0; /** * Ends unclosed subpaths and dash segments with a round decoration that has * a radius equal to half of the width of the pen. */ public final static int CAP_ROUND = 1; /** * Ends unclosed subpaths and dash segments with a square projection that * extends beyond the end of the segment to a distance equal to half of the * line width. */ public final static int CAP_SQUARE = 2; float width; int join; int cap; float miterlimit; float dash[]; float dash_phase; public BasicStroke(float width, int cap, int join, float miterlimit, float dash[], float dash_phase) { if (width < 0.0f) { throw new IllegalArgumentException("negative width"); } if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { throw new IllegalArgumentException("illegal end cap value"); } if (join == JOIN_MITER) { if (miterlimit < 1.0f) { throw new IllegalArgumentException("miter limit < 1"); } } else if (join != JOIN_ROUND && join != JOIN_BEVEL) { throw new IllegalArgumentException("illegal line join value"); } if (dash != null) { if (dash_phase < 0.0f) { throw new IllegalArgumentException("negative dash phase"); } boolean allzero = true; int n=dash.length; //for (int i = 0; i < dash.length; i++) for (int i = 0; i < n; i++) { float d = dash[i]; if (d > 0.0) { allzero = false; } else if (d < 0.0) { throw new IllegalArgumentException("negative dash length"); } } if (allzero) { throw new IllegalArgumentException("dash lengths all zero"); } } this.width = width; this.cap = cap; this.join = join; this.miterlimit = miterlimit; if (dash != null) { this.dash = (float[]) dash.clone(); } this.dash_phase = dash_phase; } public BasicStroke(float width, int cap, int join, float miterlimit) { this(width, cap, join, miterlimit, null, 0.0f); } public BasicStroke(float width, int cap, int join) { this(width, cap, join, 10.0f, null, 0.0f); } /** * Constructs a solid <code>BasicStroke</code> with the specified line width * and with default values for the cap and join styles. * * @param width * the width of the <code>BasicStroke</code> * @throws IllegalArgumentException * if <code>width</code> is negative */ public BasicStroke(float width) { this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); } /** * Constructs a new <code>BasicStroke</code> with defaults for all * attributes. The default attributes are a solid line of width 1.0, * CAP_SQUARE, JOIN_MITER, a miter limit of 10.0. */ public BasicStroke() { this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); } /** * Returns a <code>Shape</code> whose interior defines the stroked outline * of a specified <code>Shape</code>. * * @param s * the <code>Shape</code> boundary be stroked * @return the <code>Shape</code> of the stroked outline. */ public Shape createStrokedShape(Shape s) { /* * sun.java2d.pipe.RenderingEngine re = * sun.java2d.pipe.RenderingEngine.getInstance(); return * re.createStrokedShape(s, width, cap, join, miterlimit, dash, * dash_phase); */ return null; } public Shape createStrokedShape(Polygon poly) { /* * sun.java2d.pipe.RenderingEngine re = * sun.java2d.pipe.RenderingEngine.getInstance(); return * re.createStrokedShape(s, width, cap, join, miterlimit, dash, * dash_phase); */ ArrayList<POINT2>pts=poly.getPathIterator(null).getPoints(); int j=0; GeneralPath gp=new GeneralPath(); POINT2 pt=null; POINT2[]ptsx=new POINT2[pts.size()]; int n=pts.size(); //for(j=0;j<pts.size();j++) for(j=0;j<n;j++) { pt=pts.get(j); ptsx[j]=pt; } pts=GetInteriorPoints(ptsx,pts.size(),TacticalLines.DEPTH_AREA,this.width); //for(j=0;j<pts.size();j++) for(j=0;j<n;j++) { pt=pts.get(j); if(j==0) gp.moveTo(pt.x, pt.y); else gp.lineTo(pt.x, pt.y); } return gp; } public float getLineWidth() { return width; } /** * Returns the end cap style. * * @return the end cap style of this <code>BasicStroke</code> as one of the * static <code>int</code> values that define possible end cap * styles. */ public int getEndCap() { return cap; } public int getLineJoin() { return join; } /** * Returns the limit of miter joins. * * @return the limit of miter joins of the <code>BasicStroke</code>. */ public float getMiterLimit() { return miterlimit; } /** * Returns the array representing the lengths of the dash segments. * Alternate entries in the array represent the user space lengths of the * opaque and transparent segments of the dashes. As the pen moves along the * outline of the <code>Shape</code> to be stroked, the user space distance * that the pen travels is accumulated. The distance value is used to index * into the dash array. The pen is opaque when its current cumulative * distance maps to an even element of the dash array and transparent * otherwise. * * @return the dash array. */ public float[] getDashArray() { if (dash == null) { return null; } return (float[]) dash.clone(); } public float getDashPhase() { return dash_phase; } /** * Returns the hashcode for this stroke. * * @return a hash code for this stroke. */ public int hashCode() { int hash = Float.floatToIntBits(width); hash = hash * 31 + join; hash = hash * 31 + cap; hash = hash * 31 + Float.floatToIntBits(miterlimit); if (dash != null) { hash = hash * 31 + Float.floatToIntBits(dash_phase); int n=dash.length; //for (int i = 0; i < dash.length; i++) for (int i = 0; i < n; i++) { hash = hash * 31 + Float.floatToIntBits(dash[i]); } } return hash; } //the Shape interface methods public PathIterator getPathIterator(AffineTransform at) { return null; } public boolean contains (int x, int y) { return false; } public boolean contains (int x, int y, int width, int height) { return false; } public boolean contains (Point2D pt) { return false; } public Rectangle2D getBounds2D() { return null; } public Rectangle getBounds() { return null; } public boolean intersects(double x, double y, double w, double h) { return false; } public boolean intersects(Rectangle2D rect) { return false; } public static ArrayList<POINT2> GetInteriorPoints(POINT2[] pLinePoints, int vblCounter, int lineType, double dist) { //var j:int=0; int j = 0; //var index:int=-1; int index = -1; //var pt0:POINT2,pt1:POINT2,pt2:POINT2; POINT2 pt0 = null, pt1 = null, pt2 = null; ///var m01:refobj=new refobj(),m12:refobj=new refobj(); //slopes for lines pt0-pt1 and pt1-pt2 ref<double[]> m01 = new ref(), m12 = new ref(), m1 = new ref(), m2 = new ref(); //var direction:int=-1; int direction = -1; //var array:Array=new Array(); //ArrayList<POINT2>array=new ArrayList(); //var intersectPt:POINT2=null; POINT2 intersectPt = null; //var m1:refobj=new refobj(),m2:refobj=new refobj(); //var intersectPoints:Array=new Array(); ArrayList<POINT2> intersectPoints = new ArrayList(); //var b01:Number,b12:Number; //the y intercepts for the lines corresponding to m1,m2 double b01 = 0, b12 = 0; //var dist:Number=10; //double dist = 10; //the first set of interior points //this assumes the area is closed for (j = 0; j < vblCounter; j++) { if (j == 0 || j == vblCounter - 1) { //pt0=new POINT2(pLinePoints[vblCounter-2]); //pt1=new POINT2(pLinePoints[0]); //pt2=new POINT2(pLinePoints[1]); pt0 = pLinePoints[vblCounter - 2]; pt1 = pLinePoints[0]; pt2 = pLinePoints[1]; } else { //pt0=new POINT2(pLinePoints[j-1]); //pt1=new POINT2(pLinePoints[j]); //pt2=new POINT2(pLinePoints[j+1]); pt0 = pLinePoints[j - 1]; pt1 = pLinePoints[j]; pt2 = pLinePoints[j+1]; } //the interiior points //var pt00:POINT2,pt01:POINT2; //var pt10:POINT2,pt11:POINT2; POINT2 pt00 = null, pt01 = null; POINT2 pt10 = null, pt11 = null; index = j - 1; if (index < 0) { index = vblCounter - 1; } direction = arraysupport.GetInsideOutsideDouble2(pt0, pt1, pLinePoints, vblCounter, index, lineType); //reverse the directions since these are interior points //pt00-pt01 will be the interior line inside line pt0-pt1 //pt00 is inside pt0, pt01 is inside pt1 switch (direction) { case 0: //direction=1; pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 1, dist); pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 1, dist); break; case 1: //direction=0; pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 0, dist); pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 0, dist); break; case 2: //direction=3; pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 3, dist); pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 3, dist); break; case 3: //direction=2; pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 2, dist); pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 2, dist); break; } //pt10-pt11 will be the interior line inside line pt1-pt2 //pt10 is inside pt1, pt11 is inside pt2 index = j; if (j == vblCounter - 1) { index = 0; } direction = arraysupport.GetInsideOutsideDouble2(pt1, pt2, pLinePoints, vblCounter, index, lineType); //reverse the directions since these are interior points switch (direction) { case 0: //direction=1; pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 1, dist); pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 1, dist); break; case 1: //direction=0; pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 0, dist); pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 0, dist); break; case 2: //direction=3; pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 3, dist); pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 3, dist); break; case 3: //direction=2; pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 2, dist); pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 2, dist); break; } //end switch //intersectPt=new POINT2(null); //get the intersection of pt01-p00 and pt10-pt11 //so it it is the interior intersection of pt0-pt1 and pt1-pt2 //first handle the case of vertical lines. if (pt0.x == pt1.x && pt1.x == pt2.x) { intersectPt = new POINT2(pt01); intersectPoints.add(intersectPt); continue; } //it's the same situation if the slopes are identical, //simply use pt01 or pt10 since they already uniquely define the intesection lineutility.CalcTrueSlopeDouble2(pt00, pt01, m01); lineutility.CalcTrueSlopeDouble2(pt10, pt11, m12); if (m01.value[0] == m12.value[0]) { intersectPt = new POINT2(pt01); intersectPoints.add(intersectPt); continue; } //now we are assuming a non-trivial intersection //calculate the y-intercepts using y=mx+b (use b=y-mx) b01 = pt01.y - m01.value[0] * pt01.x; b12 = pt11.y - m12.value[0] * pt11.x; intersectPt = lineutility.CalcTrueIntersectDouble2(m01.value[0], b01, m12.value[0], b12, 1, 1, 0, 0); intersectPoints.add(intersectPt); }//end for return intersectPoints; } }