001/* 002 * A class to create renderables for the ShapeInfo from the GeneralPath 003 * This class is used for the GoogleEarth Renderer 004 * To change this template, choose Tools | Templates 005 * and open the template in the editor. 006 */ 007 008package armyc2.c5isr.RenderMultipoints; 009import armyc2.c5isr.JavaTacticalRenderer.TGLight; 010import armyc2.c5isr.JavaLineArray.TacticalLines; 011import java.util.ArrayList; 012import java.util.Arrays; 013 014import armyc2.c5isr.JavaLineArray.Shape2; 015import armyc2.c5isr.JavaLineArray.lineutility; 016import armyc2.c5isr.renderer.utilities.ErrorLogger; 017import armyc2.c5isr.renderer.utilities.RendererException; 018import armyc2.c5isr.renderer.utilities.ShapeInfo; 019import armyc2.c5isr.JavaLineArray.POINT2; 020import static armyc2.c5isr.JavaLineArray.lineutility.CalcDistanceDouble; 021 022import armyc2.c5isr.JavaTacticalRenderer.clsMETOC; 023import armyc2.c5isr.renderer.utilities.Color; 024import armyc2.c5isr.renderer.utilities.RendererSettings; 025import armyc2.c5isr.graphics2d.Area; 026import armyc2.c5isr.graphics2d.BasicStroke; 027import armyc2.c5isr.graphics2d.Line2D; 028import armyc2.c5isr.graphics2d.PathIterator; 029import armyc2.c5isr.graphics2d.Point2D; 030import armyc2.c5isr.graphics2d.Polygon; 031import armyc2.c5isr.graphics2d.Rectangle; 032import armyc2.c5isr.graphics2d.Rectangle2D; 033import armyc2.c5isr.graphics2d.Shape; 034 035/** 036 * Utilities require for GoogleEarth functionality 037* 038 */ 039public final class clsUtilityGE { 040 private static final String _className="clsUtilityGE"; 041 protected static void setSplineLinetype(TGLight tg) 042 { 043 switch(tg.get_LineType()) 044 { 045 case TacticalLines.BRDGHD: 046 tg.set_LineType(TacticalLines.BRDGHD_GE); 047 break; 048 case TacticalLines.HOLD: 049 tg.set_LineType(TacticalLines.HOLD_GE); 050 break; 051 case TacticalLines.ICE_OPENINGS_FROZEN: 052 tg.set_LineType(TacticalLines.ICE_OPENINGS_FROZEN_GE); 053 break; 054 case TacticalLines.ICE_OPENINGS_LEAD: 055 tg.set_LineType(TacticalLines.ICE_OPENINGS_LEAD_GE); 056 break; 057 case TacticalLines.ICE_EDGE_RADAR: 058 tg.set_LineType(TacticalLines.ICE_EDGE_RADAR_GE); 059 break; 060 case TacticalLines.CRACKS_SPECIFIC_LOCATION: 061 tg.set_LineType(TacticalLines.CRACKS_SPECIFIC_LOCATION_GE); 062 break; 063 case TacticalLines.JET: 064 tg.set_LineType(TacticalLines.JET_GE); 065 break; 066 case TacticalLines.STREAM: 067 tg.set_LineType(TacticalLines.STREAM_GE); 068 break; 069 case TacticalLines.FLOOD_TIDE: 070 tg.set_LineType(TacticalLines.FLOOD_TIDE_GE); 071 break; 072 case TacticalLines.EBB_TIDE: 073 tg.set_LineType(TacticalLines.EBB_TIDE_GE); 074 break; 075 case TacticalLines.SEAWALL: 076 tg.set_LineType(TacticalLines.SEAWALL_GE); 077 break; 078 case TacticalLines.JETTY_BELOW_WATER: 079 tg.set_LineType(TacticalLines.JETTY_BELOW_WATER_GE); 080 break; 081 case TacticalLines.JETTY_ABOVE_WATER: 082 tg.set_LineType(TacticalLines.JETTY_ABOVE_WATER_GE); 083 break; 084 case TacticalLines.RAMP_BELOW_WATER: 085 tg.set_LineType(TacticalLines.RAMP_BELOW_WATER_GE); 086 break; 087 case TacticalLines.RAMP_ABOVE_WATER: 088 tg.set_LineType(TacticalLines.RAMP_ABOVE_WATER_GE); 089 break; 090 case TacticalLines.PIER: 091 tg.set_LineType(TacticalLines.PIER_GE); 092 break; 093 case TacticalLines.COASTLINE: 094 tg.set_LineType(TacticalLines.COASTLINE_GE); 095 break; 096 case TacticalLines.DEPTH_CONTOUR: 097 tg.set_LineType(TacticalLines.DEPTH_CONTOUR_GE); 098 break; 099 case TacticalLines.DEPTH_CURVE: 100 tg.set_LineType(TacticalLines.DEPTH_CURVE_GE); 101 break; 102 case TacticalLines.CRACKS: 103 tg.set_LineType(TacticalLines.CRACKS_GE); 104 break; 105 case TacticalLines.ESTIMATED_ICE_EDGE: 106 tg.set_LineType(TacticalLines.ESTIMATED_ICE_EDGE_GE); 107 break; 108 case TacticalLines.ICE_EDGE: 109 tg.set_LineType(TacticalLines.ICE_EDGE_GE); 110 break; 111 case TacticalLines.ISOTHERM: 112 tg.set_LineType(TacticalLines.ISOTHERM_GE); 113 break; 114 case TacticalLines.UPPER_AIR: 115 tg.set_LineType(TacticalLines.UPPER_AIR_GE); 116 break; 117 case TacticalLines.ISOBAR: 118 tg.set_LineType(TacticalLines.ISOBAR_GE); 119 break; 120 case TacticalLines.ISODROSOTHERM: 121 tg.set_LineType(TacticalLines.ISODROSOTHERM_GE); 122 break; 123 case TacticalLines.ISOTACH: 124 tg.set_LineType(TacticalLines.ISOTACH_GE); 125 break; 126 case TacticalLines.ISOPLETHS: 127 tg.set_LineType(TacticalLines.ISOPLETHS_GE); 128 break; 129 default: 130 break; 131 } 132 return; 133 } 134 135 /** 136 * GE has no capability for dashed lines. This function sets each polyline in the array as a new 137 * polyline broken into points corresponding to the dash pattern 138 * @param polylines 139 * @param shape 140 */ 141 private static void createDashedPolylines(ArrayList<ArrayList<Point2D>>polylines, ShapeInfo shape) { 142 try { 143 if (shape.getLineColor() == null) { 144 return; 145 } 146 147 BasicStroke stroke = shape.getStroke(); 148 float[] dash = stroke.getDashArray(); 149 if (dash == null || dash.length < 2) { 150 return; 151 } 152 153 ArrayList<ArrayList<Point2D>> dashedPolylines = new ArrayList<>(); 154 155 for (ArrayList<Point2D> polyline : polylines) { 156 int dashIndex = 0; // Current index in dash array 157 double remainingInIndex = dash[dashIndex]; // Length remaining in current dash array index 158 for (int i = 0; i < polyline.size() - 1; i++) { 159 Point2D segStartPt = polyline.get(i); // segment start, moves as segment is processed 160 final Point2D segEndPt = polyline.get(i + 1); // Segment end 161 162 double segLength; // distance remaining in segment 163 while ((segLength = lineutility.CalcDistanceDouble(segStartPt, segEndPt)) > 0) { 164 // If the line segment length is shorter than the current dash then move to the end of the segment continuing to draw or move 165 // Otherwise move to the end of the current dash and start the next dash there 166 if (segLength < remainingInIndex) { 167 if (dashIndex % 2 == 0) { 168 // Continue line 169 ArrayList<Point2D> dashedPolyline = new ArrayList<>(Arrays.asList(segStartPt, segEndPt)); 170 dashedPolylines.add(dashedPolyline); 171 } 172 remainingInIndex -= segLength; 173 break; // Next segment 174 } else { 175 // Flip to line or space at dashFlipPoint 176 Point2D dashFlipPoint = lineutility.ExtendAlongLineDouble2(segStartPt, segEndPt, remainingInIndex); 177 if (dashIndex % 2 == 0) { 178 // Continue line 179 ArrayList<Point2D> dashedPolyline = new ArrayList<>(Arrays.asList(segStartPt, dashFlipPoint)); 180 dashedPolylines.add(dashedPolyline); 181 } 182 // Next dash 183 dashIndex++; 184 if (dashIndex >= dash.length) 185 dashIndex = 0; 186 remainingInIndex = dash[dashIndex]; 187 segStartPt = dashFlipPoint; 188 } 189 } 190 } 191 } 192 polylines.clear(); 193 polylines.addAll(dashedPolylines); 194 } catch (Exception exc) { 195 ErrorLogger.LogException(_className, "createDashedPolylines", 196 new RendererException("Failed inside createDashedPolylines", exc)); 197 } 198 } 199 private static ShapeInfo createSimpleFillShape(TGLight tg,ShapeInfo shape,ArrayList<ArrayList<Point2D>>polylines) 200 { 201 try 202 { 203 BasicStroke s=shape.getStroke(); 204 float[]dash=s.getDashArray(); 205 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType())==false) 206 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(tg.get_LineType())==false) 207 return null; 208 if(dash==null || dash.length<2) 209 return null; 210 if(shape.getFillColor()==null) 211 return null; 212 213 //if we reach this point we know it is a dashed line so we need a separate fill shape 214 int j=0,k=0; 215 ShapeInfo shape2=new ShapeInfo(shape.getShape()); 216 shape2.setShapeType(ShapeInfo.SHAPE_TYPE_FILL); 217 ArrayList<ArrayList<Point2D>>polylines2=new ArrayList(); 218 ArrayList<Point2D>polyline=null,polyline2=null; 219 Point2D pt2d=null; 220 s=new BasicStroke(0); 221 shape2.setStroke(s); 222 shape2.setFillColor(shape.getFillColor()); 223 int n=polylines.size(); 224 //for(j=0;j<polylines.size();j++) 225 for(j=0;j<n;j++) 226 { 227 polyline=polylines.get(j); 228 polyline2=new ArrayList(); 229 int t=polyline.size(); 230 //for(k=0;k<polyline.size();k++) 231 for(k=0;k<t;k++) 232 { 233 pt2d=new Point2D.Double(polyline.get(k).getX(),polyline.get(k).getY()); 234 polyline2.add(pt2d); 235 } 236 polylines2.add(polyline2); 237 } 238 //reset our original dashed shapinfo type to polyline 239 shape.setShapeType(ShapeInfo.SHAPE_TYPE_POLYLINE); 240 //this line will prevent unecessary work by multipointhandler 241 shape.setFillColor(null); 242 shape2.setPolylines(polylines2); 243// shape2.setAffineTransform(new AffineTransform()); 244 return shape2; 245 } 246 catch (Exception exc) { 247 ErrorLogger.LogException(_className, "createSimpleFillShape", 248 new RendererException("Failed inside createSimpleFillShape", exc)); 249 } 250 return null; 251 } 252 private static ShapeInfo createSimplePatternFillShape(TGLight tg,ShapeInfo shape,ArrayList<ArrayList<Point2D>>polylines) 253 { 254 try 255 { 256 BasicStroke s=shape.getStroke(); 257 float[]dash=s.getDashArray(); 258 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType())==false) 259 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(tg.get_LineType())==false) 260 return null; 261 if(dash==null || dash.length<2) 262 return null; 263 if(shape.getPatternFillImage()==null) 264 return null; 265 266 //if we reach this point we know it is a dashed line so we need a separate pattern fill shape 267 int j=0,k=0; 268 ShapeInfo shape2=new ShapeInfo(shape.getShape()); 269 shape2.setShapeType(ShapeInfo.SHAPE_TYPE_FILL); 270 ArrayList<ArrayList<Point2D>>polylines2=new ArrayList(); 271 ArrayList<Point2D>polyline=null,polyline2=null; 272 Point2D pt2d=null; 273 s=new BasicStroke(0); 274 shape2.setStroke(s); 275 shape2.setPatternFillImage(shape.getPatternFillImage()); 276 shape2.setShader(shape.getShader()); 277 int n=polylines.size(); 278 //for(j=0;j<polylines.size();j++) 279 for(j=0;j<n;j++) 280 { 281 polyline=polylines.get(j); 282 polyline2=new ArrayList(); 283 int t=polyline.size(); 284 //for(k=0;k<polyline.size();k++) 285 for(k=0;k<t;k++) 286 { 287 pt2d=new Point2D.Double(polyline.get(k).getX(),polyline.get(k).getY()); 288 polyline2.add(pt2d); 289 } 290 polylines2.add(polyline2); 291 } 292 //reset our original dashed shapinfo type to polyline 293 shape.setShapeType(ShapeInfo.SHAPE_TYPE_POLYLINE); 294 //this line will prevent unecessary work by multipointhandler 295 shape.setPatternFillImage(null); 296 shape.setShader(null); 297 shape2.setPolylines(polylines2); 298// shape2.setAffineTransform(new AffineTransform()); 299 return shape2; 300 } 301 catch (Exception exc) { 302 ErrorLogger.LogException(_className, "createSimplePatternFillShape", 303 new RendererException("Failed inside createSimplePatternFillShape", exc)); 304 } 305 return null; 306 } 307 private static boolean allowFillForThese(TGLight tg) 308 { 309 try 310 { 311 int linetype=tg.get_LineType(); 312 int bolMETOC=clsMETOC.IsWeather(tg.get_SymbolId()); 313 if(bolMETOC >= 0) 314 return true; 315 316 switch(linetype) 317 { 318 case TacticalLines.CATK: 319 case TacticalLines.CATKBYFIRE: 320 case TacticalLines.AIRAOA: 321 case TacticalLines.AAAAA: 322 case TacticalLines.MAIN: 323 case TacticalLines.SPT: 324 325 case TacticalLines.SARA: 326 case TacticalLines.RANGE_FAN_SECTOR: 327 case TacticalLines.RADAR_SEARCH: 328 case TacticalLines.RANGE_FAN: 329 case TacticalLines.MNFLDFIX: 330 case TacticalLines.TURN: 331 case TacticalLines.MNFLDDIS: 332 //case TacticalLines.OVERHEAD_WIRE: 333 case TacticalLines.EASY: 334 case TacticalLines.ATDITCHC: 335 case TacticalLines.ATDITCHM: 336 case TacticalLines.FERRY: 337 case TacticalLines.BYDIF: 338 case TacticalLines.BYIMP: 339 case TacticalLines.DEPTH_AREA: 340 return true; 341 default: 342 return false; 343 } 344 } 345 catch (Exception exc) { 346 ErrorLogger.LogException(_className, "allowFillForThese", 347 new RendererException("Failed inside allowFillForThese", exc)); 348 } 349 return false; 350 } 351 protected static void SetShapeInfosPolylines(TGLight tg, ArrayList<ShapeInfo> shapeInfos, Object clipBounds) 352 { 353 try 354 { 355 int j=0; 356 Shape shape=null; 357 ShapeInfo shapeInfo=null; 358 ArrayList<ArrayList<Point2D>>polylines=null; 359 int type=-1; 360 ShapeInfo simpleFillShape =null;//diagnostic 361 Boolean isClosed= armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType()); 362 int linetype=tg.get_LineType(); 363 Color fillColor=null; 364 int n=shapeInfos.size(); 365 //for(j=0;j<shapeInfos.size();j++) 366 for(j=0;j<n;j++) 367 { 368 shapeInfo=shapeInfos.get(j); 369 type=shapeInfo.getShapeType(); 370 shape=shapeInfo.getShape(); 371 if(isClosed==false && type != Shape2.SHAPE_TYPE_FILL) 372 polylines=createRenderablesFromShape(tg,shape,type,clipBounds); 373 else 374 polylines=createRenderablesFromShape(tg,shape,type,null); 375 //create a simple fill shape here and change the shape type to SHAPE_TYPE_POLYLINE if it has non-null dash 376 //add the simple fill shape to shapeInfos after the loop 377 if(simpleFillShape==null) 378 simpleFillShape=createSimpleFillShape(tg,shapeInfo,polylines); 379 if(simpleFillShape==null) 380 simpleFillShape=createSimplePatternFillShape(tg,shapeInfo,polylines); 381 382 fillColor=shapeInfo.getFillColor(); 383 //if(simpleFillShape!=null || fillColor != null)//the symbol has a basic fill shape 384 if(simpleFillShape!=null)//the symbol has a basic fill shape 385 if(allowFillForThese(tg)==false) 386 shapeInfo.setFillColor(null); 387 388 if (!tg.get_UseDashArray()) 389 createDashedPolylines(polylines, shapeInfo); 390 391 shapeInfo.setPolylines(polylines); 392 } 393 if(simpleFillShape != null) 394 shapeInfos.add(0,simpleFillShape); 395 } 396 catch (Exception exc) { 397 ErrorLogger.LogException(_className, "SetShapeInfosPolylines", 398 new RendererException("Failed inside SetShapeInfosPolylines", exc)); 399 } 400 } 401 /** 402 * Separates the Shape into separate polylines, eas as an ArrayList of Point2D 403 * @param shape 404 * @return 405 */ 406 private static ArrayList<ArrayList<Point2D>>createRenderablesFromShape(TGLight tg, Shape shape, int shapeType, Object clipArea) 407 { 408 ArrayList<Point2D> ptsPoly=new ArrayList(); 409 ArrayList<ArrayList<Point2D>>polylines2=new ArrayList<ArrayList<Point2D>>(); 410 Point2D ptPoly=null; 411 try 412 { 413 //this is not going to work for splines 414 double[] coords = new double[6]; 415 for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) 416 { 417 int type = i.currentSegment(coords); 418 switch (type) { 419 case PathIterator.SEG_MOVETO: 420 //newshape.moveTo(coords[0], coords[1]); 421 //finalize the last Polyline and add it to the array 422 if(ptsPoly.size()>0) 423 { 424 if(shapeType==ShapeInfo.SHAPE_TYPE_FILL) 425 { 426 if(ptsPoly.get(ptsPoly.size()-1).getX() != ptsPoly.get(0).getX() || 427 ptsPoly.get(ptsPoly.size()-1).getY() != ptsPoly.get(0).getY() ) 428 { 429 Point2D pt2d=new Point2D.Double(ptsPoly.get(0).getX(), ptsPoly.get(0).getY()); 430 ptsPoly.add(pt2d); 431 } 432 } 433 if(ptsPoly.size()>1) 434 polylines2.add(ptsPoly); 435 } 436 //start the ArrayList for next Polyline 437 ptsPoly=new ArrayList(); 438 ptPoly=new Point2D.Double(coords[0], coords[1]); 439 ptsPoly.add(ptPoly); 440 break; 441 case PathIterator.SEG_LINETO: 442 //newshape.lineTo(coords[0], coords[1]); 443 ptPoly=new Point2D.Double(coords[0],coords[1]); 444 ptsPoly.add(ptPoly); 445 break; 446 case PathIterator.SEG_QUADTO: //quadTo was never used 447 //no idea what to do with this 448 //newshape.quadTo(coords[0], coords[1], coords[2], coords[3]); 449 break; 450 case PathIterator.SEG_CUBICTO: //curveTo was used for some METOC's 451 //no idea what to do with these 452 //newshape.curveTo(coords[0], coords[1], coords[2], coords[3], 453 // coords[4], coords[5]); 454 break; 455 case PathIterator.SEG_CLOSE: //closePath was never used 456 //newshape.closePath(); 457 break; 458 } 459 } 460 if(ptsPoly.size()>1) 461 { 462 //add the last line to the ArrayList 463 //if it is a fill shape then the Google Earth linear ring requires the last point be added 464 if(shapeType==ShapeInfo.SHAPE_TYPE_FILL) 465 { 466 if(ptsPoly.get(ptsPoly.size()-1).getX() != ptsPoly.get(0).getX() || 467 ptsPoly.get(ptsPoly.size()-1).getY() != ptsPoly.get(0).getY() ) 468 { 469 Point2D pt2d=new Point2D.Double(ptsPoly.get(0).getX(), ptsPoly.get(0).getY()); 470 ptsPoly.add(pt2d); 471 } 472 } 473 polylines2.add(ptsPoly); 474 } 475 } 476 catch (Exception exc) { 477 ErrorLogger.LogException(_className, "createRenderableFromShape", 478 new RendererException("Failed inside createRenderableFromShape", exc)); 479 } 480 //return newshape; 481 return polylines2; 482 } 483 /** 484 * Assumes a convex polygon for the clipping area. 485 * expand the polygon using pixels and a similar algorithm to what flash renderer does for DEPTH AREA 486 * @param pts clipping area to expand 487 * @param expand pixels expansion 488 * @return 489 */ 490 protected static ArrayList<Point2D>expandPolygon(ArrayList<Point2D>pts, 491 double expand) 492 { 493 ArrayList<Point2D>lgPoly=null; 494 try 495 { 496 int j=0; 497 Point2D[]destPts=null; 498 boolean isClosed=false; 499 if(pts.get(pts.size()-1).getX()==pts.get(0).getX() && pts.get(pts.size()-1).getY()==pts.get(0).getY()) 500 { 501 pts.remove(pts.size()-1); 502 isClosed=true; 503 } 504 ArrayList<POINT2>pts2=clsUtility.Points2DToPOINT2(pts); 505 POINT2 pt0=null,pt1=null,pt2=null,pt3=null; 506 double m=0,m1=0,b=0,b1=0; 507 ArrayList<Line2D>lineSegments=new ArrayList(); 508 //n vertical segments 509 int n=pts2.size(); 510 //for(j=0;j<pts2.size()-1;j++) 511 for(j=0;j<n-1;j++) 512 { 513 pt0=new POINT2(pts2.get(j)); 514 pt1=new POINT2(pts2.get(j+1)); 515 //no vertical segments 516 if(pt0.x==pt1.x) 517 { 518 pt1.x+=1; 519 pts2.set(j+1, pt1); 520 } 521 } 522 POINT2 ptn=pts2.get(pts2.size()-1); 523 pt0=new POINT2(pts2.get(0)); 524 //last segment not vertical 525 if(ptn.x==pt0.x) 526 { 527 ptn.x+=1; 528 pts2.set(pts2.size()-1, ptn); 529 } 530 //close pts2 531 pts2.add(pt0);; 532 533 //POINT2 ptOther=null; 534 //int quadrant=-1,otherQuadrant=-1; 535 Polygon poly=new Polygon(); 536 n=pts2.size(); 537 //for(j=0;j<pts2.size();j++) 538 for(j=0;j<n;j++) 539 poly.addPoint((int)pts2.get(j).x, (int)pts2.get(j).y); 540 541 Line2D lineSegment=null; 542 POINT2 midPt=null; 543 //pts2 is closed 544 n=pts2.size(); 545 //for(j=0;j<pts2.size()-1;j++) 546 for(j=0;j<n-1;j++) 547 { 548 pt0=new POINT2(pts2.get(j)); 549 pt1=new POINT2(pts2.get(j+1)); 550 m=(pt0.y-pt1.y)/(pt0.x-pt1.x); 551 //m1=-1/m; 552 if(Math.abs(m)<1) 553 { 554 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_above, expand); 555 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_above, expand); 556 midPt=lineutility.MidPointDouble(pt2, pt3, 0); 557 //we want the polygon to not contain the extended points 558 if(poly.contains(midPt.x, midPt.y)) 559 { 560 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_below, expand); 561 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_below, expand); 562 } 563 } 564 else 565 { 566 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_left, expand); 567 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_left, expand); 568 midPt=lineutility.MidPointDouble(pt2, pt3, 0); 569 //we want the polygon to not contain the extended points 570 if(poly.contains(midPt.x, midPt.y)) 571 { 572 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_right, expand); 573 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_right, expand); 574 } 575 } 576 lineSegment=new Line2D.Double(pt2.x, pt2.y, pt3.x, pt3.y); 577 lineSegments.add(lineSegment); 578 } 579 //we will intersect the line segments to form an expanded polygon 580 ArrayList<POINT2> expandPts=new ArrayList(); 581 Line2D thisLine=null,nextLine=null; 582 double x1=0,y1=0,x2=0,y2=0,x=0,y=0; 583 int t=lineSegments.size(); 584 //for(j=0;j<lineSegments.size();j++) 585 for(j=0;j<t;j++) 586 { 587 thisLine=lineSegments.get(j); 588 x1=thisLine.getX1(); 589 y1=thisLine.getY1(); 590 x2=thisLine.getX2(); 591 y2=thisLine.getY2(); 592 //thisLine line equation 593 m=(y1-y2)/(x1-x2); 594 b=y1-m*x1; 595 596 if(j==lineSegments.size()-1) 597 nextLine=lineSegments.get(0); 598 else 599 nextLine=lineSegments.get(j+1); 600 601 x1=nextLine.getX1(); 602 y1=nextLine.getY1(); 603 x2=nextLine.getX2(); 604 y2=nextLine.getY2(); 605 //nextLine line equation 606 m1=(y1-y2)/(x1-x2); 607 b1=y1-m1*x1; 608 609 //intersect thisLine with nextLine 610 if(m != m1) 611 { 612 x=(b1-b)/(m-m1); //cannot blow up 613 y=(m*x+b); 614 } 615 else //this should not happen 616 { 617 x=thisLine.getX2(); 618 y=thisLine.getY2(); 619 } 620 expandPts.add(new POINT2(x,y)); 621 } 622 lgPoly=new ArrayList(); 623 t=expandPts.size(); 624 //for(j=0;j<expandPts.size();j++) 625 for(j=0;j<t;j++) 626 lgPoly.add(new Point2D.Double(expandPts.get(j).x, expandPts.get(j).y)); 627 628 //close the aray if the original clipping array if applicable 629 if(isClosed) 630 lgPoly.add( new Point2D.Double( lgPoly.get(0).getX(),lgPoly.get(0).getY() ) ); 631 } 632 catch (Exception exc) 633 { 634 ErrorLogger.LogException(_className, "expandPolygon2", 635 new RendererException("Failed inside expandPolygon2", exc)); 636 } 637 return lgPoly; 638 } 639 /** 640 * use cheap algorithm to expand polygons, works best on regular 4+ sided convex polygons 641 * used primarily for expanding the original clipping areas. After clipping a tactical line against 642 * the expanded clipping area, the original clipping area can be used to drop the clip lines 643 * @param pts points to expand, usually a clipping area 644 * @param expandX X expansion factor, e.g 10% growth would be 1.1 645 * @param expandY Y expansion factor 646 * @return points for the expanded polygon 647 */ 648 protected static ArrayList<Point2D>expandPolygon2(ArrayList<Point2D>pts, 649 double expandX, 650 double expandY) 651 { 652 ArrayList<Point2D>lgPoly=null; 653 try 654 { 655// AffineTransform at=new AffineTransform(); 656// at.setToIdentity(); 657 //get the center of the pts using an average 658 double avgX=0,avgY=0,totalX=0,totalY=0; 659 int j=0; 660 boolean isClosed=false; 661 //open the array, remove the last point if necessary 662 if(pts.get(pts.size()-1).getX()==pts.get(0).getX() && pts.get(pts.size()-1).getY()==pts.get(0).getY()) 663 { 664 pts.remove(pts.size()-1); 665 isClosed=true; 666 } 667 //asumes open array 668 int n=pts.size(); 669 //for(j=0;j<pts.size();j++) 670 for(j=0;j<n;j++) 671 { 672 totalX+=pts.get(j).getX(); 673 totalY+=pts.get(j).getY(); 674 } 675 avgX=totalX/pts.size(); 676 avgY=totalY/pts.size(); 677 Point2D.Double[]srcPts=new Point2D.Double[pts.size()]; 678 //for(j=0;j<pts.size();j++) 679 n=pts.size(); 680 for(j=0;j<n;j++) 681 { 682 srcPts[j]=new Point2D.Double(pts.get(j).getX(),pts.get(j).getY()); 683 } 684 Point2D[]destPts=new Point2D[pts.size()]; 685 //translate the points to crcumscribe 0,0 686// at.translate(-avgY, -avgY);//ideally would be close to 0 687// at.transform(srcPts, 0, destPts, 0, srcPts.length); 688// at.setToIdentity(); 689 //scale the points by 10% 690// at.scale(expandX, expandY); 691// at.transform(destPts, 0, destPts, 0, destPts.length); 692// at.setToIdentity(); 693// at.translate(avgY, avgY); 694// at.transform(destPts, 0, destPts, 0, destPts.length); 695 lgPoly=new ArrayList<Point2D>(); 696 int t=destPts.length; 697 //for(j=0;j<destPts.length;j++) 698 for(j=0;j<t;j++) 699 { 700 lgPoly.add(destPts[j]); 701 } 702 //close the aray if the original clipping array was closed 703 if(isClosed) 704 lgPoly.add(new Point2D.Double(destPts[0].getX(),destPts[0].getY())); 705 } 706 catch (Exception exc) { 707 ErrorLogger.LogException(_className, "expandPolygon", 708 new RendererException("Failed inside expandPolygon", exc)); 709 } 710 return lgPoly; 711 } 712 /** 713 * @deprecated 714 * For tactical lines break up the arraylists into separate arraylists within the bounds. 715 * This was added for the Google Earth 3D map because small scales cut off and we want the clip lines 716 * to not be visible. 717 * @param ptsPoly 718 * @param clipBounds 719 * @return 720 */ 721 private static ArrayList<ArrayList<Point2D>> ptsPolyToPtsPoly(TGLight tg, ArrayList<ArrayList<Point2D>>ptsPoly, 722 Rectangle2D clipBounds) 723 { 724 ArrayList<ArrayList<Point2D>> ptsPoly2=null; 725 try 726 { 727 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(tg.get_LineType())==true) 728 return ptsPoly; 729 730 int j=0,k=0; 731 ArrayList<Point2D>pts=null; 732 ArrayList<Point2D>addPts=null; 733 Point2D pt0=null; 734 Point2D pt1=null; 735 Line2D line=null; 736 ptsPoly2=new ArrayList(); 737 int n=ptsPoly.size(); 738 //for(j=0;j<ptsPoly.size();j++) 739 for(j=0;j<n;j++) 740 { 741 addPts=null; 742 pts=ptsPoly.get(j); 743 //find the first point inside the clipbounds 744 int t=pts.size(); 745 //for(k=0;k<pts.size()-1;k++) 746 for(k=0;k<t-1;k++) 747 { 748 pt0=pts.get(k); 749 pt1=pts.get(k+1); 750 751 line=new Line2D.Double(pt0,pt1); 752 //both points out of bounds, do not add points 753 if(clipBounds.contains(pt0)==false && clipBounds.contains(pt1)==false) 754 { 755 if(clipBounds.intersectsLine(line)==false) 756 { 757 addPts=null; 758 continue; 759 } 760 else 761 { 762 if(addPts==null) 763 { 764 addPts=new ArrayList(); 765 addPts.add(pt0); 766 } 767 if(addPts.contains(pt0)==false) 768 addPts.add(pt0); 769 770 addPts.add(pt1); 771 ptsPoly2.add(addPts); 772 addPts=null; 773 } 774 } 775 else if(clipBounds.contains(pt0)==false && clipBounds.contains(pt1)==true) 776 { 777 if(addPts == null) 778 { 779 addPts=new ArrayList(); 780 addPts.add(pt0); 781 } 782 if(addPts.contains(pt0)==false) 783 addPts.add(pt0); 784 785 addPts.add(pt1); 786 } 787 else if(clipBounds.contains(pt0)==true && clipBounds.contains(pt1)==true) 788 { 789 if(addPts==null) 790 { 791 addPts=new ArrayList(); 792 addPts.add(pt0); 793 } 794 if(addPts.contains(pt0)==false) 795 addPts.add(pt0); 796 797 addPts.add(pt1); 798 } 799 else if(clipBounds.contains(pt0)==true && clipBounds.contains(pt1)==false) 800 { 801 if(addPts==null) 802 { 803 addPts=new ArrayList(); 804 addPts.add(pt0); 805 } 806 if(addPts.contains(pt0)==false) 807 addPts.add(pt0); 808 //end the current polyline 809 //and add it to the array list 810 addPts.add(pt1); 811 ptsPoly2.add(addPts); 812 addPts=null; 813 } 814 } 815 //add the final array list 816 if(addPts != null && addPts.size()>0) 817 ptsPoly2.add(addPts); 818 } 819 } 820 catch (Exception exc) { 821 ErrorLogger.LogException(_className, "ptsPolyToPtsPoly", 822 new RendererException("Failed inside ptsPolyToPtsPoly", exc)); 823 } 824 return ptsPoly2; 825 } 826 /** 827 * @deprecated 828 * function to remove the clip lines from the polygon that was clipped 829 * @param ptsPoly the clipped points array 830 * @param clipBounds the clipping points 831 * @return 832 */ 833 private static ArrayList<ArrayList<Point2D>> ptsPolyToPtsPoly(TGLight tg, ArrayList<ArrayList<Point2D>>ptsPoly, 834 ArrayList<Point2D> clipBounds)//was rectangle2D clipBounds 835 { 836 ArrayList<ArrayList<Point2D>> ptsPoly2=null; 837 try 838 { 839 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(tg.get_LineType())==true) 840 return ptsPoly; 841 842 int j=0,k=0; 843 ArrayList<Point2D>pts=null; 844 ArrayList<Point2D>addPts=null; 845 Point2D pt0=null; 846 Point2D pt1=null; 847 Line2D line=null; 848 ptsPoly2=new ArrayList(); 849 Polygon clipPoly=new Polygon(); 850 851 //ArrayList<Point2D>ptsClipArea=null; 852 int n=clipBounds.size(); 853 //for(j=0;j<clipBounds.size();j++) 854 for(j=0;j<n;j++) 855 { 856 clipPoly.addPoint((int)clipBounds.get(j).getX(), (int)clipBounds.get(j).getY()); 857 } 858 n=ptsPoly.size(); 859 //for(j=0;j<ptsPoly.size();j++) 860 for(j=0;j<n;j++) 861 { 862 addPts=null; 863 pts=ptsPoly.get(j); 864 //find the first point inside the clipbounds 865 int t=pts.size(); 866 //for(k=0;k<pts.size()-1;k++) 867 for(k=0;k<t-1;k++) 868 { 869 pt0=pts.get(k); 870 pt1=pts.get(k+1); 871 line=new Line2D.Double(pt0,pt1); 872 //both points out of bounds, do not add points 873 if(clipPoly.contains(pt0)==false && clipPoly.contains(pt1)==false) 874 { 875 if(lineIntersectsClipArea(line,clipBounds)==false) 876 { 877 addPts=null; 878 continue; 879 } 880 else 881 { 882 if(addPts==null) 883 { 884 addPts=new ArrayList(); 885 addPts.add(pt0); 886 } 887 if(addPts.contains(pt0)==false) 888 addPts.add(pt0); 889 890 addPts.add(pt1); 891 ptsPoly2.add(addPts); 892 addPts=null; 893 } 894 } 895 else if(clipPoly.contains(pt0)==false && clipPoly.contains(pt1)==true) 896 { 897 if(addPts == null) 898 { 899 addPts=new ArrayList(); 900 addPts.add(pt0); 901 } 902 if(addPts.contains(pt0)==false) 903 addPts.add(pt0); 904 905 addPts.add(pt1); 906 } 907 else if(clipPoly.contains(pt0)==true && clipPoly.contains(pt1)==true) 908 { 909 if(addPts==null) 910 { 911 addPts=new ArrayList(); 912 addPts.add(pt0); 913 } 914 if(addPts.contains(pt0)==false) 915 addPts.add(pt0); 916 917 addPts.add(pt1); 918 } 919 else if(clipPoly.contains(pt0)==true && clipPoly.contains(pt1)==false) 920 { 921 if(addPts==null) 922 { 923 addPts=new ArrayList(); 924 addPts.add(pt0); 925 } 926 if(addPts.contains(pt0)==false) 927 addPts.add(pt0); 928 //end the current polyline 929 //and add it to the array list 930 addPts.add(pt1); 931 ptsPoly2.add(addPts); 932 addPts=null; 933 } 934 } 935 //add the final array list 936 if(addPts != null && addPts.size()>0) 937 ptsPoly2.add(addPts); 938 } 939 } 940 catch (Exception exc) { 941 ErrorLogger.LogException(_className, "ptsPolyToPtsPoly", 942 new RendererException("Failed inside ptsPolyToPtsPoly", exc)); 943 } 944 return ptsPoly2; 945 } 946 /** 947 * removes leading or trailing segments after the points were clipped 948 * @param tg 949 * @param clipArea 950 */ 951 protected static void removeTrailingPoints(TGLight tg, Object clipArea) 952 { 953 try 954 { 955 boolean isClosed= armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType()); 956 if(isClosed) 957 return; 958 959 Polygon poly=new Polygon(); 960 Area area=null; 961 Rectangle2D clipBounds=null; 962 ArrayList<Point2D>clipPoints=null; 963 Point2D pt2d=null; 964 int j=0; 965 if(clipArea==null) 966 return; 967 968 if(clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) 969 { 970 clipBounds=(Rectangle2D.Double)clipArea; 971 } 972 else if(clipArea.getClass().isAssignableFrom(Rectangle.class)) 973 { 974 //clipBounds=(Rectangle2D)clipArea; 975 Rectangle rectx=(Rectangle)clipArea; 976 clipBounds=new Rectangle2D.Double(rectx.x,rectx.y,rectx.width,rectx.height); 977 } 978 else if(clipArea.getClass().isAssignableFrom(ArrayList.class)) 979 { 980 clipPoints=(ArrayList<Point2D>)clipArea; 981 } 982 if(clipBounds != null) 983 { 984 clipPoints=new ArrayList<Point2D>(); 985 clipPoints.add(new Point2D.Double(clipBounds.getX(),clipBounds.getY())); 986 clipPoints.add(new Point2D.Double(clipBounds.getX()+clipBounds.getWidth(),clipBounds.getY())); 987 clipPoints.add(new Point2D.Double(clipBounds.getX()+clipBounds.getWidth(),clipBounds.getY()+clipBounds.getHeight())); 988 clipPoints.add(new Point2D.Double(clipBounds.getX(),clipBounds.getY()+clipBounds.getHeight())); 989 clipPoints.add(new Point2D.Double(clipBounds.getX(),clipBounds.getY())); 990 } 991 992 Point2D ptLast=clipPoints.get(clipPoints.size()-1); 993 Point2D pt02d=clipPoints.get(0); 994 Point2D pt12d=null; 995 //close the area 996 if(pt02d.getX() != ptLast.getX() || pt02d.getY() != ptLast.getY()) 997 { 998 clipPoints.add(new Point2D.Double(pt02d.getX(),pt02d.getY())); 999 //poly.addPoint((int)pt02d.getX(),(int)pt02d.getY()); 1000 } 1001 //fill the polygon 1002 int n=clipPoints.size(); 1003 //for(j=0;j<clipPoints.size();j++) 1004 for(j=0;j<n;j++) 1005 { 1006 pt02d=clipPoints.get(j); 1007 poly.addPoint((int)pt02d.getX(), (int)pt02d.getY()); 1008 } 1009 area=new Area(poly); 1010 Line2D line=null; 1011 POINT2 pt0=null,pt1=null; 1012 boolean intersects=false; 1013 int frontIndex=0,backIndex=tg.Pixels.size()-1; 1014 //breaks at the first leading segment that intersects the clip area 1015 n=tg.Pixels.size(); 1016 //for(j=0;j<tg.Pixels.size()-1;j++) 1017 for(j=0;j<n-1;j++) 1018 { 1019 pt0=tg.Pixels.get(j); 1020 pt1=tg.Pixels.get(j+1); 1021 line=new Line2D.Double(pt0.x, pt0.y, pt1.x, pt1.y); 1022 intersects=lineIntersectsClipArea(line, clipPoints); 1023 if(intersects==true) 1024 { 1025 frontIndex=j; 1026 break; 1027 } 1028 else if(area.contains((int)pt0.x,(int)pt0.y) || area.contains((int)pt1.x,(int)pt1.y)) 1029 { 1030 frontIndex=j; 1031 break; 1032 } 1033 } 1034 //breaks at the first trailing segment that intersects the clip area 1035 n=tg.Pixels.size(); 1036 //for(j=tg.Pixels.size()-1;j>0;j--) 1037 for(j=n-1;j>0;j--) 1038 { 1039 pt0=tg.Pixels.get(j); 1040 pt1=tg.Pixels.get(j-1); 1041 line=new Line2D.Double(pt0.x, pt0.y, pt1.x, pt1.y); 1042 intersects=lineIntersectsClipArea(line, clipPoints); 1043 if(intersects==true) 1044 { 1045 backIndex=j; 1046 break; 1047 } 1048 else if(area.contains((int)pt0.x,(int)pt0.y) || area.contains((int)pt1.x,(int)pt1.y)) 1049 { 1050 backIndex=j; 1051 break; 1052 } 1053 } 1054 ArrayList<POINT2>pts=new ArrayList(); 1055 for(j=frontIndex;j<=backIndex;j++) 1056 { 1057 pt0=new POINT2(tg.Pixels.get(j)); 1058 pts.add(pt0); 1059 } 1060 tg.Pixels=pts; 1061 } 1062 catch(Exception exc) 1063 { 1064 ErrorLogger.LogException("clsRenderer" ,"removeTrailingPoints", 1065 new RendererException("Failed inside removeTrailingPoints", exc)); 1066 } 1067 } 1068/** 1069 * tests of a Line2D intersects a polygon by using line.intersectsLine on each segment of the polygon 1070 * assumes clip clipping area was parsed to shift points of vertical segments to make them not vertical 1071 * @param line a clipping line in the clipping polygon 1072 * @param clipPts array of clip points assumed to be closed 1073 * @return true if the line intersects the clip bounds 1074 */ 1075 private static boolean lineIntersectsClipArea(Line2D line, 1076 ArrayList<Point2D> clipPts) 1077 { 1078 boolean result=false; 1079 try 1080 { 1081 int j=0; 1082 1083 //test if polygon contains an end point 1084 Polygon poly=new Polygon(); 1085 int n=clipPts.size(); 1086 //for(j=0;j<clipPts.size();j++) 1087 for(j=0;j<n;j++) 1088 poly.addPoint((int)clipPts.get(j).getX(),(int)clipPts.get(j).getY()); 1089 1090 if(poly.contains(line.getX1(),line.getY1())) 1091 return true; 1092 if(poly.contains(line.getX2(),line.getY2())) 1093 return true; 1094 //end section 1095 1096 Line2D currentSegment=null; 1097 n=clipPts.size(); 1098 //for(j=0;j<clipPts.size()-1;j++) 1099 for(j=0;j<n-1;j++) 1100 { 1101 currentSegment=new Line2D.Double(clipPts.get(j).getX(),clipPts.get(j).getY(),clipPts.get(j+1).getX(),clipPts.get(j+1).getY()); 1102 if(line.intersectsLine(currentSegment)==true) 1103 return true; 1104 } 1105 //if the clipPts are not closed then the above loop did not test the closing segment 1106 Point2D pt0=clipPts.get(0); 1107 Point2D ptLast=clipPts.get(clipPts.size()-1); 1108 //int n=clipPts.size()-1; 1109 if(pt0.getX()!=ptLast.getX() || pt0.getY()!=ptLast.getY()) 1110 { 1111 //currentSegment=new Line2D.Double(clipPts.get(n).getX(),clipPts.get(n).getY(),clipPts.get(0).getX(),clipPts.get(0).getY()); 1112 currentSegment=new Line2D.Double(ptLast.getX(),ptLast.getY(),pt0.getX(),pt0.getY()); 1113 if(line.intersectsLine(currentSegment)==true) 1114 return true; 1115 } 1116 } 1117 catch (Exception exc) { 1118 ErrorLogger.LogException(_className, "lineIntersectsClipArea", 1119 new RendererException("Failed inside lineIntersectsClipArea", exc)); 1120 } 1121 return result; 1122 } 1123 /** 1124 * returns true if segment data set for MSR, ASR, Boundary 1125 * @param tg 1126 * @return 1127 */ 1128 protected static boolean segmentColorsSet(TGLight tg) 1129 { 1130 try 1131 { 1132 switch(tg.get_LineType()) 1133 { 1134 case TacticalLines.BOUNDARY: 1135 case TacticalLines.MSR: 1136 case TacticalLines.ASR: 1137 case TacticalLines.ROUTE: 1138 break; 1139 default: 1140 return false; 1141 } 1142 String strH=tg.get_H(); 1143 if(strH==null || strH.isEmpty()) 1144 return false; 1145 String[] strs=strH.split(","); 1146 if(strs.length>1) 1147 return true; 1148 } 1149 catch(Exception exc) 1150 { 1151 ErrorLogger.LogException(_className, "segmentColorsSet", 1152 new RendererException("Failed inside segmentColorsSet", exc)); 1153 } 1154 return false; 1155 } 1156 /** 1157 * Use clipping rectangle or clip points to build a zoom factor if the client zoomed in after the initial render. 1158 * Multiply the geo segmenting interval by this factor. 1159 * @param rect 1160 * @param clipPoints 1161 * @param pixels 1162 * @return 1163 */ 1164 protected static double getZoomFactor(Rectangle2D rect, ArrayList<Point2D> clipPoints, ArrayList<POINT2>pixels) 1165 { 1166 double factor=-1; 1167 try 1168 { 1169 if(pixels==null || pixels.size()<2) 1170 return factor; 1171 if(clipPoints==null && rect==null) 1172 return factor; 1173 double maxLengthPixels=0, maxLengthClipArea=0,temp=0; 1174 int j=0; 1175 Point2D pt2d0=null,pt2d1=null;POINT2 pt0=null, pt1=null; 1176 for(j=0;j<pixels.size()-1;j++) 1177 { 1178 pt0=pixels.get(j); 1179 pt1=pixels.get(j+1); 1180 temp=lineutility.CalcDistanceDouble(pt0, pt1); 1181 if(temp>maxLengthPixels) 1182 maxLengthPixels=temp; 1183 } 1184 temp=0; 1185 if(clipPoints != null) 1186 { 1187 for(j=0;j<clipPoints.size()-1;j++) 1188 { 1189 pt2d0=clipPoints.get(j); 1190 pt2d1=clipPoints.get(j+1); 1191 pt0=new POINT2(pt2d0.getX(),pt2d0.getY()); 1192 pt1=new POINT2(pt2d1.getX(),pt2d1.getY()); 1193 temp=lineutility.CalcDistanceDouble(pt0, pt1); 1194 } 1195 } 1196 else if(rect != null) 1197 { 1198 temp=rect.getMaxX()-rect.getMinX(); 1199 if(temp < rect.getMaxY()-rect.getMinY()) 1200 temp=rect.getMaxY()-rect.getMinY(); 1201 } 1202 if(temp>maxLengthClipArea) 1203 maxLengthClipArea=temp; 1204 if(maxLengthPixels > 0 && maxLengthClipArea > 0) 1205 factor=maxLengthClipArea/maxLengthPixels; 1206 } 1207 catch(Exception exc) 1208 { 1209 ErrorLogger.LogException(_className, "getZoomFactor", 1210 new RendererException("Failed inside getZoomFactor", exc)); 1211 } 1212 return factor; 1213 } 1214 1215}