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