001/* 002 * To change this template, choose Tools | Templates 003 * and open the template in the editor. 004 */ 005package armyc2.c2sd.graphics2d; 006import java.util.ArrayList; 007import armyc2.c2sd.JavaLineArray.POINT2; 008import armyc2.c2sd.JavaLineArray.ref; 009import armyc2.c2sd.JavaLineArray.arraysupport; 010import armyc2.c2sd.JavaLineArray.lineutility; 011import armyc2.c2sd.JavaLineArray.TacticalLines; 012 013/** 014 * 015 * @author Michael Deutch 016 */ 017public class BasicStroke implements Stroke, Shape{ 018 019 /** 020 * Joins path segments by extending their outside edges until they meet. 021 */ 022 public final static int JOIN_MITER = 0; 023 /** 024 * Joins path segments by rounding off the corner at a radius of half the 025 * line width. 026 */ 027 public final static int JOIN_ROUND = 1; 028 /** 029 * Joins path segments by connecting the outer corners of their wide 030 * outlines with a straight segment. 031 */ 032 public final static int JOIN_BEVEL = 2; 033 /** 034 * Ends unclosed subpaths and dash segments with no added decoration. 035 */ 036 public final static int CAP_BUTT = 0; 037 /** 038 * Ends unclosed subpaths and dash segments with a round decoration that has 039 * a radius equal to half of the width of the pen. 040 */ 041 public final static int CAP_ROUND = 1; 042 /** 043 * Ends unclosed subpaths and dash segments with a square projection that 044 * extends beyond the end of the segment to a distance equal to half of the 045 * line width. 046 */ 047 public final static int CAP_SQUARE = 2; 048 float width; 049 int join; 050 int cap; 051 float miterlimit; 052 float dash[]; 053 float dash_phase; 054 055 public BasicStroke(float width, int cap, int join, float miterlimit, 056 float dash[], float dash_phase) { 057 if (width < 0.0f) { 058 throw new IllegalArgumentException("negative width"); 059 } 060 if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { 061 throw new IllegalArgumentException("illegal end cap value"); 062 } 063 if (join == JOIN_MITER) { 064 if (miterlimit < 1.0f) { 065 throw new IllegalArgumentException("miter limit < 1"); 066 } 067 } else if (join != JOIN_ROUND && join != JOIN_BEVEL) { 068 throw new IllegalArgumentException("illegal line join value"); 069 } 070 if (dash != null) { 071 if (dash_phase < 0.0f) { 072 throw new IllegalArgumentException("negative dash phase"); 073 } 074 boolean allzero = true; 075 int n=dash.length; 076 //for (int i = 0; i < dash.length; i++) 077 for (int i = 0; i < n; i++) 078 { 079 float d = dash[i]; 080 if (d > 0.0) { 081 allzero = false; 082 } else if (d < 0.0) { 083 throw new IllegalArgumentException("negative dash length"); 084 } 085 } 086 if (allzero) { 087 throw new IllegalArgumentException("dash lengths all zero"); 088 } 089 } 090 this.width = width; 091 this.cap = cap; 092 this.join = join; 093 this.miterlimit = miterlimit; 094 if (dash != null) { 095 this.dash = (float[]) dash.clone(); 096 } 097 this.dash_phase = dash_phase; 098 } 099 100 public BasicStroke(float width, int cap, int join, float miterlimit) { 101 this(width, cap, join, miterlimit, null, 0.0f); 102 } 103 104 public BasicStroke(float width, int cap, int join) { 105 this(width, cap, join, 10.0f, null, 0.0f); 106 } 107 108 /** 109 * Constructs a solid <code>BasicStroke</code> with the specified line width 110 * and with default values for the cap and join styles. 111 * 112 * @param width 113 * the width of the <code>BasicStroke</code> 114 * @throws IllegalArgumentException 115 * if <code>width</code> is negative 116 */ 117 public BasicStroke(float width) { 118 this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); 119 } 120 121 /** 122 * Constructs a new <code>BasicStroke</code> with defaults for all 123 * attributes. The default attributes are a solid line of width 1.0, 124 * CAP_SQUARE, JOIN_MITER, a miter limit of 10.0. 125 */ 126 public BasicStroke() { 127 this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); 128 } 129 130 /** 131 * Returns a <code>Shape</code> whose interior defines the stroked outline 132 * of a specified <code>Shape</code>. 133 * 134 * @param s 135 * the <code>Shape</code> boundary be stroked 136 * @return the <code>Shape</code> of the stroked outline. 137 */ 138 public Shape createStrokedShape(Shape s) { 139 /* 140 * sun.java2d.pipe.RenderingEngine re = 141 * sun.java2d.pipe.RenderingEngine.getInstance(); return 142 * re.createStrokedShape(s, width, cap, join, miterlimit, dash, 143 * dash_phase); 144 */ 145 return null; 146 } 147 public Shape createStrokedShape(Polygon poly) { 148 /* 149 * sun.java2d.pipe.RenderingEngine re = 150 * sun.java2d.pipe.RenderingEngine.getInstance(); return 151 * re.createStrokedShape(s, width, cap, join, miterlimit, dash, 152 * dash_phase); 153 */ 154 ArrayList<POINT2>pts=poly.getPathIterator(null).getPoints(); 155 int j=0; 156 GeneralPath gp=new GeneralPath(); 157 POINT2 pt=null; 158 POINT2[]ptsx=new POINT2[pts.size()]; 159 int n=pts.size(); 160 //for(j=0;j<pts.size();j++) 161 for(j=0;j<n;j++) 162 { 163 pt=pts.get(j); 164 ptsx[j]=pt; 165 } 166 167 pts=GetInteriorPoints(ptsx,pts.size(),TacticalLines.DEPTH_AREA,this.width); 168 169 170 //for(j=0;j<pts.size();j++) 171 for(j=0;j<n;j++) 172 { 173 pt=pts.get(j); 174 if(j==0) 175 gp.moveTo(pt.x, pt.y); 176 else 177 gp.lineTo(pt.x, pt.y); 178 } 179 return gp; 180 } 181 182 public float getLineWidth() { 183 return width; 184 } 185 186 /** 187 * Returns the end cap style. 188 * 189 * @return the end cap style of this <code>BasicStroke</code> as one of the 190 * static <code>int</code> values that define possible end cap 191 * styles. 192 */ 193 public int getEndCap() { 194 return cap; 195 } 196 197 public int getLineJoin() { 198 return join; 199 } 200 201 /** 202 * Returns the limit of miter joins. 203 * 204 * @return the limit of miter joins of the <code>BasicStroke</code>. 205 */ 206 public float getMiterLimit() { 207 return miterlimit; 208 } 209 210 /** 211 * Returns the array representing the lengths of the dash segments. 212 * Alternate entries in the array represent the user space lengths of the 213 * opaque and transparent segments of the dashes. As the pen moves along the 214 * outline of the <code>Shape</code> to be stroked, the user space distance 215 * that the pen travels is accumulated. The distance value is used to index 216 * into the dash array. The pen is opaque when its current cumulative 217 * distance maps to an even element of the dash array and transparent 218 * otherwise. 219 * 220 * @return the dash array. 221 */ 222 public float[] getDashArray() { 223 if (dash == null) { 224 return null; 225 } 226 return (float[]) dash.clone(); 227 } 228 229 public float getDashPhase() { 230 return dash_phase; 231 } 232 233 /** 234 * Returns the hashcode for this stroke. 235 * 236 * @return a hash code for this stroke. 237 */ 238 public int hashCode() { 239 int hash = Float.floatToIntBits(width); 240 hash = hash * 31 + join; 241 hash = hash * 31 + cap; 242 hash = hash * 31 + Float.floatToIntBits(miterlimit); 243 if (dash != null) { 244 hash = hash * 31 + Float.floatToIntBits(dash_phase); 245 int n=dash.length; 246 //for (int i = 0; i < dash.length; i++) 247 for (int i = 0; i < n; i++) 248 { 249 hash = hash * 31 + Float.floatToIntBits(dash[i]); 250 } 251 } 252 return hash; 253 } 254 //the Shape interface methods 255 public PathIterator getPathIterator(AffineTransform at) 256 { 257 return null; 258 } 259 public boolean contains (int x, int y) 260 { 261 return false; 262 } 263 public boolean contains (int x, int y, int width, int height) 264 { 265 return false; 266 } 267 public boolean contains (Point2D pt) 268 { 269 return false; 270 } 271 public Rectangle2D getBounds2D() 272 { 273 return null; 274 } 275 public Rectangle getBounds() 276 { 277 return null; 278 } 279 public boolean intersects(double x, double y, double w, double h) 280 { 281 return false; 282 } 283 public boolean intersects(Rectangle2D rect) 284 { 285 return false; 286 } 287 288 public static ArrayList<POINT2> GetInteriorPoints(POINT2[] pLinePoints, 289 int vblCounter, 290 int lineType, 291 double dist) { 292 //var j:int=0; 293 int j = 0; 294 //var index:int=-1; 295 int index = -1; 296 //var pt0:POINT2,pt1:POINT2,pt2:POINT2; 297 POINT2 pt0 = null, pt1 = null, pt2 = null; 298 ///var m01:refobj=new refobj(),m12:refobj=new refobj(); //slopes for lines pt0-pt1 and pt1-pt2 299 ref<double[]> m01 = new ref(), m12 = new ref(), m1 = new ref(), m2 = new ref(); 300 //var direction:int=-1; 301 int direction = -1; 302 //var array:Array=new Array(); 303 //ArrayList<POINT2>array=new ArrayList(); 304 //var intersectPt:POINT2=null; 305 POINT2 intersectPt = null; 306 //var m1:refobj=new refobj(),m2:refobj=new refobj(); 307 //var intersectPoints:Array=new Array(); 308 ArrayList<POINT2> intersectPoints = new ArrayList(); 309 //var b01:Number,b12:Number; //the y intercepts for the lines corresponding to m1,m2 310 double b01 = 0, b12 = 0; 311 //var dist:Number=10; 312 //double dist = 10; 313 //the first set of interior points 314 //this assumes the area is closed 315 for (j = 0; j < vblCounter; j++) { 316 317 if (j == 0 || j == vblCounter - 1) { 318 //pt0=new POINT2(pLinePoints[vblCounter-2]); 319 //pt1=new POINT2(pLinePoints[0]); 320 //pt2=new POINT2(pLinePoints[1]); 321 pt0 = pLinePoints[vblCounter - 2]; 322 pt1 = pLinePoints[0]; 323 pt2 = pLinePoints[1]; 324 } else { 325 //pt0=new POINT2(pLinePoints[j-1]); 326 //pt1=new POINT2(pLinePoints[j]); 327 //pt2=new POINT2(pLinePoints[j+1]); 328 pt0 = pLinePoints[j - 1]; 329 pt1 = pLinePoints[j]; 330 pt2 = pLinePoints[j+1]; 331 } 332 333 //the interiior points 334 //var pt00:POINT2,pt01:POINT2; 335 //var pt10:POINT2,pt11:POINT2; 336 POINT2 pt00 = null, pt01 = null; 337 POINT2 pt10 = null, pt11 = null; 338 339 index = j - 1; 340 if (index < 0) { 341 index = vblCounter - 1; 342 } 343 344 direction = arraysupport.GetInsideOutsideDouble2(pt0, pt1, pLinePoints, vblCounter, index, lineType); 345 //reverse the directions since these are interior points 346 //pt00-pt01 will be the interior line inside line pt0-pt1 347 //pt00 is inside pt0, pt01 is inside pt1 348 switch (direction) { 349 case 0: 350 //direction=1; 351 pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 1, dist); 352 pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 1, dist); 353 break; 354 case 1: 355 //direction=0; 356 pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 0, dist); 357 pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 0, dist); 358 break; 359 case 2: 360 //direction=3; 361 pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 3, dist); 362 pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 3, dist); 363 break; 364 case 3: 365 //direction=2; 366 pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 2, dist); 367 pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 2, dist); 368 break; 369 } 370 371 //pt10-pt11 will be the interior line inside line pt1-pt2 372 //pt10 is inside pt1, pt11 is inside pt2 373 index = j; 374 if (j == vblCounter - 1) { 375 index = 0; 376 } 377 direction = arraysupport.GetInsideOutsideDouble2(pt1, pt2, pLinePoints, vblCounter, index, lineType); 378 //reverse the directions since these are interior points 379 switch (direction) { 380 case 0: 381 //direction=1; 382 pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 1, dist); 383 pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 1, dist); 384 break; 385 case 1: 386 //direction=0; 387 pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 0, dist); 388 pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 0, dist); 389 break; 390 case 2: 391 //direction=3; 392 pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 3, dist); 393 pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 3, dist); 394 break; 395 case 3: 396 //direction=2; 397 pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 2, dist); 398 pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 2, dist); 399 break; 400 } //end switch 401 //intersectPt=new POINT2(null); 402 //get the intersection of pt01-p00 and pt10-pt11 403 //so it it is the interior intersection of pt0-pt1 and pt1-pt2 404 405 //first handle the case of vertical lines. 406 if (pt0.x == pt1.x && pt1.x == pt2.x) { 407 intersectPt = new POINT2(pt01); 408 intersectPoints.add(intersectPt); 409 continue; 410 } 411 //it's the same situation if the slopes are identical, 412 //simply use pt01 or pt10 since they already uniquely define the intesection 413 lineutility.CalcTrueSlopeDouble2(pt00, pt01, m01); 414 lineutility.CalcTrueSlopeDouble2(pt10, pt11, m12); 415 if (m01.value[0] == m12.value[0]) { 416 intersectPt = new POINT2(pt01); 417 intersectPoints.add(intersectPt); 418 continue; 419 } 420 //now we are assuming a non-trivial intersection 421 //calculate the y-intercepts using y=mx+b (use b=y-mx) 422 b01 = pt01.y - m01.value[0] * pt01.x; 423 b12 = pt11.y - m12.value[0] * pt11.x; 424 425 intersectPt = lineutility.CalcTrueIntersectDouble2(m01.value[0], b01, m12.value[0], b12, 1, 1, 0, 0); 426 intersectPoints.add(intersectPt); 427 }//end for 428 return intersectPoints; 429 } 430}