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.BBS_AREA: 319 case TacticalLines.BBS_RECTANGLE: 320 321 case TacticalLines.CATK: 322 case TacticalLines.CATKBYFIRE: 323 case TacticalLines.AIRAOA: 324 case TacticalLines.AAAAA: 325 case TacticalLines.MAIN: 326 case TacticalLines.SPT: 327 case TacticalLines.FRONTAL_ATTACK: 328 case TacticalLines.TURNING_MOVEMENT: 329 case TacticalLines.MOVEMENT_TO_CONTACT: 330 331 case TacticalLines.SARA: 332 case TacticalLines.RANGE_FAN_SECTOR: 333 case TacticalLines.RADAR_SEARCH: 334 case TacticalLines.RANGE_FAN: 335 case TacticalLines.MNFLDFIX: 336 case TacticalLines.TURN_REVD: 337 case TacticalLines.TURN: 338 case TacticalLines.MNFLDDIS: 339 //case TacticalLines.OVERHEAD_WIRE: 340 case TacticalLines.EASY: 341 case TacticalLines.ATDITCHC: 342 case TacticalLines.ATDITCHM: 343 case TacticalLines.FERRY: 344 case TacticalLines.BYDIF: 345 case TacticalLines.BYIMP: 346 case TacticalLines.DEPTH_AREA: 347 return true; 348 default: 349 return false; 350 } 351 } 352 catch (Exception exc) { 353 ErrorLogger.LogException(_className, "allowFillForThese", 354 new RendererException("Failed inside allowFillForThese", exc)); 355 } 356 return false; 357 } 358 protected static void SetShapeInfosPolylines(TGLight tg, ArrayList<ShapeInfo> shapeInfos, Object clipBounds) 359 { 360 try 361 { 362 int j=0; 363 Shape shape=null; 364 ShapeInfo shapeInfo=null; 365 ArrayList<ArrayList<Point2D>>polylines=null; 366 int type=-1; 367 ShapeInfo simpleFillShape =null;//diagnostic 368 Boolean isClosed= armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType()); 369 int linetype=tg.get_LineType(); 370 Color fillColor=null; 371 int n=shapeInfos.size(); 372 //for(j=0;j<shapeInfos.size();j++) 373 for(j=0;j<n;j++) 374 { 375 shapeInfo=shapeInfos.get(j); 376 type=shapeInfo.getShapeType(); 377 shape=shapeInfo.getShape(); 378 if(isClosed==false && type != Shape2.SHAPE_TYPE_FILL) 379 polylines=createRenderablesFromShape(tg,shape,type,clipBounds); 380 else 381 polylines=createRenderablesFromShape(tg,shape,type,null); 382 //create a simple fill shape here and change the shape type to SHAPE_TYPE_POLYLINE if it has non-null dash 383 //add the simple fill shape to shapeInfos after the loop 384 if(simpleFillShape==null) 385 simpleFillShape=createSimpleFillShape(tg,shapeInfo,polylines); 386 if(simpleFillShape==null) 387 simpleFillShape=createSimplePatternFillShape(tg,shapeInfo,polylines); 388 389 fillColor=shapeInfo.getFillColor(); 390 //if(simpleFillShape!=null || fillColor != null)//the symbol has a basic fill shape 391 if(simpleFillShape!=null)//the symbol has a basic fill shape 392 if(allowFillForThese(tg)==false) 393 shapeInfo.setFillColor(null); 394 395 if (!tg.get_UseDashArray()) 396 createDashedPolylines(polylines, shapeInfo); 397 398 shapeInfo.setPolylines(polylines); 399 } 400 if(simpleFillShape != null) 401 shapeInfos.add(0,simpleFillShape); 402 } 403 catch (Exception exc) { 404 ErrorLogger.LogException(_className, "SetShapeInfosPolylines", 405 new RendererException("Failed inside SetShapeInfosPolylines", exc)); 406 } 407 } 408 /** 409 * Separates the Shape into separate polylines, eas as an ArrayList of Point2D 410 * @param shape 411 * @return 412 */ 413 private static ArrayList<ArrayList<Point2D>>createRenderablesFromShape(TGLight tg, Shape shape, int shapeType, Object clipArea) 414 { 415 ArrayList<Point2D> ptsPoly=new ArrayList(); 416 ArrayList<ArrayList<Point2D>>polylines2=new ArrayList<ArrayList<Point2D>>(); 417 Point2D ptPoly=null; 418 try 419 { 420 //this is not going to work for splines 421 double[] coords = new double[6]; 422 for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) 423 { 424 int type = i.currentSegment(coords); 425 switch (type) { 426 case PathIterator.SEG_MOVETO: 427 //newshape.moveTo(coords[0], coords[1]); 428 //finalize the last Polyline and add it to the array 429 if(ptsPoly.size()>0) 430 { 431 if(shapeType==ShapeInfo.SHAPE_TYPE_FILL) 432 { 433 if(ptsPoly.get(ptsPoly.size()-1).getX() != ptsPoly.get(0).getX() || 434 ptsPoly.get(ptsPoly.size()-1).getY() != ptsPoly.get(0).getY() ) 435 { 436 Point2D pt2d=new Point2D.Double(ptsPoly.get(0).getX(), ptsPoly.get(0).getY()); 437 ptsPoly.add(pt2d); 438 } 439 } 440 if(ptsPoly.size()>1) 441 polylines2.add(ptsPoly); 442 } 443 //start the ArrayList for next Polyline 444 ptsPoly=new ArrayList(); 445 ptPoly=new Point2D.Double(coords[0], coords[1]); 446 ptsPoly.add(ptPoly); 447 break; 448 case PathIterator.SEG_LINETO: 449 //newshape.lineTo(coords[0], coords[1]); 450 ptPoly=new Point2D.Double(coords[0],coords[1]); 451 ptsPoly.add(ptPoly); 452 break; 453 case PathIterator.SEG_QUADTO: //quadTo was never used 454 //no idea what to do with this 455 //newshape.quadTo(coords[0], coords[1], coords[2], coords[3]); 456 break; 457 case PathIterator.SEG_CUBICTO: //curveTo was used for some METOC's 458 //no idea what to do with these 459 //newshape.curveTo(coords[0], coords[1], coords[2], coords[3], 460 // coords[4], coords[5]); 461 break; 462 case PathIterator.SEG_CLOSE: //closePath was never used 463 //newshape.closePath(); 464 break; 465 } 466 } 467 if(ptsPoly.size()>1) 468 { 469 //add the last line to the ArrayList 470 //if it is a fill shape then the Google Earth linear ring requires the last point be added 471 if(shapeType==ShapeInfo.SHAPE_TYPE_FILL) 472 { 473 if(ptsPoly.get(ptsPoly.size()-1).getX() != ptsPoly.get(0).getX() || 474 ptsPoly.get(ptsPoly.size()-1).getY() != ptsPoly.get(0).getY() ) 475 { 476 Point2D pt2d=new Point2D.Double(ptsPoly.get(0).getX(), ptsPoly.get(0).getY()); 477 ptsPoly.add(pt2d); 478 } 479 } 480 polylines2.add(ptsPoly); 481 } 482 } 483 catch (Exception exc) { 484 ErrorLogger.LogException(_className, "createRenderableFromShape", 485 new RendererException("Failed inside createRenderableFromShape", exc)); 486 } 487 //return newshape; 488 return polylines2; 489 } 490 /** 491 * Assumes a convex polygon for the clipping area. 492 * expand the polygon using pixels and a similar algorithm to what flash renderer does for DEPTH AREA 493 * @param pts clipping area to expand 494 * @param expand pixels expansion 495 * @return 496 */ 497 protected static ArrayList<Point2D>expandPolygon(ArrayList<Point2D>pts, 498 double expand) 499 { 500 ArrayList<Point2D>lgPoly=null; 501 try 502 { 503 int j=0; 504 Point2D[]destPts=null; 505 boolean isClosed=false; 506 if(pts.get(pts.size()-1).getX()==pts.get(0).getX() && pts.get(pts.size()-1).getY()==pts.get(0).getY()) 507 { 508 pts.remove(pts.size()-1); 509 isClosed=true; 510 } 511 ArrayList<POINT2>pts2=clsUtility.Points2DToPOINT2(pts); 512 POINT2 pt0=null,pt1=null,pt2=null,pt3=null; 513 double m=0,m1=0,b=0,b1=0; 514 ArrayList<Line2D>lineSegments=new ArrayList(); 515 //n vertical segments 516 int n=pts2.size(); 517 //for(j=0;j<pts2.size()-1;j++) 518 for(j=0;j<n-1;j++) 519 { 520 pt0=new POINT2(pts2.get(j)); 521 pt1=new POINT2(pts2.get(j+1)); 522 //no vertical segments 523 if(pt0.x==pt1.x) 524 { 525 pt1.x+=1; 526 pts2.set(j+1, pt1); 527 } 528 } 529 POINT2 ptn=pts2.get(pts2.size()-1); 530 pt0=new POINT2(pts2.get(0)); 531 //last segment not vertical 532 if(ptn.x==pt0.x) 533 { 534 ptn.x+=1; 535 pts2.set(pts2.size()-1, ptn); 536 } 537 //close pts2 538 pts2.add(pt0);; 539 540 //POINT2 ptOther=null; 541 //int quadrant=-1,otherQuadrant=-1; 542 Polygon poly=new Polygon(); 543 n=pts2.size(); 544 //for(j=0;j<pts2.size();j++) 545 for(j=0;j<n;j++) 546 poly.addPoint((int)pts2.get(j).x, (int)pts2.get(j).y); 547 548 Line2D lineSegment=null; 549 POINT2 midPt=null; 550 //pts2 is closed 551 n=pts2.size(); 552 //for(j=0;j<pts2.size()-1;j++) 553 for(j=0;j<n-1;j++) 554 { 555 pt0=new POINT2(pts2.get(j)); 556 pt1=new POINT2(pts2.get(j+1)); 557 m=(pt0.y-pt1.y)/(pt0.x-pt1.x); 558 //m1=-1/m; 559 if(Math.abs(m)<1) 560 { 561 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_above, expand); 562 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_above, expand); 563 midPt=lineutility.MidPointDouble(pt2, pt3, 0); 564 //we want the polygon to not contain the extended points 565 if(poly.contains(midPt.x, midPt.y)) 566 { 567 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_below, expand); 568 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_below, expand); 569 } 570 } 571 else 572 { 573 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_left, expand); 574 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_left, expand); 575 midPt=lineutility.MidPointDouble(pt2, pt3, 0); 576 //we want the polygon to not contain the extended points 577 if(poly.contains(midPt.x, midPt.y)) 578 { 579 pt2=lineutility.ExtendDirectedLine(pt0, pt1, pt0, lineutility.extend_right, expand); 580 pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt1, lineutility.extend_right, expand); 581 } 582 } 583 lineSegment=new Line2D.Double(pt2.x, pt2.y, pt3.x, pt3.y); 584 lineSegments.add(lineSegment); 585 } 586 //we will intersect the line segments to form an expanded polygon 587 ArrayList<POINT2> expandPts=new ArrayList(); 588 Line2D thisLine=null,nextLine=null; 589 double x1=0,y1=0,x2=0,y2=0,x=0,y=0; 590 int t=lineSegments.size(); 591 //for(j=0;j<lineSegments.size();j++) 592 for(j=0;j<t;j++) 593 { 594 thisLine=lineSegments.get(j); 595 x1=thisLine.getX1(); 596 y1=thisLine.getY1(); 597 x2=thisLine.getX2(); 598 y2=thisLine.getY2(); 599 //thisLine line equation 600 m=(y1-y2)/(x1-x2); 601 b=y1-m*x1; 602 603 if(j==lineSegments.size()-1) 604 nextLine=lineSegments.get(0); 605 else 606 nextLine=lineSegments.get(j+1); 607 608 x1=nextLine.getX1(); 609 y1=nextLine.getY1(); 610 x2=nextLine.getX2(); 611 y2=nextLine.getY2(); 612 //nextLine line equation 613 m1=(y1-y2)/(x1-x2); 614 b1=y1-m1*x1; 615 616 //intersect thisLine with nextLine 617 if(m != m1) 618 { 619 x=(b1-b)/(m-m1); //cannot blow up 620 y=(m*x+b); 621 } 622 else //this should not happen 623 { 624 x=thisLine.getX2(); 625 y=thisLine.getY2(); 626 } 627 expandPts.add(new POINT2(x,y)); 628 } 629 lgPoly=new ArrayList(); 630 t=expandPts.size(); 631 //for(j=0;j<expandPts.size();j++) 632 for(j=0;j<t;j++) 633 lgPoly.add(new Point2D.Double(expandPts.get(j).x, expandPts.get(j).y)); 634 635 //close the aray if the original clipping array if applicable 636 if(isClosed) 637 lgPoly.add( new Point2D.Double( lgPoly.get(0).getX(),lgPoly.get(0).getY() ) ); 638 } 639 catch (Exception exc) 640 { 641 ErrorLogger.LogException(_className, "expandPolygon2", 642 new RendererException("Failed inside expandPolygon2", exc)); 643 } 644 return lgPoly; 645 } 646 /** 647 * use cheap algorithm to expand polygons, works best on regular 4+ sided convex polygons 648 * used primarily for expanding the original clipping areas. After clipping a tactical line against 649 * the expanded clipping area, the original clipping area can be used to drop the clip lines 650 * @param pts points to expand, usually a clipping area 651 * @param expandX X expansion factor, e.g 10% growth would be 1.1 652 * @param expandY Y expansion factor 653 * @return points for the expanded polygon 654 */ 655 protected static ArrayList<Point2D>expandPolygon2(ArrayList<Point2D>pts, 656 double expandX, 657 double expandY) 658 { 659 ArrayList<Point2D>lgPoly=null; 660 try 661 { 662// AffineTransform at=new AffineTransform(); 663// at.setToIdentity(); 664 //get the center of the pts using an average 665 double avgX=0,avgY=0,totalX=0,totalY=0; 666 int j=0; 667 boolean isClosed=false; 668 //open the array, remove the last point if necessary 669 if(pts.get(pts.size()-1).getX()==pts.get(0).getX() && pts.get(pts.size()-1).getY()==pts.get(0).getY()) 670 { 671 pts.remove(pts.size()-1); 672 isClosed=true; 673 } 674 //asumes open array 675 int n=pts.size(); 676 //for(j=0;j<pts.size();j++) 677 for(j=0;j<n;j++) 678 { 679 totalX+=pts.get(j).getX(); 680 totalY+=pts.get(j).getY(); 681 } 682 avgX=totalX/pts.size(); 683 avgY=totalY/pts.size(); 684 Point2D.Double[]srcPts=new Point2D.Double[pts.size()]; 685 //for(j=0;j<pts.size();j++) 686 n=pts.size(); 687 for(j=0;j<n;j++) 688 { 689 srcPts[j]=new Point2D.Double(pts.get(j).getX(),pts.get(j).getY()); 690 } 691 Point2D[]destPts=new Point2D[pts.size()]; 692 //translate the points to crcumscribe 0,0 693// at.translate(-avgY, -avgY);//ideally would be close to 0 694// at.transform(srcPts, 0, destPts, 0, srcPts.length); 695// at.setToIdentity(); 696 //scale the points by 10% 697// at.scale(expandX, expandY); 698// at.transform(destPts, 0, destPts, 0, destPts.length); 699// at.setToIdentity(); 700// at.translate(avgY, avgY); 701// at.transform(destPts, 0, destPts, 0, destPts.length); 702 lgPoly=new ArrayList<Point2D>(); 703 int t=destPts.length; 704 //for(j=0;j<destPts.length;j++) 705 for(j=0;j<t;j++) 706 { 707 lgPoly.add(destPts[j]); 708 } 709 //close the aray if the original clipping array was closed 710 if(isClosed) 711 lgPoly.add(new Point2D.Double(destPts[0].getX(),destPts[0].getY())); 712 } 713 catch (Exception exc) { 714 ErrorLogger.LogException(_className, "expandPolygon", 715 new RendererException("Failed inside expandPolygon", exc)); 716 } 717 return lgPoly; 718 } 719 /** 720 * @deprecated 721 * For tactical lines break up the arraylists into separate arraylists within the bounds. 722 * This was added for the Google Earth 3D map because small scales cut off and we want the clip lines 723 * to not be visible. 724 * @param ptsPoly 725 * @param clipBounds 726 * @return 727 */ 728 private static ArrayList<ArrayList<Point2D>> ptsPolyToPtsPoly(TGLight tg, ArrayList<ArrayList<Point2D>>ptsPoly, 729 Rectangle2D clipBounds) 730 { 731 ArrayList<ArrayList<Point2D>> ptsPoly2=null; 732 try 733 { 734 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(tg.get_LineType())==true) 735 return ptsPoly; 736 737 int j=0,k=0; 738 ArrayList<Point2D>pts=null; 739 ArrayList<Point2D>addPts=null; 740 Point2D pt0=null; 741 Point2D pt1=null; 742 Line2D line=null; 743 ptsPoly2=new ArrayList(); 744 int n=ptsPoly.size(); 745 //for(j=0;j<ptsPoly.size();j++) 746 for(j=0;j<n;j++) 747 { 748 addPts=null; 749 pts=ptsPoly.get(j); 750 //find the first point inside the clipbounds 751 int t=pts.size(); 752 //for(k=0;k<pts.size()-1;k++) 753 for(k=0;k<t-1;k++) 754 { 755 pt0=pts.get(k); 756 pt1=pts.get(k+1); 757 758 line=new Line2D.Double(pt0,pt1); 759 //both points out of bounds, do not add points 760 if(clipBounds.contains(pt0)==false && clipBounds.contains(pt1)==false) 761 { 762 if(clipBounds.intersectsLine(line)==false) 763 { 764 addPts=null; 765 continue; 766 } 767 else 768 { 769 if(addPts==null) 770 { 771 addPts=new ArrayList(); 772 addPts.add(pt0); 773 } 774 if(addPts.contains(pt0)==false) 775 addPts.add(pt0); 776 777 addPts.add(pt1); 778 ptsPoly2.add(addPts); 779 addPts=null; 780 } 781 } 782 else if(clipBounds.contains(pt0)==false && clipBounds.contains(pt1)==true) 783 { 784 if(addPts == null) 785 { 786 addPts=new ArrayList(); 787 addPts.add(pt0); 788 } 789 if(addPts.contains(pt0)==false) 790 addPts.add(pt0); 791 792 addPts.add(pt1); 793 } 794 else if(clipBounds.contains(pt0)==true && clipBounds.contains(pt1)==true) 795 { 796 if(addPts==null) 797 { 798 addPts=new ArrayList(); 799 addPts.add(pt0); 800 } 801 if(addPts.contains(pt0)==false) 802 addPts.add(pt0); 803 804 addPts.add(pt1); 805 } 806 else if(clipBounds.contains(pt0)==true && clipBounds.contains(pt1)==false) 807 { 808 if(addPts==null) 809 { 810 addPts=new ArrayList(); 811 addPts.add(pt0); 812 } 813 if(addPts.contains(pt0)==false) 814 addPts.add(pt0); 815 //end the current polyline 816 //and add it to the array list 817 addPts.add(pt1); 818 ptsPoly2.add(addPts); 819 addPts=null; 820 } 821 } 822 //add the final array list 823 if(addPts != null && addPts.size()>0) 824 ptsPoly2.add(addPts); 825 } 826 } 827 catch (Exception exc) { 828 ErrorLogger.LogException(_className, "ptsPolyToPtsPoly", 829 new RendererException("Failed inside ptsPolyToPtsPoly", exc)); 830 } 831 return ptsPoly2; 832 } 833 /** 834 * @deprecated 835 * function to remove the clip lines from the polygon that was clipped 836 * @param ptsPoly the clipped points array 837 * @param clipBounds the clipping points 838 * @return 839 */ 840 private static ArrayList<ArrayList<Point2D>> ptsPolyToPtsPoly(TGLight tg, ArrayList<ArrayList<Point2D>>ptsPoly, 841 ArrayList<Point2D> clipBounds)//was rectangle2D clipBounds 842 { 843 ArrayList<ArrayList<Point2D>> ptsPoly2=null; 844 try 845 { 846 if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(tg.get_LineType())==true) 847 return ptsPoly; 848 849 int j=0,k=0; 850 ArrayList<Point2D>pts=null; 851 ArrayList<Point2D>addPts=null; 852 Point2D pt0=null; 853 Point2D pt1=null; 854 Line2D line=null; 855 ptsPoly2=new ArrayList(); 856 Polygon clipPoly=new Polygon(); 857 858 //ArrayList<Point2D>ptsClipArea=null; 859 int n=clipBounds.size(); 860 //for(j=0;j<clipBounds.size();j++) 861 for(j=0;j<n;j++) 862 { 863 clipPoly.addPoint((int)clipBounds.get(j).getX(), (int)clipBounds.get(j).getY()); 864 } 865 n=ptsPoly.size(); 866 //for(j=0;j<ptsPoly.size();j++) 867 for(j=0;j<n;j++) 868 { 869 addPts=null; 870 pts=ptsPoly.get(j); 871 //find the first point inside the clipbounds 872 int t=pts.size(); 873 //for(k=0;k<pts.size()-1;k++) 874 for(k=0;k<t-1;k++) 875 { 876 pt0=pts.get(k); 877 pt1=pts.get(k+1); 878 line=new Line2D.Double(pt0,pt1); 879 //both points out of bounds, do not add points 880 if(clipPoly.contains(pt0)==false && clipPoly.contains(pt1)==false) 881 { 882 if(lineIntersectsClipArea(line,clipBounds)==false) 883 { 884 addPts=null; 885 continue; 886 } 887 else 888 { 889 if(addPts==null) 890 { 891 addPts=new ArrayList(); 892 addPts.add(pt0); 893 } 894 if(addPts.contains(pt0)==false) 895 addPts.add(pt0); 896 897 addPts.add(pt1); 898 ptsPoly2.add(addPts); 899 addPts=null; 900 } 901 } 902 else if(clipPoly.contains(pt0)==false && clipPoly.contains(pt1)==true) 903 { 904 if(addPts == null) 905 { 906 addPts=new ArrayList(); 907 addPts.add(pt0); 908 } 909 if(addPts.contains(pt0)==false) 910 addPts.add(pt0); 911 912 addPts.add(pt1); 913 } 914 else if(clipPoly.contains(pt0)==true && clipPoly.contains(pt1)==true) 915 { 916 if(addPts==null) 917 { 918 addPts=new ArrayList(); 919 addPts.add(pt0); 920 } 921 if(addPts.contains(pt0)==false) 922 addPts.add(pt0); 923 924 addPts.add(pt1); 925 } 926 else if(clipPoly.contains(pt0)==true && clipPoly.contains(pt1)==false) 927 { 928 if(addPts==null) 929 { 930 addPts=new ArrayList(); 931 addPts.add(pt0); 932 } 933 if(addPts.contains(pt0)==false) 934 addPts.add(pt0); 935 //end the current polyline 936 //and add it to the array list 937 addPts.add(pt1); 938 ptsPoly2.add(addPts); 939 addPts=null; 940 } 941 } 942 //add the final array list 943 if(addPts != null && addPts.size()>0) 944 ptsPoly2.add(addPts); 945 } 946 } 947 catch (Exception exc) { 948 ErrorLogger.LogException(_className, "ptsPolyToPtsPoly", 949 new RendererException("Failed inside ptsPolyToPtsPoly", exc)); 950 } 951 return ptsPoly2; 952 } 953 /** 954 * removes leading or trailing segments after the points were clipped 955 * @param tg 956 * @param clipArea 957 */ 958 protected static void removeTrailingPoints(TGLight tg, Object clipArea) 959 { 960 try 961 { 962 boolean isClosed= armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType()); 963 if(isClosed) 964 return; 965 966 Polygon poly=new Polygon(); 967 Area area=null; 968 Rectangle2D clipBounds=null; 969 ArrayList<Point2D>clipPoints=null; 970 Point2D pt2d=null; 971 int j=0; 972 if(clipArea==null) 973 return; 974 975 if(clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) 976 { 977 clipBounds=(Rectangle2D.Double)clipArea; 978 } 979 else if(clipArea.getClass().isAssignableFrom(Rectangle.class)) 980 { 981 //clipBounds=(Rectangle2D)clipArea; 982 Rectangle rectx=(Rectangle)clipArea; 983 clipBounds=new Rectangle2D.Double(rectx.x,rectx.y,rectx.width,rectx.height); 984 } 985 else if(clipArea.getClass().isAssignableFrom(ArrayList.class)) 986 { 987 clipPoints=(ArrayList<Point2D>)clipArea; 988 } 989 if(clipBounds != null) 990 { 991 clipPoints=new ArrayList<Point2D>(); 992 clipPoints.add(new Point2D.Double(clipBounds.getX(),clipBounds.getY())); 993 clipPoints.add(new Point2D.Double(clipBounds.getX()+clipBounds.getWidth(),clipBounds.getY())); 994 clipPoints.add(new Point2D.Double(clipBounds.getX()+clipBounds.getWidth(),clipBounds.getY()+clipBounds.getHeight())); 995 clipPoints.add(new Point2D.Double(clipBounds.getX(),clipBounds.getY()+clipBounds.getHeight())); 996 clipPoints.add(new Point2D.Double(clipBounds.getX(),clipBounds.getY())); 997 } 998 999 Point2D ptLast=clipPoints.get(clipPoints.size()-1); 1000 Point2D pt02d=clipPoints.get(0); 1001 Point2D pt12d=null; 1002 //close the area 1003 if(pt02d.getX() != ptLast.getX() || pt02d.getY() != ptLast.getY()) 1004 { 1005 clipPoints.add(new Point2D.Double(pt02d.getX(),pt02d.getY())); 1006 //poly.addPoint((int)pt02d.getX(),(int)pt02d.getY()); 1007 } 1008 //fill the polygon 1009 int n=clipPoints.size(); 1010 //for(j=0;j<clipPoints.size();j++) 1011 for(j=0;j<n;j++) 1012 { 1013 pt02d=clipPoints.get(j); 1014 poly.addPoint((int)pt02d.getX(), (int)pt02d.getY()); 1015 } 1016 area=new Area(poly); 1017 Line2D line=null; 1018 POINT2 pt0=null,pt1=null; 1019 boolean intersects=false; 1020 int frontIndex=0,backIndex=tg.Pixels.size()-1; 1021 //breaks at the first leading segment that intersects the clip area 1022 n=tg.Pixels.size(); 1023 //for(j=0;j<tg.Pixels.size()-1;j++) 1024 for(j=0;j<n-1;j++) 1025 { 1026 pt0=tg.Pixels.get(j); 1027 pt1=tg.Pixels.get(j+1); 1028 line=new Line2D.Double(pt0.x, pt0.y, pt1.x, pt1.y); 1029 intersects=lineIntersectsClipArea(line, clipPoints); 1030 if(intersects==true) 1031 { 1032 frontIndex=j; 1033 break; 1034 } 1035 else if(area.contains((int)pt0.x,(int)pt0.y) || area.contains((int)pt1.x,(int)pt1.y)) 1036 { 1037 frontIndex=j; 1038 break; 1039 } 1040 } 1041 //breaks at the first trailing segment that intersects the clip area 1042 n=tg.Pixels.size(); 1043 //for(j=tg.Pixels.size()-1;j>0;j--) 1044 for(j=n-1;j>0;j--) 1045 { 1046 pt0=tg.Pixels.get(j); 1047 pt1=tg.Pixels.get(j-1); 1048 line=new Line2D.Double(pt0.x, pt0.y, pt1.x, pt1.y); 1049 intersects=lineIntersectsClipArea(line, clipPoints); 1050 if(intersects==true) 1051 { 1052 backIndex=j; 1053 break; 1054 } 1055 else if(area.contains((int)pt0.x,(int)pt0.y) || area.contains((int)pt1.x,(int)pt1.y)) 1056 { 1057 backIndex=j; 1058 break; 1059 } 1060 } 1061 ArrayList<POINT2>pts=new ArrayList(); 1062 for(j=frontIndex;j<=backIndex;j++) 1063 { 1064 pt0=new POINT2(tg.Pixels.get(j)); 1065 pts.add(pt0); 1066 } 1067 tg.Pixels=pts; 1068 } 1069 catch(Exception exc) 1070 { 1071 ErrorLogger.LogException("clsRenderer" ,"removeTrailingPoints", 1072 new RendererException("Failed inside removeTrailingPoints", exc)); 1073 } 1074 } 1075/** 1076 * tests of a Line2D intersects a polygon by using line.intersectsLine on each segment of the polygon 1077 * assumes clip clipping area was parsed to shift points of vertical segments to make them not vertical 1078 * @param line a clipping line in the clipping polygon 1079 * @param clipPts array of clip points assumed to be closed 1080 * @return true if the line intersects the clip bounds 1081 */ 1082 private static boolean lineIntersectsClipArea(Line2D line, 1083 ArrayList<Point2D> clipPts) 1084 { 1085 boolean result=false; 1086 try 1087 { 1088 int j=0; 1089 1090 //test if polygon contains an end point 1091 Polygon poly=new Polygon(); 1092 int n=clipPts.size(); 1093 //for(j=0;j<clipPts.size();j++) 1094 for(j=0;j<n;j++) 1095 poly.addPoint((int)clipPts.get(j).getX(),(int)clipPts.get(j).getY()); 1096 1097 if(poly.contains(line.getX1(),line.getY1())) 1098 return true; 1099 if(poly.contains(line.getX2(),line.getY2())) 1100 return true; 1101 //end section 1102 1103 Line2D currentSegment=null; 1104 n=clipPts.size(); 1105 //for(j=0;j<clipPts.size()-1;j++) 1106 for(j=0;j<n-1;j++) 1107 { 1108 currentSegment=new Line2D.Double(clipPts.get(j).getX(),clipPts.get(j).getY(),clipPts.get(j+1).getX(),clipPts.get(j+1).getY()); 1109 if(line.intersectsLine(currentSegment)==true) 1110 return true; 1111 } 1112 //if the clipPts are not closed then the above loop did not test the closing segment 1113 Point2D pt0=clipPts.get(0); 1114 Point2D ptLast=clipPts.get(clipPts.size()-1); 1115 //int n=clipPts.size()-1; 1116 if(pt0.getX()!=ptLast.getX() || pt0.getY()!=ptLast.getY()) 1117 { 1118 //currentSegment=new Line2D.Double(clipPts.get(n).getX(),clipPts.get(n).getY(),clipPts.get(0).getX(),clipPts.get(0).getY()); 1119 currentSegment=new Line2D.Double(ptLast.getX(),ptLast.getY(),pt0.getX(),pt0.getY()); 1120 if(line.intersectsLine(currentSegment)==true) 1121 return true; 1122 } 1123 } 1124 catch (Exception exc) { 1125 ErrorLogger.LogException(_className, "lineIntersectsClipArea", 1126 new RendererException("Failed inside lineIntersectsClipArea", exc)); 1127 } 1128 return result; 1129 } 1130 /** 1131 * returns true if segment data set for MSR, ASR, Boundary 1132 * @param tg 1133 * @return 1134 */ 1135 protected static boolean segmentColorsSet(TGLight tg) 1136 { 1137 try 1138 { 1139 switch(tg.get_LineType()) 1140 { 1141 case TacticalLines.BOUNDARY: 1142 case TacticalLines.MSR: 1143 case TacticalLines.ASR: 1144 case TacticalLines.ROUTE: 1145 break; 1146 default: 1147 return false; 1148 } 1149 String strH=tg.get_H(); 1150 if(strH==null || strH.isEmpty()) 1151 return false; 1152 String[] strs=strH.split(","); 1153 if(strs.length>1) 1154 return true; 1155 } 1156 catch(Exception exc) 1157 { 1158 ErrorLogger.LogException(_className, "segmentColorsSet", 1159 new RendererException("Failed inside segmentColorsSet", exc)); 1160 } 1161 return false; 1162 } 1163 /** 1164 * Use clipping rectangle or clip points to build a zoom factor if the client zoomed in after the initial render. 1165 * Multiply the geo segmenting interval by this factor. 1166 * @param rect 1167 * @param clipPoints 1168 * @param pixels 1169 * @return 1170 */ 1171 protected static double getZoomFactor(Rectangle2D rect, ArrayList<Point2D> clipPoints, ArrayList<POINT2>pixels) 1172 { 1173 double factor=-1; 1174 try 1175 { 1176 if(pixels==null || pixels.size()<2) 1177 return factor; 1178 if(clipPoints==null && rect==null) 1179 return factor; 1180 double maxLengthPixels=0, maxLengthClipArea=0,temp=0; 1181 int j=0; 1182 Point2D pt2d0=null,pt2d1=null;POINT2 pt0=null, pt1=null; 1183 for(j=0;j<pixels.size()-1;j++) 1184 { 1185 pt0=pixels.get(j); 1186 pt1=pixels.get(j+1); 1187 temp=lineutility.CalcDistanceDouble(pt0, pt1); 1188 if(temp>maxLengthPixels) 1189 maxLengthPixels=temp; 1190 } 1191 temp=0; 1192 if(clipPoints != null) 1193 { 1194 for(j=0;j<clipPoints.size()-1;j++) 1195 { 1196 pt2d0=clipPoints.get(j); 1197 pt2d1=clipPoints.get(j+1); 1198 pt0=new POINT2(pt2d0.getX(),pt2d0.getY()); 1199 pt1=new POINT2(pt2d1.getX(),pt2d1.getY()); 1200 temp=lineutility.CalcDistanceDouble(pt0, pt1); 1201 } 1202 } 1203 else if(rect != null) 1204 { 1205 temp=rect.getMaxX()-rect.getMinX(); 1206 if(temp < rect.getMaxY()-rect.getMinY()) 1207 temp=rect.getMaxY()-rect.getMinY(); 1208 } 1209 if(temp>maxLengthClipArea) 1210 maxLengthClipArea=temp; 1211 if(maxLengthPixels > 0 && maxLengthClipArea > 0) 1212 factor=maxLengthClipArea/maxLengthPixels; 1213 } 1214 catch(Exception exc) 1215 { 1216 ErrorLogger.LogException(_className, "getZoomFactor", 1217 new RendererException("Failed inside getZoomFactor", exc)); 1218 } 1219 return factor; 1220 } 1221 1222}