001/* 002 * To change this template, choose Tools | Templates 003 * and open the template in the editor. 004 */ 005package armyc2.c5isr.RenderMultipoints; 006 007import java.util.ArrayList; 008import java.util.HashMap; 009import java.util.Map; 010 011import armyc2.c5isr.JavaLineArray.POINT2; 012import armyc2.c5isr.JavaLineArray.Shape2; 013import armyc2.c5isr.JavaLineArray.TacticalLines; 014import armyc2.c5isr.JavaLineArray.arraysupport; 015import armyc2.c5isr.JavaLineArray.lineutility; 016import armyc2.c5isr.JavaLineArray.ref; 017import armyc2.c5isr.JavaTacticalRenderer.TGLight; 018import armyc2.c5isr.JavaTacticalRenderer.clsMETOC; 019import armyc2.c5isr.JavaTacticalRenderer.clsUtility; 020import armyc2.c5isr.JavaTacticalRenderer.mdlGeodesic; 021import armyc2.c5isr.graphics2d.GeneralPath; 022import armyc2.c5isr.graphics2d.PathIterator; 023import armyc2.c5isr.graphics2d.Point2D; 024import armyc2.c5isr.graphics2d.Rectangle; 025import armyc2.c5isr.graphics2d.Rectangle2D; 026import armyc2.c5isr.graphics2d.Shape; 027import armyc2.c5isr.renderer.utilities.ErrorLogger; 028import armyc2.c5isr.renderer.utilities.IPointConversion; 029import armyc2.c5isr.renderer.utilities.RendererException; 030import armyc2.c5isr.renderer.utilities.ShapeInfo; 031import armyc2.c5isr.renderer.utilities.SymbolUtilities; 032 033/** 034 * CPOF utility functions taken from JavaLineArrayCPOF 035 * 036* 037 */ 038public final class clsUtilityCPOF { 039 040 private static final String _className = "clsUtilityCPOF"; 041 042 /** 043 * 044 * @param ptLatLong 045 * @param converter 046 * @return 047 */ 048 private static POINT2 PointLatLongToPixels(POINT2 ptLatLong, 049 IPointConversion converter) { 050 POINT2 pt = new POINT2(); 051 try { 052 double x = ptLatLong.x; 053 double y = ptLatLong.y; 054 Point2D ptPixels = converter.GeoToPixels(new Point2D.Double(x, y)); 055 pt.x = ptPixels.getX(); 056 pt.y = ptPixels.getY(); 057 pt.style = ptLatLong.style; 058 059 } catch (Exception exc) { 060 ErrorLogger.LogException(_className, "PointLatLongToPixels", 061 new RendererException("Failed inside PointLatLongToPixels", exc)); 062 } 063 return pt; 064 } 065 066 /** 067 * for the change 1 fire support areas 068 * 069 * @param tg 070 * @param lineType 071 * @param radius 072 * @param width 073 * @param length 074 * @param attitude 075 */ 076 private static void GetNumericFields(TGLight tg, 077 int lineType, 078 ref<double[]> radius, 079 ref<double[]> width, 080 ref<double[]> length, 081 ref<double[]> attitude) { 082 try { 083 if (lineType == TacticalLines.RANGE_FAN_FILL) { 084 return; 085 } 086 double dist = 0; 087 ref<double[]> a12 = new ref(), a21 = new ref(); 088 POINT2 pt0 = new POINT2(0, 0); 089 POINT2 pt1 = new POINT2(0, 0); 090 radius.value = new double[1]; 091 width.value = new double[1]; 092 attitude.value = new double[1]; 093 length.value = new double[1]; 094 switch (lineType) { 095 case TacticalLines.CIRCULAR: 096 case TacticalLines.BDZ: 097 case TacticalLines.FSA_CIRCULAR: 098 case TacticalLines.NOTACK: 099 case TacticalLines.FFA_CIRCULAR: 100 case TacticalLines.NFA_CIRCULAR: 101 case TacticalLines.RFA_CIRCULAR: 102 case TacticalLines.PAA_CIRCULAR: 103 case TacticalLines.ATI_CIRCULAR: 104 case TacticalLines.CFFZ_CIRCULAR: 105 case TacticalLines.SENSOR_CIRCULAR: 106 case TacticalLines.CENSOR_CIRCULAR: 107 case TacticalLines.DA_CIRCULAR: 108 case TacticalLines.CFZ_CIRCULAR: 109 case TacticalLines.ZOR_CIRCULAR: 110 case TacticalLines.TBA_CIRCULAR: 111 case TacticalLines.TVAR_CIRCULAR: 112 case TacticalLines.ACA_CIRCULAR: 113 case TacticalLines.KILLBOXBLUE_CIRCULAR: 114 case TacticalLines.KILLBOXPURPLE_CIRCULAR: 115 if (SymbolUtilities.isNumber(tg.get_AM())) { 116 radius.value[0] = Double.parseDouble(tg.get_AM()); 117 } 118 break; 119 case TacticalLines.LAUNCH_AREA: 120 case TacticalLines.DEFENDED_AREA_CIRCULAR: 121 case TacticalLines.SHIP_AOI_CIRCULAR: 122 //minor radius in meters 123 if (SymbolUtilities.isNumber(tg.get_AM1())) { 124 length.value[0] = Double.parseDouble(tg.get_AM1()); 125 } 126 //major radius in meters 127 if (SymbolUtilities.isNumber(tg.get_AM())) { 128 width.value[0] = Double.parseDouble(tg.get_AM()); 129 } 130 //rotation angle in degrees 131 if (SymbolUtilities.isNumber(tg.get_AN())) { 132 attitude.value[0] = Double.parseDouble(tg.get_AN()); 133 } 134 135 break; 136 case TacticalLines.RECTANGULAR: 137 if (SymbolUtilities.isNumber(tg.get_AM1())) { 138 length.value[0] = Double.parseDouble(tg.get_AM1()); 139 } 140 if (SymbolUtilities.isNumber(tg.get_AM())) { 141 width.value[0] = Double.parseDouble(tg.get_AM()); 142 } 143 //assume that attitude was passed in mils 144 //so we must multiply by 360/6400 to convert to degrees 145 if (SymbolUtilities.isNumber(tg.get_AN())) { 146 attitude.value[0] = Double.parseDouble(tg.get_AN()) * (360d / 6400d); 147 } 148 break; 149 case TacticalLines.CUED_ACQUISITION: 150 if (SymbolUtilities.isNumber(tg.get_AM())) { 151 length.value[0] = Double.parseDouble(tg.get_AM()); 152 } 153 if (SymbolUtilities.isNumber(tg.get_AM1())) { 154 width.value[0] = Double.parseDouble(tg.get_AM1()); 155 } 156 if (SymbolUtilities.isNumber(tg.get_AN())) { 157 // Make 0 degrees point north instead of East 158 attitude.value[0] = Double.parseDouble(tg.get_AN()) + 270; 159 } 160 break; 161 case TacticalLines.PAA_RECTANGULAR: 162 case TacticalLines.FSA_RECTANGULAR: 163 case TacticalLines.SHIP_AOI_RECTANGULAR: 164 case TacticalLines.DEFENDED_AREA_RECTANGULAR: 165 case TacticalLines.FFA_RECTANGULAR: 166 case TacticalLines.ACA_RECTANGULAR: 167 case TacticalLines.NFA_RECTANGULAR: 168 case TacticalLines.RFA_RECTANGULAR: 169 case TacticalLines.ATI_RECTANGULAR: 170 case TacticalLines.CFFZ_RECTANGULAR: 171 case TacticalLines.SENSOR_RECTANGULAR: 172 case TacticalLines.CENSOR_RECTANGULAR: 173 case TacticalLines.DA_RECTANGULAR: 174 case TacticalLines.CFZ_RECTANGULAR: 175 case TacticalLines.ZOR_RECTANGULAR: 176 case TacticalLines.TBA_RECTANGULAR: 177 case TacticalLines.TVAR_RECTANGULAR: 178 case TacticalLines.KILLBOXBLUE_RECTANGULAR: 179 case TacticalLines.KILLBOXPURPLE_RECTANGULAR: 180 case TacticalLines.RECTANGULAR_TARGET: 181 if (tg.LatLongs.size() >= 2) { 182 //get the length and the attitude in mils 183 pt0 = tg.LatLongs.get(0); 184 pt1 = tg.LatLongs.get(1); 185 dist = mdlGeodesic.geodesic_distance(pt0, pt1, a12, a21); 186 attitude.value[0] = a12.value[0]; 187 } 188 if (SymbolUtilities.isNumber(tg.get_AM())) { 189 width.value[0] = Double.parseDouble(tg.get_AM()); 190 } 191 break; 192 default: 193 break; 194 } 195 } catch (Exception exc) { 196 ErrorLogger.LogException(_className, "GetNumericFields", 197 new RendererException("Failed inside GetNumericFields", exc)); 198 } 199 } 200 201 /** 202 * Do a 360 degree horizontal shift for points on either side of the 203 * midpoint of the display, if the MBR for the pixels is greater than 180 204 * degrees wide. Builds pixels for two symbols to draw a symbol flipped 205 * about the left edge and also a symbol flipped about the right edge. This 206 * function is typically used at world view. Caller must instantiate last 207 * two parameters. 208 * 209 * @param tg 210 * @param converter 211 * @param farLeftPixels - OUT - the resultant pixels for left shift symbol 212 * @param farRightPixels - OUT - the result pixels for the right shift 213 * symbol 214 */ 215 protected static void GetFarPixels(TGLight tg, 216 IPointConversion converter, 217 ArrayList farLeftPixels, 218 ArrayList farRightPixels) { 219 try { 220 if (farLeftPixels == null || farRightPixels == null) { 221 return; 222 } 223 //Cannot use tg.LatLon to get width in degrees because it shifts +/-180 at IDL. 224 //Get degrees per pixel longitude, will use it for determining width in degrees 225 Point2D ptPixels50 = converter.GeoToPixels(new Point2D.Double(50, 30)); 226 Point2D ptPixels60 = converter.GeoToPixels(new Point2D.Double(60, 30)); 227 double degLonPerPixel = 10 / Math.abs(ptPixels60.getX() - ptPixels50.getX()); 228 int j = 0; 229 double minX = Double.MAX_VALUE, maxX = -Double.MAX_VALUE; 230 int n = tg.Pixels.size(); 231 //for(j=0;j<tg.Pixels.size();j++) 232 for (j = 0; j < n; j++) { 233 if (tg.Pixels.get(j).x < minX) { 234 minX = tg.Pixels.get(j).x; 235 } 236 if (tg.Pixels.get(j).x > maxX) { 237 maxX = tg.Pixels.get(j).x; 238 } 239 } 240 double degWidth = (maxX - minX) * degLonPerPixel; 241 if (Math.abs(degWidth) < 180) { 242 return; 243 } 244 245 //if it did not return then we must shift the pixels left and right 246 //first get the midpoint X value to use for partitioning the points 247 double midX = Math.abs(180 / degLonPerPixel); 248 double x = 0, y = 0; 249 //do a shift about the left hand side 250 //for(j=0;j<tg.Pixels.size();j++) 251 for (j = 0; j < n; j++) { 252 x = tg.Pixels.get(j).x; 253 y = tg.Pixels.get(j).y; 254 if (x > midX) { 255 //shift x left by 360 degrees in pixels 256 x -= 2 * midX; 257 } 258 //else do not shift the point 259 //add the shifted (or not) point to the new arraylist 260 farLeftPixels.add(new POINT2(x, y)); 261 } 262 //do a shift about the right hand side 263 //for(j=0;j<tg.Pixels.size();j++) 264 for (j = 0; j < n; j++) { 265 x = tg.Pixels.get(j).x; 266 y = tg.Pixels.get(j).y; 267 if (x < midX) { 268 //shift x right by 360 degrees in pixels 269 x += 2 * midX; 270 } 271 //else do not shift the point 272 //add the shifted (or not) point to the new arraylist 273 farRightPixels.add(new POINT2(x, y)); 274 } 275 } catch (Exception exc) { 276 ErrorLogger.LogException(_className, "GetFarPixels", 277 new RendererException("Failed inside GetFarPixels", exc)); 278 } 279 } 280 281 /** 282 * 283 * @param tg 284 * @param lineType 285 * @param converter 286 * @param shapes 287 * @return 288 */ 289 protected static boolean Change1TacticalAreas(TGLight tg, 290 int lineType, IPointConversion converter, ArrayList<Shape2> shapes) { 291 try { 292 ref<double[]> width = new ref(), length = new ref(), attitude = new ref(), radius = new ref(); 293 int j = 0; 294 POINT2 pt0 = tg.LatLongs.get(0); 295 POINT2 pt1 = null; 296 POINT2 ptTemp = new POINT2(); 297 POINT2 pt00 = new POINT2(); 298 if (tg.LatLongs.size() > 1) { 299 pt1 = tg.LatLongs.get(1); 300 } else { 301 pt1 = tg.LatLongs.get(0); 302 } 303 POINT2[] pPoints = null; 304 POINT2 ptCenter = PointLatLongToPixels(pt0, converter); 305 306 GetNumericFields(tg, lineType, radius, width, length, attitude); 307 switch (lineType) { 308 case TacticalLines.LAUNCH_AREA: 309 case TacticalLines.DEFENDED_AREA_CIRCULAR: 310 case TacticalLines.SHIP_AOI_CIRCULAR: 311 POINT2[] ellipsePts = mdlGeodesic.getGeoEllipse(pt0, width.value[0], length.value[0], attitude.value[0]); 312 for (j = 0; j < ellipsePts.length; j++) //was 103 313 { 314 pt0 = ellipsePts[j]; 315 pt1 = PointLatLongToPixels(pt0, converter); 316 tg.Pixels.add(pt1); 317 } 318 break; 319 case TacticalLines.PAA_RECTANGULAR: 320 case TacticalLines.FSA_RECTANGULAR: 321 case TacticalLines.SHIP_AOI_RECTANGULAR: 322 case TacticalLines.DEFENDED_AREA_RECTANGULAR: 323 case TacticalLines.FFA_RECTANGULAR: 324 case TacticalLines.ACA_RECTANGULAR: 325 case TacticalLines.NFA_RECTANGULAR: 326 case TacticalLines.RFA_RECTANGULAR: 327 case TacticalLines.ATI_RECTANGULAR: 328 case TacticalLines.CFFZ_RECTANGULAR: 329 case TacticalLines.SENSOR_RECTANGULAR: 330 case TacticalLines.CENSOR_RECTANGULAR: 331 case TacticalLines.DA_RECTANGULAR: 332 case TacticalLines.CFZ_RECTANGULAR: 333 case TacticalLines.ZOR_RECTANGULAR: 334 case TacticalLines.TBA_RECTANGULAR: 335 case TacticalLines.TVAR_RECTANGULAR: 336 case TacticalLines.KILLBOXBLUE_RECTANGULAR: 337 case TacticalLines.KILLBOXPURPLE_RECTANGULAR: 338 //get the upper left corner 339 pt00 = mdlGeodesic.geodesic_coordinate(pt0, width.value[0] / 2, attitude.value[0] - 90); 340 pt00 = PointLatLongToPixels(pt00, converter); 341 342 pt00.style = 0; 343 tg.Pixels.add(pt00); 344 345 //second corner (clockwise from center) 346 ptTemp = mdlGeodesic.geodesic_coordinate(pt0, width.value[0] / 2, attitude.value[0] + 90); 347 ptTemp = PointLatLongToPixels(ptTemp, converter); 348 ptTemp.style = 0; 349 tg.Pixels.add(ptTemp); 350 351 //third corner (clockwise from center) 352 ptTemp = mdlGeodesic.geodesic_coordinate(pt1, width.value[0] / 2, attitude.value[0] + 90); 353 ptTemp = PointLatLongToPixels(ptTemp, converter); 354 ptTemp.style = 0; 355 tg.Pixels.add(ptTemp); 356 357 //fourth corner (clockwise from center) 358 ptTemp = mdlGeodesic.geodesic_coordinate(pt1, width.value[0] / 2, attitude.value[0] - 90); 359 ptTemp = PointLatLongToPixels(ptTemp, converter); 360 ptTemp.style = 0; 361 tg.Pixels.add(ptTemp); 362 363 tg.Pixels.add(pt00); 364 break; 365 case TacticalLines.RECTANGULAR_TARGET: 366 POINT2[] pts = new POINT2[4]; // 4 Corners 367 368 // get the upper left corner 369 pts[0] = mdlGeodesic.geodesic_coordinate(pt0, width.value[0] / 2, attitude.value[0] - 90); 370 ptTemp = PointLatLongToPixels(pts[0], converter); 371 ptTemp.style = 0; 372 tg.Pixels.add(ptTemp); 373 374 // second corner (clockwise from center) 375 pts[1] = mdlGeodesic.geodesic_coordinate(pt0, width.value[0] / 2, attitude.value[0] + 90); 376 ptTemp = PointLatLongToPixels(pts[1], converter); 377 ptTemp.style = 0; 378 tg.Pixels.add(ptTemp); 379 380 // third corner (clockwise from center) 381 pts[2] = mdlGeodesic.geodesic_coordinate(pt1, width.value[0] / 2, attitude.value[0] + 90); 382 ptTemp = PointLatLongToPixels(pts[2], converter); 383 ptTemp.style = 0; 384 tg.Pixels.add(ptTemp); 385 386 // fourth corner (clockwise from center) 387 pts[3] = mdlGeodesic.geodesic_coordinate(pt1, width.value[0] / 2, attitude.value[0] - 90); 388 ptTemp = PointLatLongToPixels(pts[3], converter); 389 ptTemp.style = 0; 390 tg.Pixels.add(ptTemp); 391 392 // Close shape 393 ptTemp = PointLatLongToPixels(pts[0], converter); 394 ptTemp.style = 5; 395 tg.Pixels.add(ptTemp); 396 397 double heightD = mdlGeodesic.geodesic_distance(pts[0], pts[1], null, null); 398 double widthD = mdlGeodesic.geodesic_distance(pts[1], pts[2], null, null); 399 double crossLength = Math.min(heightD, widthD) * .4; // Length from center 400 401 POINT2 centerPt = lineutility.CalcCenterPointDouble2(pts, 4); 402 403 ptTemp = mdlGeodesic.geodesic_coordinate(centerPt, crossLength, 0); 404 ptTemp = PointLatLongToPixels(ptTemp, converter); 405 ptTemp.style = 0; 406 tg.Pixels.add(ptTemp); 407 408 ptTemp = mdlGeodesic.geodesic_coordinate(centerPt, crossLength, 180); 409 ptTemp = PointLatLongToPixels(ptTemp, converter); 410 ptTemp.style = 5; 411 tg.Pixels.add(ptTemp); 412 413 ptTemp = mdlGeodesic.geodesic_coordinate(centerPt, crossLength, -90); 414 ptTemp = PointLatLongToPixels(ptTemp, converter); 415 ptTemp.style = 0; 416 tg.Pixels.add(ptTemp); 417 418 ptTemp = mdlGeodesic.geodesic_coordinate(centerPt, crossLength, 90); 419 ptTemp = PointLatLongToPixels(ptTemp, converter); 420 ptTemp.style = 0; 421 tg.Pixels.add(ptTemp); 422 break; 423 case TacticalLines.RECTANGULAR: 424 case TacticalLines.CUED_ACQUISITION: 425 //AFATDS swap length and width 426 //comment next three lines to render per Mil-Std-2525 427 //double temp=width.value[0]; 428 //width.value[0]=length.value[0]; 429 //length.value[0]=temp; 430 431 //get the upper left corner 432 ptTemp = mdlGeodesic.geodesic_coordinate(pt0, length.value[0] / 2, attitude.value[0] - 90);//was length was -90 433 ptTemp = mdlGeodesic.geodesic_coordinate(ptTemp, width.value[0] / 2, attitude.value[0] + 0);//was width was 0 434 435 ptTemp = PointLatLongToPixels(ptTemp, converter); 436 tg.Pixels.add(ptTemp); 437 //second corner (clockwise from center) 438 ptTemp = mdlGeodesic.geodesic_coordinate(pt0, length.value[0] / 2, attitude.value[0] + 90); //was length was +90 439 ptTemp = mdlGeodesic.geodesic_coordinate(ptTemp, width.value[0] / 2, attitude.value[0] + 0); //was width was 0 440 441 ptTemp = PointLatLongToPixels(ptTemp, converter); 442 443 tg.Pixels.add(ptTemp); 444 445 //third corner (clockwise from center) 446 ptTemp = mdlGeodesic.geodesic_coordinate(pt0, length.value[0] / 2, attitude.value[0] + 90);//was length was +90 447 ptTemp = mdlGeodesic.geodesic_coordinate(ptTemp, width.value[0] / 2, attitude.value[0] + 180);//was width was +180 448 449 ptTemp = PointLatLongToPixels(ptTemp, converter); 450 451 tg.Pixels.add(ptTemp); 452 453 //fouth corner (clockwise from center) 454 ptTemp = mdlGeodesic.geodesic_coordinate(pt0, length.value[0] / 2, attitude.value[0] - 90);//was length was -90 455 ptTemp = mdlGeodesic.geodesic_coordinate(ptTemp, width.value[0] / 2, attitude.value[0] + 180);//was width was +180 456 457 ptTemp = PointLatLongToPixels(ptTemp, converter); 458 tg.Pixels.add(ptTemp); 459 tg.Pixels.add(new POINT2(tg.Pixels.get(0).x, tg.Pixels.get(0).y)); 460 break; 461 case TacticalLines.CIRCULAR: 462 case TacticalLines.BDZ: 463 case TacticalLines.FSA_CIRCULAR: 464 case TacticalLines.NOTACK: 465 case TacticalLines.ACA_CIRCULAR: 466 case TacticalLines.FFA_CIRCULAR: 467 case TacticalLines.NFA_CIRCULAR: 468 case TacticalLines.RFA_CIRCULAR: 469 case TacticalLines.PAA_CIRCULAR: 470 case TacticalLines.ATI_CIRCULAR: 471 case TacticalLines.CFFZ_CIRCULAR: 472 case TacticalLines.SENSOR_CIRCULAR: 473 case TacticalLines.CENSOR_CIRCULAR: 474 case TacticalLines.DA_CIRCULAR: 475 case TacticalLines.CFZ_CIRCULAR: 476 case TacticalLines.ZOR_CIRCULAR: 477 case TacticalLines.TBA_CIRCULAR: 478 case TacticalLines.TVAR_CIRCULAR: 479 case TacticalLines.KILLBOXBLUE_CIRCULAR: 480 case TacticalLines.KILLBOXPURPLE_CIRCULAR: 481 //get a horizontal point on the radius 482 pt0 = tg.LatLongs.get(0); 483 484 ptTemp = mdlGeodesic.geodesic_coordinate(pt0, radius.value[0], 90); 485 486 pPoints = new POINT2[3]; 487 pPoints[0] = new POINT2(pt0); 488 pPoints[1] = new POINT2(ptTemp); 489 pPoints[2] = new POINT2(ptTemp); 490 491 ArrayList<POINT2> pPoints2 = mdlGeodesic.GetGeodesicArc(pPoints); 492 POINT2 ptTemp2 = null; 493 //fill pixels and latlongs 494 for (j = 0; j < pPoints2.size(); j++) //was 103 495 { 496 pt0 = pPoints2.get(j); 497 ptTemp2 = new POINT2(); 498 ptTemp2 = PointLatLongToPixels(pt0, converter); 499 500 tg.Pixels.add(ptTemp2); 501 } 502 break; 503 case TacticalLines.RANGE_FAN: 504 //get the concentric circles 505 GetConcentricCircles(tg, lineType, converter); 506 //Mil-Std-2525 Rev C does not have the orientation arrow 507 //assume we are using Rev C if there is only 1 anchor point 508 if (tg.LatLongs.size() > 1) { 509 RangeFanOrientation(tg, lineType, converter); 510 } 511 break; 512 case TacticalLines.RANGE_FAN_SECTOR: 513 GetSectorRangeFan(tg, converter); 514 RangeFanOrientation(tg, lineType, converter); 515 break; 516 case TacticalLines.RADAR_SEARCH: 517 GetSectorRangeFan(tg, converter); 518 break; 519 case TacticalLines.RANGE_FAN_FILL: //circular range fan calls Change1TacticalAreas twice 520 GetSectorRangeFan(tg, converter); 521 break; 522 default: 523 return false; 524 } 525 526 //the shapes 527 ArrayList<POINT2> farLeftPixels = new ArrayList(); 528 ArrayList<POINT2> farRightPixels = new ArrayList(); 529 clsUtilityCPOF.GetFarPixels(tg, converter, farLeftPixels, farRightPixels); 530 ArrayList<Shape2> shapesLeft = new ArrayList(); 531 ArrayList<Shape2> shapesRight = new ArrayList(); 532 //ArrayList<Shape2>shapes=null; //use this to collect all the shapes 533 534 if (farLeftPixels.isEmpty() || farRightPixels.isEmpty()) { 535 //diagnostic 536 //Change1PixelsToShapes(tg,shapes); 537 ArrayList<POINT2> tempPixels = new ArrayList(); 538 tempPixels.addAll((ArrayList) tg.Pixels); 539 clsUtilityCPOF.postSegmentFSA(tg, converter); 540 Change1PixelsToShapes(tg, shapes, false); 541 //reuse the original pixels for the subsequent call to AddModifier2 542 tg.Pixels = tempPixels; 543 //end section 544 } else //symbol was more than 180 degrees wide, use left and right symbols 545 { 546 //set tg.Pixels to the left shapes for the call to Change1PixelsToShapes 547 tg.Pixels = farLeftPixels; 548 Change1PixelsToShapes(tg, shapesLeft, false); 549 //set tg.Pixels to the right shapes for the call to Change1PixelsToShapes 550 tg.Pixels = farRightPixels; 551 Change1PixelsToShapes(tg, shapesRight, false); 552 //load left and right shapes into shapes 553 shapes.addAll(shapesLeft); 554 shapes.addAll(shapesRight); 555 } 556 return true; 557 } catch (Exception exc) { 558 ErrorLogger.LogException(_className, "Change1TacticalAreas", 559 new RendererException("Failed inside Change1TacticalAreas", exc)); 560 } 561 return false; 562 } 563 564 /** 565 * build shapes arraylist from tg.Pixels for the Change 1 symbols 566 * 567 * @param tg 568 * @param shapes - OUT - caller instantiates the arraylist 569 */ 570 private static void Change1PixelsToShapes(TGLight tg, ArrayList<Shape2> shapes, boolean fill) { 571 Shape2 shape = null; 572 boolean beginLine = true; 573 POINT2 currentPt = null, lastPt = null; 574 int k = 0; 575 int linetype = tg.get_LineType(); 576 int n = tg.Pixels.size(); 577 //a loop for the outline shapes 578 //for (k = 0; k < tg.Pixels.size(); k++) 579 for (k = 0; k < n; k++) { 580 //use shapes instead of pixels 581 if (shape == null) { 582 //shape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE); 583 if(!fill) 584 shape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE); 585 else if(fill) 586 shape = new Shape2(Shape2.SHAPE_TYPE_FILL); 587 } 588 589 currentPt = tg.Pixels.get(k); 590 if (k > 0) { 591 lastPt = tg.Pixels.get(k - 1); 592 } 593 594 if (beginLine) { 595 if (k == 0) { 596 shape.set_Style(currentPt.style); 597 } 598 599 if (k > 0) //doubled points with linestyle=5 600 { 601 if (currentPt.style == 5 && lastPt.style == 5) { 602 shape.lineTo(currentPt); 603 } 604 } 605 606 shape.moveTo(currentPt); 607 beginLine = false; 608 } else { 609 shape.lineTo(currentPt); 610 if (currentPt.style == 5 || currentPt.style == 10) { 611 beginLine = true; 612 //unless there are doubled points with style=5 613 if (linetype == TacticalLines.RANGE_FAN_FILL && k < tg.Pixels.size() - 1) { 614 shapes.add(shape); 615 shape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE); 616 } 617 } 618 } 619 if (k == tg.Pixels.size() - 1) //PBS shapes have 2 shapes, other non-LC symbols have 1 shape 620 { 621 //shapes.add(shape); 622 if(shape.getShapeType()==ShapeInfo.SHAPE_TYPE_FILL) 623 shapes.add(0,shape); 624 else 625 shapes.add(shape); 626 } 627 } //end for 628 629 } 630 631 private static void GetConcentricCircles(TGLight tg, int lineType, IPointConversion converter) { 632 try { 633 int j = 0, l = 0; 634 double radius = 0; 635 636 POINT2 pt = new POINT2(); 637 ArrayList<POINT2> pts = new ArrayList(); 638 double[] radii = null; // AM 639 String strAM = tg.get_AM(); 640 if (tg.LatLongs.size() == 1 && strAM != null) 641 { 642 String[] strs = strAM.split(","); 643 radii = new double[strs.length]; 644 for (j = 0; j < strs.length; j++) { 645 radii[j] = Double.parseDouble(strs[j]); 646 } 647 } 648 649 int n = radii.length; 650 651 //loop thru the circles 652 POINT2[] pPoints = null; 653 for (l = 0; l < n; l++) { 654 radius = radii[l]; 655 if (radius == 0) { 656 continue; 657 } 658 659 pPoints = new POINT2[3]; 660 pt = tg.LatLongs.get(0); 661 pPoints[0] = new POINT2(pt); 662 //radius, 90, ref lon2c, ref lat2c); 663 pt = mdlGeodesic.geodesic_coordinate(pt, radius, 90); 664 pPoints[1] = new POINT2(pt); 665 pPoints[2] = new POINT2(pt); 666 667 pts = mdlGeodesic.GetGeodesicArc(pPoints); 668 669 POINT2 ptTemp2 = null; 670 //fill pixels and latlongs 671 int t = pts.size(); 672 //for (j = 0; j < pts.size(); j++)//was 103 673 for (j = 0; j < t; j++)//was 103 674 { 675 ptTemp2 = new POINT2(); 676 ptTemp2 = PointLatLongToPixels(pts.get(j), converter); 677 ptTemp2.style = 0; 678 if (j == pts.size() - 1) { 679 ptTemp2.style = 5; 680 } 681 682 tg.Pixels.add(ptTemp2); 683 } 684 } 685 int length = tg.Pixels.size(); 686 tg.Pixels.get(length - 1).style = 5; 687 688 } catch (Exception exc) { 689 ErrorLogger.LogException(_className, "GetConcentricCircles", 690 new RendererException("Failed inside GetConcentricCircles", exc)); 691 } 692 } 693 694 /** 695 * if tg.H2 is filled then the max range sector is used to determine the 696 * orientation 697 * 698 * @param tg 699 * @return left,right,min,max 700 */ 701 private static String GetMaxSector(TGLight tg) { 702 String strLeftRightMinMax = null; 703 try { 704 double max = 0, maxx = -Double.MAX_VALUE; 705 //get the number of sectors 706 strLeftRightMinMax = tg.get_LRMM(); 707 String[] leftRightMinMax = strLeftRightMinMax.split(","); 708 int numSectors = leftRightMinMax.length / 4; 709 int k = 0, maxIndex = -1; 710 //there must be at least one sector 711 if (numSectors < 1) { 712 return null; 713 } 714 715 if (numSectors * 4 != leftRightMinMax.length) { 716 return null; 717 } 718 //get the max index 719 try { 720 for (k = 0; k < numSectors; k++) { 721 //left = Double.parseDouble(leftRightMinMax[4 * k]); 722 //right = Double.parseDouble(leftRightMinMax[4 * k + 1]); 723 //min = Double.parseDouble(leftRightMinMax[4 * k + 2]); 724 max = Double.parseDouble(leftRightMinMax[4 * k + 3]); 725 if (max > maxx) { 726 maxx = max; 727 maxIndex = k; 728 } 729 } 730 } catch (NumberFormatException e) { 731 return null; 732 } 733 String strLeft = leftRightMinMax[4 * maxIndex]; 734 String strRight = leftRightMinMax[4 * maxIndex + 1]; 735 String strMin = leftRightMinMax[4 * maxIndex + 2]; 736 String strMax = leftRightMinMax[4 * maxIndex + 3]; 737 strLeftRightMinMax = strLeft + "," + strRight + "," + strMin + "," + strMax; 738 } catch (Exception exc) { 739 ErrorLogger.LogException(_className, "GetMaxSector", 740 new RendererException("Failed inside GetMaxSector", exc)); 741 } 742 return strLeftRightMinMax; 743 } 744 745 /** 746 * Create a tg with a new line type to used for circular range fan fill 747 * 748 * @param tg 749 * @return 750 */ 751 protected static TGLight GetCircularRangeFanFillTG(TGLight tg) { 752 TGLight tg1 = null; 753 try { 754 //instantiate a dummy tg which will be used to call GetSectorRangeFan 755 tg1 = new TGLight(); 756 tg1.set_VisibleModifiers(true); 757 tg1.set_LineThickness(0); 758 tg1.set_FillColor(tg.get_FillColor()); 759 tg1.set_Fillstyle(tg.get_FillStyle()); 760 tg1.LatLongs = new ArrayList<POINT2>(); 761 tg1.Pixels = new ArrayList<POINT2>(); 762 //we only want the 0th point 763 tg1.LatLongs.add(tg.LatLongs.get(0)); 764 tg1.Pixels.add(tg.Pixels.get(0)); 765 tg1.Pixels.add(tg.Pixels.get(1)); 766 tg1.set_LineType(TacticalLines.RANGE_FAN_FILL); 767 768 if (tg.get_LineType() == TacticalLines.RANGE_FAN_SECTOR || tg.get_LineType() == TacticalLines.RADAR_SEARCH) { 769 tg1.set_LRMM(tg.get_LRMM()); 770 return tg1; 771 } else if (tg.get_LineType() == TacticalLines.RANGE_FAN) { 772 String[] radii = tg.get_AM().split(","); 773 String strLeftRightMinMax = ""; 774 for (int j = 0; j < radii.length - 1; j++) { 775 if (j > 0) { 776 strLeftRightMinMax += ","; 777 } 778 779 strLeftRightMinMax += "0,0," + radii[j] + "," + radii[j + 1]; 780 } 781 tg1.set_LRMM(strLeftRightMinMax); 782 } 783 } catch (Exception exc) { 784 ErrorLogger.LogException(_className, "GetCircularRangeFanFillTG", 785 new RendererException("Failed inside GetCircularRangeFanFillTG", exc)); 786 } 787 return tg1; 788 } 789 790 /** 791 * 792 * @param tg 793 * @param converter 794 * @return 795 */ 796 private static boolean GetSectorRangeFan(TGLight tg, IPointConversion converter) { 797 boolean circle = false; 798 try { 799 POINT2 ptCenter = tg.LatLongs.get(0); 800 int k = 0, l = 0; 801 int numSectors = 0; 802 clsUtility.GetSectorRadiiFromPoints(tg); 803 804 //use pPoints to get each geodesic arc 805 ArrayList<POINT2> pPoints = new ArrayList(); 806 ArrayList<POINT2> pPointsInnerArc = new ArrayList(); 807 ArrayList<POINT2> pPointsOuterArc = new ArrayList(); 808 ArrayList<POINT2> sectorPoints = new ArrayList(); 809 ArrayList<POINT2> allPoints = new ArrayList(); 810 811 //use these and the center to define each sector 812 POINT2 pt1 = new POINT2(), pt2 = new POINT2(); 813 814 //get the number of sectors 815 String strLeftRightMinMax = tg.get_LRMM(); 816 String[] leftRightMinMax = strLeftRightMinMax.split(","); 817 818 //sanity checks 819 double left = 0, right = 0, min = 0, max = 0; 820 numSectors = leftRightMinMax.length / 4; 821 822 //there must be at least one sector 823 if (numSectors < 1) { 824 return false; 825 } 826 827 if (numSectors * 4 != leftRightMinMax.length) { 828 return false; 829 } 830 831 //left must be less than right, 832 //min must be less than max, each sector 833 try { 834 for (k = 0; k < numSectors; k++) { 835 left = Double.parseDouble(leftRightMinMax[4 * k]); 836 right = Double.parseDouble(leftRightMinMax[4 * k + 1]); 837 min = Double.parseDouble(leftRightMinMax[4 * k + 2]); 838 max = Double.parseDouble(leftRightMinMax[4 * k + 3]); 839 } 840 } catch (NumberFormatException e) { 841 return false; 842 } 843 844 for (k = 0; k < numSectors; k++) //was k=0 845 { 846 //empty any points that were there from the last sector 847 sectorPoints.clear(); 848 pPointsOuterArc.clear(); 849 pPointsInnerArc.clear(); 850 851 left = Double.parseDouble(leftRightMinMax[4 * k]); 852 right = Double.parseDouble(leftRightMinMax[4 * k + 1]); 853 min = Double.parseDouble(leftRightMinMax[4 * k + 2]); 854 max = Double.parseDouble(leftRightMinMax[4 * k + 3]); 855 856 //get the first point of the sector inner arc 857 pt1 = mdlGeodesic.geodesic_coordinate(ptCenter, min, left); 858 859 //get the last point of the sector inner arc 860 pt2 = mdlGeodesic.geodesic_coordinate(ptCenter, min, right); 861 862 pPoints.clear(); 863 864 pPoints.add(ptCenter); 865 pPoints.add(pt1); 866 pPoints.add(pt2); 867 868 circle = mdlGeodesic.GetGeodesicArc2(pPoints, pPointsInnerArc); 869 870 pPoints.clear(); 871 circle = false; 872 873 pt1 = mdlGeodesic.geodesic_coordinate(ptCenter, max, left); 874 pt2 = mdlGeodesic.geodesic_coordinate(ptCenter, max, right); 875 876 pPoints.add(ptCenter); 877 pPoints.add(pt1); 878 pPoints.add(pt2); 879 880 //get the geodesic min arc from left to right 881 circle = mdlGeodesic.GetGeodesicArc2(pPoints, pPointsOuterArc); 882 883 //we now have all the points and can add them to the polygon to return 884 //we will have to reverse the order of points in the outer arc 885 int n = pPointsInnerArc.size(); 886 for (l = 0; l < n; l++) { 887 pt1 = new POINT2(pPointsInnerArc.get(l)); 888 sectorPoints.add(pt1); 889 } 890 n = pPointsOuterArc.size(); 891 //for (l = pPointsOuterArc.size() - 1; l >= 0; l--) 892 for (l = n - 1; l >= 0; l--) { 893 pt1 = new POINT2(pPointsOuterArc.get(l)); 894 sectorPoints.add(pt1); 895 } 896 897 //close the polygon 898 pt1 = new POINT2(pPointsInnerArc.get(0)); 899 pt1.style = 5; 900 sectorPoints.add(pt1); 901 n = sectorPoints.size(); 902 //for (l = 0; l < sectorPoints.size(); l++) 903 for (l = 0; l < n; l++) { 904 allPoints.add(sectorPoints.get(l)); 905 } 906 } 907 908 //cleanup what we can 909 pPointsInnerArc = null; 910 pPointsOuterArc = null; 911 ptCenter = null; 912 913 POINT2 ptTemp = null; 914 int n = allPoints.size(); 915 //for (l = 0; l < allPoints.size(); l++) 916 for (l = 0; l < n; l++) { 917 pt1 = new POINT2(); 918 pt1 = PointLatLongToPixels(allPoints.get(l), converter); 919 //do not add duplicates 920 if (ptTemp != null && pt1.x == ptTemp.x && pt1.y == ptTemp.y) { 921 continue; 922 } 923 tg.Pixels.add(new POINT2(pt1)); 924 ptTemp = new POINT2(pt1); 925 } 926 927 return true; 928 } catch (Exception exc) { 929 ErrorLogger.LogException(_className, "GetSectorRangeFan", 930 new RendererException("Failed inside GetSectorRangeFan", exc)); 931 } 932 return circle; 933 } 934 935 private static void RangeFanOrientation(TGLight tg, int lineType, IPointConversion converter) { 936 try { 937 POINT2 pt0 = tg.LatLongs.get(0); 938 double dist = 0; 939 double orientation = 0; 940 double radius = 0; 941 //double[] radii = clsUtility.GetRadii(tg,lineType); 942 int j = 0; 943 POINT2 pt1 = new POINT2(); 944 //if tg.PointCollection has more than one point 945 //we use pts[1] to stuff tg.H with the orientation 946 ref<double[]> a12 = new ref(), a21 = new ref(); 947 if (tg.LatLongs.size() > 1) //rev B can use points 948 { 949 pt1 = tg.LatLongs.get(1); 950 dist = mdlGeodesic.geodesic_distance(pt0, pt1, a12, a21); 951 orientation = a12.value[0]; 952 } else //rev C uses H2 953 { 954 String strLeftRightMinMax = GetMaxSector(tg); 955 String[] sector = strLeftRightMinMax.split(","); 956 double left = Double.parseDouble(sector[0]); 957 double right = Double.parseDouble(sector[1]); 958 double min = Double.parseDouble(sector[2]); 959 double max = Double.parseDouble(sector[3]); 960 //we want the range to be 0 to 360 961 while (left > 360) { 962 left -= 360; 963 } 964 while (right > 360) { 965 right -= 360; 966 } 967 while (left < 0) { 968 left += 360; 969 } 970 while (right < 0) { 971 right += 360; 972 } 973 974 if (left > right) { 975 orientation = (left - 360 + right) / 2; 976 } else { 977 orientation = (left + right) / 2; 978 } 979 980 dist = max; 981 } 982 radius = dist * 1.1; 983 POINT2 pt0F = new POINT2(); 984 POINT2 pt1F = new POINT2(); 985 POINT2 ptBaseF = new POINT2(); 986 POINT2 ptLeftF = new POINT2(); 987 POINT2 ptRightF = new POINT2(); 988 POINT2 ptTipF = new POINT2(); 989 990 pt0 = tg.LatLongs.get(0); 991 992 pt0F = PointLatLongToPixels(pt0, converter); 993 994 pt1 = mdlGeodesic.geodesic_coordinate(pt0, radius, orientation); 995 996 pt1F = PointLatLongToPixels(pt1, converter); 997 dist = lineutility.CalcDistanceDouble(pt0F, pt1F); 998 double base = 10; 999 if (dist < 100) { 1000 base = dist / 10; 1001 } 1002 if (base < 5) { 1003 base = 5; 1004 } 1005 double basex2 = 2 * base; 1006 ptBaseF = lineutility.ExtendAlongLineDouble(pt0F, pt1F, dist + base); //was 10 1007 ptTipF = lineutility.ExtendAlongLineDouble(pt0F, pt1F, dist + basex2); //was 20 1008 1009 ptLeftF = lineutility.ExtendDirectedLine(pt0F, ptBaseF, ptBaseF, 0, base); //was 10 1010 ptRightF = lineutility.ExtendDirectedLine(pt0F, ptBaseF, ptBaseF, 1, base); //was 10 1011 //length1 = tg.Pixels.size(); 1012 1013 tg.Pixels.add(pt0F); 1014 ptTipF.style = 5; 1015 tg.Pixels.add(ptTipF); 1016 tg.Pixels.add(ptLeftF); 1017 ptTipF.style = 0; 1018 tg.Pixels.add(ptTipF); 1019 tg.Pixels.add(ptRightF); 1020 } catch (Exception exc) { 1021 ErrorLogger.LogException(_className, "RangeFanOrientation", 1022 new RendererException("Failed inside RangeFanOrientation", exc)); 1023 } 1024 } 1025 1026 /** 1027 * after filtering pixels it needs to reinitialize the style to 0 or it 1028 * causes CELineArraydotNet to build wrong shapes 1029 * 1030 * @param tg 1031 */ 1032 protected static void ClearPixelsStyle(TGLight tg) { 1033 try { 1034 //do not clear pixel style for the air corridors because 1035 //arraysupport is using linestyle for these to set the segment width 1036 switch (tg.get_LineType()) { 1037 case TacticalLines.SC: 1038 case TacticalLines.MRR: 1039 case TacticalLines.SL: 1040 case TacticalLines.TC: 1041 case TacticalLines.LLTR: 1042 case TacticalLines.AC: 1043 case TacticalLines.SAAFR: 1044 return; 1045 default: 1046 break; 1047 1048 } 1049 int n = tg.Pixels.size(); 1050 //for(int j=0;j<tg.Pixels.size();j++) 1051 for (int j = 0; j < n; j++) { 1052 tg.Pixels.get(j).style = 0; 1053 } 1054 1055 } catch (Exception exc) { 1056 ErrorLogger.LogException(_className, "ClearPixelsStyle", 1057 new RendererException("Failed inside ClearPixelsStyle", exc)); 1058 1059 } 1060 } 1061 1062 /** 1063 * Filters too close points after segmenting and clipping 1064 * 1065 * @param tg 1066 * @param converter 1067 */ 1068 protected static void FilterPoints2(TGLight tg, IPointConversion converter) { 1069 try { 1070 int lineType = tg.get_LineType(); 1071 double minSpikeDistance = 0; 1072 boolean segmented = true; 1073 if (tg.Pixels.size() < 3) { 1074 return; 1075 } 1076 1077 switch (lineType) { 1078 case TacticalLines.PL: 1079 case TacticalLines.FEBA: 1080 case TacticalLines.LOA: 1081 case TacticalLines.LL: 1082 case TacticalLines.EWL: 1083 case TacticalLines.FCL: 1084 case TacticalLines.LOD: 1085 case TacticalLines.LDLC: 1086 case TacticalLines.PLD: 1087 case TacticalLines.HOLD: 1088 case TacticalLines.HOLD_GE: 1089 case TacticalLines.RELEASE: 1090 case TacticalLines.HOL: 1091 case TacticalLines.BHL: 1092 case TacticalLines.BRDGHD: 1093 case TacticalLines.BRDGHD_GE: 1094 case TacticalLines.NFL: 1095 minSpikeDistance = arraysupport.getScaledSize(5, tg.get_LineThickness()); 1096 segmented = false; 1097 break; 1098 case TacticalLines.ATDITCH: 1099 case TacticalLines.ATDITCHC: 1100 case TacticalLines.ATDITCHM: 1101 case TacticalLines.FLOT: 1102 case TacticalLines.FORT_REVD: 1103 case TacticalLines.FORT: 1104 case TacticalLines.FORTL: 1105 case TacticalLines.STRONG: 1106 minSpikeDistance = arraysupport.getScaledSize(25, tg.get_LineThickness()); 1107 break; 1108 case TacticalLines.LC: 1109 case TacticalLines.OBSAREA: 1110 case TacticalLines.OBSFAREA: 1111 case TacticalLines.ENCIRCLE: 1112 case TacticalLines.ZONE: 1113 case TacticalLines.LINE: 1114 case TacticalLines.ATWALL: 1115 //case TacticalLines.ATWALL3D: 1116 case TacticalLines.UNSP: 1117 case TacticalLines.SFENCE: 1118 case TacticalLines.DFENCE: 1119 case TacticalLines.DOUBLEA: 1120 case TacticalLines.LWFENCE: 1121 case TacticalLines.HWFENCE: 1122 case TacticalLines.SINGLEC: 1123 case TacticalLines.DOUBLEC: 1124 case TacticalLines.TRIPLE: 1125 minSpikeDistance = arraysupport.getScaledSize(35, tg.get_LineThickness()); 1126 break; 1127 case TacticalLines.ICE_EDGE_RADAR: //METOCs 1128 case TacticalLines.ICE_OPENINGS_FROZEN: 1129 case TacticalLines.CRACKS_SPECIFIC_LOCATION: 1130 minSpikeDistance = arraysupport.getScaledSize(35, tg.get_LineThickness()); 1131 break; 1132 default: 1133 return; 1134 } 1135 double dist = 0; 1136 1137 ArrayList<POINT2> pts = new ArrayList(); 1138 1139 //stuff pts with tg.Pixels 1140 //loop through pts to remove any points which are too close 1141 //then reset tg.Pixels with the new array with boundary points removed, 1142 int j = 0; 1143 POINT2 pt = null, pt0 = null, pt1 = null; 1144 int n = tg.Pixels.size(); 1145 //for(j=0;j<tg.Pixels.size();j++) 1146 for (j = 0; j < n; j++) { 1147 pt = tg.Pixels.get(j); 1148 pt.style = tg.Pixels.get(j).style; 1149 pts.add(pt); 1150 } 1151 1152 boolean removedPt = true; 1153 //order of priority is: keep anchor points, then boundary points, then segmented points 1154 outer: 1155 while (removedPt == true) { 1156 removedPt = false; 1157 //n=pts.size(); 1158 for (j = 0; j < pts.size() - 1; j++) { 1159 pt0 = pts.get(j); 1160 pt1 = pts.get(j + 1); 1161 dist = lineutility.CalcDistanceDouble(pts.get(j), pts.get(j + 1)); 1162 if (dist < minSpikeDistance) { 1163 if (segmented == false) { 1164 if (j + 1 == pts.size() - 1) { 1165 pts.remove(j); 1166 } else { 1167 pts.remove(j + 1); 1168 } 1169 1170 removedPt = true; 1171 break outer; 1172 } else if (pt0.style == 0 && pt1.style == -1)//-1 are clipped boundary points 1173 { 1174 pts.remove(j + 1); 1175 removedPt = true; 1176 break outer; 1177 } else if (pt0.style == 0 && pt1.style == -2)//-2 are segmented points, this should never happen 1178 { 1179 pts.remove(j + 1); 1180 removedPt = true; 1181 break outer; 1182 } else if (pt0.style == -1 && pt1.style == 0) { 1183 pts.remove(j); 1184 removedPt = true; 1185 break outer; 1186 } else if (pt0.style == -1 && pt1.style == -1) { 1187 pts.remove(j + 1); 1188 removedPt = true; 1189 break outer; 1190 } else if (pt0.style == -1 && pt1.style == -2) { 1191 pts.remove(j + 1); 1192 removedPt = true; 1193 break outer; 1194 } else if (pt0.style == -2 && pt1.style == 0)//this should never happen 1195 { 1196 pts.remove(j); 1197 removedPt = true; 1198 break outer; 1199 } else if (pt0.style == -2 && pt1.style == -1) { 1200 pts.remove(j); 1201 removedPt = true; 1202 break outer; 1203 } else if (pt0.style == -2 && pt1.style == -2) { 1204 pts.remove(j + 1); 1205 removedPt = true; 1206 break outer; 1207 } 1208 } 1209 //n=pts.size(); 1210 } 1211 } 1212 tg.Pixels = pts; 1213 tg.LatLongs = armyc2.c5isr.RenderMultipoints.clsUtility.PixelsToLatLong(pts, converter); 1214 1215 } catch (Exception exc) { 1216 ErrorLogger.LogException(_className, "FilterPoints2", 1217 new RendererException("Failed inside FilterPoints2", exc)); 1218 1219 } 1220 } 1221 1222 /** 1223 * returns true if the line type can be clipped before calculating the 1224 * shapes 1225 * 1226 * @param tg tactical graphic 1227 * @return true if can pre-clip points 1228 */ 1229 public static Boolean canClipPoints(TGLight tg) { 1230 try { 1231 String symbolId = tg.get_SymbolId(); 1232 if (clsMETOC.IsWeather(symbolId) > 0) { 1233 return true; 1234 } 1235 1236 int linetype = tg.get_LineType(); 1237 switch (linetype) { 1238 case TacticalLines.ABATIS: 1239// case TacticalLines.BOUNDARY: 1240 case TacticalLines.FLOT: 1241 case TacticalLines.LC: 1242 case TacticalLines.PL: 1243 case TacticalLines.FEBA: 1244 case TacticalLines.LL: 1245 case TacticalLines.EWL: 1246 case TacticalLines.GENERAL: 1247 case TacticalLines.JTAA: 1248 case TacticalLines.SAA: 1249 case TacticalLines.SGAA: 1250 case TacticalLines.ASSY: 1251 case TacticalLines.EA: 1252 case TacticalLines.FORT_REVD: 1253 case TacticalLines.FORT: 1254 case TacticalLines.DZ: 1255 case TacticalLines.EZ: 1256 case TacticalLines.LZ: 1257 case TacticalLines.PZ: 1258 case TacticalLines.LAA: 1259 case TacticalLines.ROZ: 1260 case TacticalLines.AARROZ: 1261 case TacticalLines.UAROZ: 1262 case TacticalLines.WEZ: 1263 case TacticalLines.FEZ: 1264 case TacticalLines.JEZ: 1265 case TacticalLines.FAADZ: 1266 case TacticalLines.HIDACZ: 1267 case TacticalLines.MEZ: 1268 case TacticalLines.LOMEZ: 1269 case TacticalLines.HIMEZ: 1270 case TacticalLines.WFZ: 1271 case TacticalLines.AIRFIELD: 1272 case TacticalLines.BATTLE: 1273 case TacticalLines.PNO: 1274 case TacticalLines.DIRATKAIR: 1275 case TacticalLines.DIRATKGND: 1276 case TacticalLines.DIRATKSPT: 1277 case TacticalLines.FCL: 1278 case TacticalLines.HOLD: 1279 case TacticalLines.BRDGHD: 1280 case TacticalLines.HOLD_GE: 1281 case TacticalLines.BRDGHD_GE: 1282 case TacticalLines.LOA: 1283 case TacticalLines.LOD: 1284 case TacticalLines.LDLC: 1285 case TacticalLines.PLD: 1286 case TacticalLines.ASSAULT: 1287 case TacticalLines.ATKPOS: 1288 case TacticalLines.OBJ: 1289 case TacticalLines.PEN: 1290 case TacticalLines.RELEASE: 1291 case TacticalLines.HOL: 1292 case TacticalLines.BHL: 1293 case TacticalLines.AO: 1294 case TacticalLines.AIRHEAD: 1295 case TacticalLines.ENCIRCLE: 1296 case TacticalLines.NAI: 1297 case TacticalLines.TAI: 1298 case TacticalLines.BASE_CAMP_REVD: 1299 case TacticalLines.BASE_CAMP: 1300 case TacticalLines.GUERILLA_BASE_REVD: 1301 case TacticalLines.GUERILLA_BASE: 1302 case TacticalLines.GENERIC_AREA: 1303 case TacticalLines.LINE: 1304 case TacticalLines.ZONE: 1305 case TacticalLines.OBSAREA: 1306 case TacticalLines.OBSFAREA: 1307 case TacticalLines.ATDITCH: 1308 case TacticalLines.ATDITCHC: 1309 case TacticalLines.ATDITCHM: 1310 case TacticalLines.ATWALL: 1311 case TacticalLines.DEPICT: 1312 case TacticalLines.MINED: 1313 case TacticalLines.FENCED: 1314 case TacticalLines.UXO: 1315 case TacticalLines.UNSP: 1316 case TacticalLines.SFENCE: 1317 case TacticalLines.DFENCE: 1318 case TacticalLines.DOUBLEA: 1319 case TacticalLines.LWFENCE: 1320 case TacticalLines.HWFENCE: 1321 case TacticalLines.SINGLEC: 1322 case TacticalLines.DOUBLEC: 1323 case TacticalLines.TRIPLE: 1324 case TacticalLines.FORTL: 1325 case TacticalLines.STRONG: 1326 case TacticalLines.RAD: 1327 case TacticalLines.BIO: 1328 case TacticalLines.NUC: 1329 case TacticalLines.CHEM: 1330 case TacticalLines.DRCL: 1331 case TacticalLines.LINTGT: 1332 case TacticalLines.LINTGTS: 1333 case TacticalLines.FPF: 1334 case TacticalLines.FSCL: 1335 case TacticalLines.BCL_REVD: 1336 case TacticalLines.BCL: 1337 case TacticalLines.ICL: 1338 case TacticalLines.IFF_OFF: 1339 case TacticalLines.IFF_ON: 1340 case TacticalLines.GENERIC_LINE: 1341 case TacticalLines.CFL: 1342 case TacticalLines.OVERHEAD_WIRE: 1343 case TacticalLines.NFL: 1344 case TacticalLines.MFP: 1345 case TacticalLines.RFL: 1346 case TacticalLines.AT: 1347 case TacticalLines.SERIES: 1348 case TacticalLines.STRIKWARN: 1349 case TacticalLines.SMOKE: 1350 case TacticalLines.BOMB: 1351 case TacticalLines.FSA: 1352 case TacticalLines.ACA: 1353 case TacticalLines.FFA: 1354 case TacticalLines.NFA: 1355 case TacticalLines.RFA: 1356 case TacticalLines.PAA: 1357 case TacticalLines.ATI: 1358 case TacticalLines.CFFZ: 1359 case TacticalLines.CFZ: 1360 case TacticalLines.SENSOR: 1361 case TacticalLines.CENSOR: 1362 case TacticalLines.DA: 1363 case TacticalLines.ZOR: 1364 case TacticalLines.TBA: 1365 case TacticalLines.TVAR: 1366 case TacticalLines.KILLBOXBLUE: 1367 case TacticalLines.KILLBOXPURPLE: 1368// case TacticalLines.MSR: 1369// case TacticalLines.ASR: 1370 case TacticalLines.MSR_ONEWAY: 1371 case TacticalLines.MSR_TWOWAY: 1372 case TacticalLines.MSR_ALT: 1373 case TacticalLines.ASR_ONEWAY: 1374 case TacticalLines.ASR_TWOWAY: 1375 case TacticalLines.ASR_ALT: 1376 case TacticalLines.ROUTE_ONEWAY: 1377 case TacticalLines.ROUTE_ALT: 1378 case TacticalLines.DHA_REVD: 1379 case TacticalLines.DHA: 1380 case TacticalLines.EPW: 1381 case TacticalLines.FARP: 1382 case TacticalLines.RHA: 1383 case TacticalLines.BSA: 1384 case TacticalLines.DSA: 1385 case TacticalLines.CSA: 1386 case TacticalLines.RSA: 1387 case TacticalLines.TGMF: 1388 return true; 1389 case TacticalLines.MSR: //post clip these so there are identical points regardless whether segment data is set 10-5-16 1390 case TacticalLines.ASR: 1391 case TacticalLines.ROUTE: 1392 case TacticalLines.BOUNDARY: 1393 return false; 1394 default: 1395 return false; 1396 } 1397 } catch (Exception exc) { 1398 ErrorLogger.LogException(_className, "canClipPoints", 1399 new RendererException("Failed inside canClipPoints", exc)); 1400 } 1401 return false; 1402 } 1403 1404 /** 1405 * These get clipped so the fill must be treated as a separate shape. 1406 * Normally lines with fill do not have a separate shape for the fill. 1407 * 1408 * @param linetype 1409 * @return 1410 */ 1411 protected static boolean LinesWithSeparateFill(int linetype, ArrayList<Shape2> shapes) { 1412 if (shapes == null) { 1413 return false; 1414 } 1415 1416 switch (linetype) { 1417 case TacticalLines.MSDZ: 1418 return true; 1419 //treat these as lines: because of the feint they need an extra shape for the fill 1420 case TacticalLines.OBSFAREA: 1421 case TacticalLines.OBSAREA: 1422 case TacticalLines.STRONG: 1423 case TacticalLines.ZONE: 1424 case TacticalLines.FORT_REVD: 1425 case TacticalLines.FORT: 1426 case TacticalLines.ENCIRCLE: 1427 //return true; 1428 case TacticalLines.FIX: 1429 case TacticalLines.BOUNDARY: 1430 case TacticalLines.FLOT: 1431 case TacticalLines.LC: 1432 case TacticalLines.PL: 1433 case TacticalLines.FEBA: 1434 case TacticalLines.LL: 1435 case TacticalLines.EWL: 1436 case TacticalLines.AC: 1437 case TacticalLines.MRR: 1438 case TacticalLines.SL: 1439 case TacticalLines.TC: 1440 case TacticalLines.SAAFR: 1441 case TacticalLines.SC: 1442 case TacticalLines.LLTR: 1443 case TacticalLines.DIRATKAIR: 1444 case TacticalLines.DIRATKGND: 1445 case TacticalLines.DIRATKSPT: 1446 case TacticalLines.FCL: 1447 case TacticalLines.HOLD: 1448 case TacticalLines.BRDGHD: 1449 case TacticalLines.HOLD_GE: 1450 case TacticalLines.BRDGHD_GE: 1451 case TacticalLines.LOA: 1452 case TacticalLines.LOD: 1453 case TacticalLines.LDLC: 1454 case TacticalLines.PLD: 1455 case TacticalLines.RELEASE: 1456 case TacticalLines.HOL: 1457 case TacticalLines.BHL: 1458 case TacticalLines.LINE: 1459 case TacticalLines.ABATIS: 1460 case TacticalLines.ATDITCH: 1461 case TacticalLines.ATDITCHC: 1462 case TacticalLines.ATDITCHM: 1463 case TacticalLines.ATWALL: 1464 case TacticalLines.MNFLDFIX: 1465 case TacticalLines.UNSP: 1466 case TacticalLines.SFENCE: 1467 case TacticalLines.DFENCE: 1468 case TacticalLines.DOUBLEA: 1469 case TacticalLines.LWFENCE: 1470 case TacticalLines.HWFENCE: 1471 case TacticalLines.SINGLEC: 1472 case TacticalLines.DOUBLEC: 1473 case TacticalLines.TRIPLE: 1474 case TacticalLines.FORTL: 1475 case TacticalLines.LINTGT: 1476 case TacticalLines.LINTGTS: 1477 case TacticalLines.FSCL: 1478 case TacticalLines.BCL_REVD: 1479 case TacticalLines.BCL: 1480 case TacticalLines.ICL: 1481 case TacticalLines.IFF_OFF: 1482 case TacticalLines.IFF_ON: 1483 case TacticalLines.GENERIC_LINE: 1484 case TacticalLines.CFL: 1485 case TacticalLines.NFL: 1486 case TacticalLines.MFP: 1487 case TacticalLines.RFL: 1488 case TacticalLines.MSR: 1489 case TacticalLines.MSR_ONEWAY: 1490 case TacticalLines.MSR_TWOWAY: 1491 case TacticalLines.MSR_ALT: 1492 case TacticalLines.ASR: 1493 case TacticalLines.ASR_ONEWAY: 1494 case TacticalLines.ASR_TWOWAY: 1495 case TacticalLines.ASR_ALT: 1496 case TacticalLines.ROUTE: 1497 case TacticalLines.ROUTE_ONEWAY: 1498 case TacticalLines.ROUTE_ALT: 1499 //undo any fill 1500 Shape2 shape = null; 1501 if (shapes != null && shapes.size() > 0) { 1502 int n = shapes.size(); 1503 //for(int j=0;j<shapes.size();j++) 1504 for (int j = 0; j < n; j++) { 1505 shape = shapes.get(j); 1506 if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) { 1507 shapes.get(j).setFillColor(null); 1508 } 1509 } 1510 } 1511 return true; 1512 default: 1513 return false; 1514 1515 } 1516 } 1517 1518 /** 1519 * uses a hash map to set the POINT2 style when creating tg.Pixels from 1520 * Point2D ArrayList 1521 * 1522 * @param pts2d 1523 * @param hashMap 1524 * @return 1525 */ 1526 protected static ArrayList<POINT2> Point2DtoPOINT2Mapped(ArrayList<Point2D> pts2d, Map<String, Object> hashMap) { 1527 ArrayList<POINT2> pts = new ArrayList(); 1528 try { 1529 Point2D pt2d; 1530 int style = 0; 1531 int n = pts2d.size(); 1532 //for(int j=0;j<pts2d.size();j++) 1533 for (int j = 0; j < n; j++) { 1534 pt2d = pts2d.get(j); 1535 //the hash map contains the original tg.Pixels before clipping 1536 if (hashMap.containsValue(pt2d)) { 1537 style = 0; 1538 } else { 1539 style = -1; //style set to -1 identifies it as a clip bounds point 1540 } 1541 pts.add(new POINT2(pts2d.get(j).getX(), pts2d.get(j).getY(), style)); 1542 } 1543 } catch (Exception exc) { 1544 ErrorLogger.LogException(_className, "Point2DToPOINT2Mapped", 1545 new RendererException("Failed inside Point2DToPOINT2Mapped", exc)); 1546 } 1547 return pts; 1548 } 1549 1550 protected static ArrayList<POINT2> Point2DtoPOINT2(ArrayList<Point2D> pts2d) { 1551 ArrayList<POINT2> pts = new ArrayList(); 1552 try { 1553 int n = pts2d.size(); 1554 //for(int j=0;j<pts2d.size();j++) 1555 for (int j = 0; j < n; j++) { 1556 pts.add(new POINT2(pts2d.get(j).getX(), pts2d.get(j).getY())); 1557 } 1558 } catch (Exception exc) { 1559 ErrorLogger.LogException(_className, "Point2DToPOINT2", 1560 new RendererException("Failed inside Point2DToPOINT2", exc)); 1561 } 1562 return pts; 1563 } 1564 1565 protected static ArrayList<Point2D> POINT2toPoint2D(ArrayList<POINT2> pts) { 1566 ArrayList<Point2D> pts2d = new ArrayList(); 1567 try { 1568 int n = pts.size(); 1569 //for(int j=0;j<pts.size();j++) 1570 for (int j = 0; j < n; j++) { 1571 pts2d.add(new Point2D.Double(pts.get(j).x, pts.get(j).y)); 1572 } 1573 1574 } catch (Exception exc) { 1575 ErrorLogger.LogException(_className, "POINT2toPoint2D", 1576 new RendererException("Failed inside POINT2toPoint2D", exc)); 1577 } 1578 return pts2d; 1579 } 1580 1581 /** 1582 * Builds a single shape from a point array. Currently we assume the array 1583 * represents a moveTo followed by a series of lineTo operations 1584 * 1585 * @param pts2d 1586 * @return 1587 */ 1588 private static Shape BuildShapeFromPoints(ArrayList<Point2D> pts2d) { 1589 GeneralPath shape = new GeneralPath(); 1590 try { 1591 shape.moveTo(pts2d.get(0).getX(), pts2d.get(0).getY()); 1592 int n = pts2d.size(); 1593 //for(int j=1;j<pts2d.size();j++) 1594 for (int j = 1; j < n; j++) { 1595 shape.lineTo(pts2d.get(j).getX(), pts2d.get(j).getY()); 1596 } 1597 } catch (Exception exc) { 1598 ErrorLogger.LogException(_className, "buildShapeFromPoints", 1599 new RendererException("Failed inside buildShapeFromPoints", exc)); 1600 1601 } 1602 return shape; 1603 } 1604 1605 /** 1606 * Clips a ShapeSpec. Assumes we are not post clipping splines, therefore 1607 * all the operations are moveTo, lineTo. Each ShapeSpec is assumed to be: 1608 * moveTo, lineTo ... lineTo, followed by another moveTo, lineTo, ... 1609 * lineTo, followed by ... 1610 * 1611 * @param shapeSpec 1612 * @param pts 1613 * @param clipArea 1614 * @return a single clipped shapeSpec 1615 */ 1616 protected static ArrayList<Shape2> buildShapeSpecFromPoints(TGLight tg0, 1617 Shape2 shapeSpec, //the original ShapeSpec 1618 ArrayList<POINT2> pts, 1619 Object clipArea) { 1620 ArrayList<Shape2> shapeSpecs2 = null; 1621 Shape2 shapeSpec2; 1622 try { 1623 //create a tg to use for the clip 1624 shapeSpecs2 = new ArrayList(); 1625 int j = 0, n = 0; 1626 //return null if it is outside the bounds 1627 Rectangle rect = shapeSpec.getBounds(); 1628 int h = shapeSpec.getBounds().height; 1629 int w = shapeSpec.getBounds().width; 1630 int x = shapeSpec.getBounds().x; 1631 int y = shapeSpec.getBounds().y; 1632// if(h==0 && w==0) 1633// return shapeSpecs2; 1634 1635 if (h == 0) { 1636 h = 1; 1637 } 1638 if (w == 0) { 1639 w = 1; 1640 } 1641 1642 Rectangle2D clipBounds = null; 1643 ArrayList<Point2D> clipPoints = null; 1644 if (clipArea != null && clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) { 1645 clipBounds = (Rectangle2D) clipArea; 1646 } else if (clipArea != null && clipArea.getClass().isAssignableFrom(Rectangle.class)) { 1647 //clipBounds=(Rectangle2D)clipArea; 1648 Rectangle rectx = (Rectangle) clipArea; 1649 clipBounds = new Rectangle2D.Double(rectx.x, rectx.y, rectx.width, rectx.height); 1650 } else if (clipArea != null && clipArea.getClass().isAssignableFrom(ArrayList.class)) { 1651 clipPoints = (ArrayList<Point2D>) clipArea; 1652 } 1653 1654 if (clipBounds != null && clipBounds.contains(shapeSpec.getShape().getBounds2D()) == false 1655 && clipBounds.intersects(shapeSpec.getShape().getBounds2D()) == false) { 1656 //this tests if the shape has height or width 0 1657 //but may be contained within the clipbounds or intersect it 1658 //in that case we gave it a default width or thickness of 1 1659 if (clipBounds.contains(x, y, w, h) == false 1660 && clipBounds.intersects(x, y, w, h) == false) { 1661 return shapeSpecs2; 1662 } 1663 } else if (clipPoints != null) { 1664 GeneralPath poly = new GeneralPath(); 1665 n = clipPoints.size(); 1666 //for(j=0;j<clipPoints.size();j++) 1667 for (j = 0; j < n; j++) { 1668 if (j == 0) { 1669 poly.moveTo(clipPoints.get(j).getX(), clipPoints.get(j).getY()); 1670 } else { 1671 poly.lineTo(clipPoints.get(j).getX(), clipPoints.get(j).getY()); 1672 } 1673 } 1674 poly.closePath(); 1675 if (poly.contains(shapeSpec.getShape().getBounds2D()) == false 1676 && poly.intersects(shapeSpec.getShape().getBounds2D()) == false) { 1677 if (poly.contains(x, y, w, h) == false 1678 && poly.intersects(x, y, w, h) == false) { 1679 return shapeSpecs2; 1680 } 1681 } 1682 } 1683 1684 if (shapeSpec.getShapeType() == Shape2.SHAPE_TYPE_MODIFIER 1685 || shapeSpec.getShapeType() == Shape2.SHAPE_TYPE_MODIFIER_FILL) { 1686 shapeSpecs2.add(shapeSpec); 1687 return shapeSpecs2; 1688 } 1689 TGLight tg = new TGLight(); 1690 POINT2 pt = null; 1691 tg.set_LineType(TacticalLines.PL); 1692 ArrayList<POINT2> pts2 = new ArrayList(); 1693 ArrayList<Point2D> pts2d = null; 1694 Shape shape = null; 1695 GeneralPath gp = new GeneralPath(); 1696 //loop through the points 1697 n = pts.size(); 1698 //for(j=0;j<pts.size();j++) 1699 for (j = 0; j < n; j++) { 1700 pt = pts.get(j); 1701 //new line 1702 switch (pt.style) { 1703 case 0: //moveTo, 1704 //they lifted the pencil, so we build the shape from the existing pts and append it 1705 if (pts2.size() > 1) { 1706 //clip the points 1707 tg = new TGLight(); 1708 tg.set_LineType(TacticalLines.PL); 1709 tg.Pixels = pts2; 1710 if (clipBounds != null) { 1711 pts2d = clsClipPolygon2.ClipPolygon(tg, clipBounds); 1712 } else if (clipPoints != null && !clipPoints.isEmpty()) { 1713 pts2d = clsClipQuad.ClipPolygon(tg, clipPoints); 1714 } 1715 1716 //build a GeneralPath from the points we collected, we will append it 1717 if (pts2d != null && pts2d.size() > 1) { 1718 shape = BuildShapeFromPoints(pts2d); 1719 //append the shape because we want to return only one shape 1720 gp.append(shape, false); 1721 } 1722 //clear the points array and begin the next line 1723 pts2.clear(); 1724 pts2.add(pt); 1725 } else { 1726 pts2.add(pt); 1727 } 1728 break; 1729 case 1: //lineTo 1730 pts2.add(pt); 1731 break; 1732 default: 1733 pts2.add(pt); 1734 break; 1735 } 1736 }//end for 1737 //append the last shape 1738 if (pts2.size() > 1) { 1739 //clip the points 1740 tg = new TGLight(); 1741 tg.set_LineType(TacticalLines.PL); 1742 tg.Pixels = pts2; 1743 if (clipBounds != null) { 1744 pts2d = clsClipPolygon2.ClipPolygon(tg, clipBounds); 1745 } else if (clipPoints != null) { 1746 pts2d = clsClipQuad.ClipPolygon(tg, clipPoints); 1747 } 1748 //build a GeneralPath from the points we collected, we will append it 1749 if (pts2d != null && pts2d.size() > 1) { 1750 shape = BuildShapeFromPoints(pts2d); 1751 gp.append(shape, false); 1752 } 1753 tg0.set_WasClipped(tg.get_WasClipped()); 1754 } 1755 //create the shapespec here 1756 //initialize the clipped ShapeSpec 1757 shapeSpec2 = new Shape2(shapeSpec.getShapeType()); 1758 shapeSpec2.setLineColor(shapeSpec.getLineColor()); 1759 shapeSpec2.setFillColor(shapeSpec.getFillColor()); 1760 shapeSpec2.setStroke(shapeSpec.getStroke()); 1761 shapeSpec2.setTexturePaint(shapeSpec.getTexturePaint()); 1762 shapeSpec2.setShape(gp); 1763 shapeSpecs2.add(shapeSpec2); 1764 } catch (Exception exc) { 1765 ErrorLogger.LogException(_className, "buildShapeSpecFromPoints", 1766 new RendererException("Failed inside buildShapeSpecFromPoints", exc)); 1767 1768 } 1769 return shapeSpecs2; 1770 } 1771 1772 /** 1773 * Currently assumes no MeTOC symbols are post clipped 1774 * 1775 * @param tg 1776 * @param shapeSpecsArray 1777 * @param clipArea 1778 * @return 1779 */ 1780 protected static ArrayList<Shape2> postClipShapes(TGLight tg, ArrayList<Shape2> shapeSpecsArray, Object clipArea) { 1781 ArrayList<Shape2> shapeSpecs2 = null; 1782 ArrayList<Shape2> tempShapes = null; 1783 try { 1784 if (shapeSpecsArray == null || shapeSpecsArray.size() == 0) { 1785 return null; 1786 } 1787 1788 shapeSpecs2 = new ArrayList(); 1789 int j = 0; 1790 ArrayList<Shape2> shapeSpecs = new ArrayList(); 1791 int n = shapeSpecsArray.size(); 1792 //for(j=0;j<shapeSpecsArray.size();j++) 1793 for (j = 0; j < n; j++) { 1794 shapeSpecs.add(shapeSpecsArray.get(j)); 1795 } 1796 1797 ArrayList<POINT2> pts = new ArrayList();//use these 1798 Shape shape = null; 1799 POINT2 pt; 1800 double[] coords = new double[6]; 1801 Shape2 shapeSpec = null; 1802 n = shapeSpecs.size(); 1803 //for(j=0;j<shapeSpecs.size();j++) 1804 for (j = 0; j < n; j++) { 1805 shapeSpec = shapeSpecs.get(j); 1806 shape = shapeSpec.getShape(); 1807 pts.clear(); 1808 for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) { 1809 int type = i.currentSegment(coords); 1810 switch (type) { 1811 case PathIterator.SEG_MOVETO: 1812 pt = new POINT2(coords[0], coords[1]); 1813 pt.style = 0; 1814 pts.add(pt); 1815 break; 1816 case PathIterator.SEG_LINETO: 1817 pt = new POINT2(coords[0], coords[1]); 1818 pt.style = 1; 1819 pts.add(pt); 1820 break; 1821 case PathIterator.SEG_QUADTO: //not using this 1822 pt = new POINT2(coords[0], coords[1]); 1823 pt.style = 2; 1824 pts.add(pt); 1825 pt = new POINT2(coords[2], coords[3]); 1826 pt.style = 2; 1827 pts.add(pt); 1828 break; 1829 case PathIterator.SEG_CUBICTO: //not using this 1830 pt = new POINT2(coords[0], coords[1]); 1831 pt.style = 3; 1832 pts.add(pt); 1833 pt = new POINT2(coords[2], coords[3]); 1834 pt.style = 3; 1835 pts.add(pt); 1836 pt = new POINT2(coords[4], coords[5]); 1837 pt.style = 3; 1838 pts.add(pt); 1839 break; 1840 case PathIterator.SEG_CLOSE://not using this 1841 pt = new POINT2(coords[0], coords[1]); 1842 pt.style = 4; 1843 pts.add(pt); 1844 break; 1845 default: 1846 pt = null; 1847 break; 1848 }//end switch 1849 } //end for pathiterator i 1850 tempShapes = buildShapeSpecFromPoints(tg, shapeSpec, pts, clipArea); 1851 shapeSpecs2.addAll(tempShapes); 1852 } 1853 } catch (Exception exc) { 1854 ErrorLogger.LogException(_className, "postClipShapes", 1855 new RendererException("Failed inside postClipShapes", exc)); 1856 } 1857 return shapeSpecs2; 1858 } 1859 1860 /** 1861 * For the 3d map we cannot pre-segment the auto-shapes or fire support 1862 * areas. We do need to pre-segment generic lines regardless of the status 1863 * if clipping is set. Currently we are not pre-segmenting axis of advance 1864 * symbols. 1865 * 1866 * @param tg 1867 * @return true if pre-segmenting is to be used 1868 */ 1869 private static boolean segmentAnticipatedLine(TGLight tg) { 1870 try { 1871 int linetype = tg.get_LineType(); 1872 //do not pre-segment the fire support rectangular and circular areas 1873 if (clsUtility.IsChange1Area(linetype)) { 1874 return false; 1875 } 1876 //do not pre-segment the autoshapes 1877 if (clsUtility.isAutoshape(tg)) { 1878 return false; 1879 } 1880 //temporarily do not pre-segment the channel types. 1881 switch (linetype) { 1882 case TacticalLines.OVERHEAD_WIRE: 1883 case TacticalLines.CATK: 1884 case TacticalLines.CATKBYFIRE: 1885 case TacticalLines.MAIN: 1886 case TacticalLines.SPT: 1887 case TacticalLines.AIRAOA: 1888 case TacticalLines.AAAAA: 1889 return false; 1890 case TacticalLines.MSR_ONEWAY: 1891 case TacticalLines.MSR_TWOWAY: 1892 case TacticalLines.MSR_ALT: 1893 case TacticalLines.ASR_ONEWAY: 1894 case TacticalLines.ASR_TWOWAY: 1895 case TacticalLines.ASR_ALT: 1896 case TacticalLines.ROUTE_ONEWAY: 1897 case TacticalLines.ROUTE_ALT: 1898 //added because of segment data 4-22-13 1899 //removed from this case block since we now post-clip these because of segment color data 10-5-16 1900// case TacticalLines.MSR: 1901// case TacticalLines.ASR: 1902// case TacticalLines.BOUNDARY: 1903 return false; 1904 default: 1905 break; 1906 } 1907 1908 } catch (Exception exc) { 1909 ErrorLogger.LogException(_className, "segmentGenericLine", 1910 new RendererException("Failed inside segmentGenericLine", exc)); 1911 } 1912 return true; 1913 } 1914 1915 /** 1916 * cannot pre-segment the fire support areas, must post segment them after 1917 * the pixels were calculated 1918 * 1919 * @param tg 1920 * @param converter 1921 */ 1922 protected static void postSegmentFSA(TGLight tg, 1923 IPointConversion converter) { 1924 try { 1925 if (tg.get_Client().equals("2D")) { 1926 return; 1927 } 1928 1929 int linetype = tg.get_LineType(); 1930 switch (linetype) { 1931 case TacticalLines.PAA_RECTANGULAR: 1932 case TacticalLines.FSA_RECTANGULAR: 1933 case TacticalLines.SHIP_AOI_RECTANGULAR: 1934 case TacticalLines.DEFENDED_AREA_RECTANGULAR: 1935 case TacticalLines.FFA_RECTANGULAR: 1936 case TacticalLines.ACA_RECTANGULAR: 1937 case TacticalLines.NFA_RECTANGULAR: 1938 case TacticalLines.RFA_RECTANGULAR: 1939 case TacticalLines.ATI_RECTANGULAR: 1940 case TacticalLines.CFFZ_RECTANGULAR: 1941 case TacticalLines.SENSOR_RECTANGULAR: 1942 case TacticalLines.CENSOR_RECTANGULAR: 1943 case TacticalLines.DA_RECTANGULAR: 1944 case TacticalLines.CFZ_RECTANGULAR: 1945 case TacticalLines.ZOR_RECTANGULAR: 1946 case TacticalLines.TBA_RECTANGULAR: 1947 case TacticalLines.TVAR_RECTANGULAR: 1948 case TacticalLines.KILLBOXBLUE_RECTANGULAR: 1949 case TacticalLines.KILLBOXPURPLE_RECTANGULAR: 1950 break; 1951 default: 1952 return; 1953 } 1954 ArrayList<POINT2> latLongs = new ArrayList(); 1955 ArrayList<POINT2> resultPts = new ArrayList(); 1956 int j = 0, k = 0, n = 0; 1957 POINT2 pt0 = null, pt1 = null, pt = null; 1958 double dist = 0; 1959 //double interval=1000000; 1960 double interval = 250000; 1961 double az = 0; 1962 1963 double maxDist = 0; 1964 Point2D pt2d = null; 1965 int t = tg.Pixels.size(); 1966 //for(j=0;j<tg.Pixels.size();j++) 1967 for (j = 0; j < t; j++) { 1968 pt0 = tg.Pixels.get(j); 1969 pt2d = new Point2D.Double(pt0.x, pt0.y); 1970 pt2d = converter.PixelsToGeo(pt2d); 1971 pt0 = new POINT2(pt2d.getX(), pt2d.getY()); 1972 latLongs.add(pt0); 1973 } 1974 t = latLongs.size(); 1975 //for(j=0;j<latLongs.size()-1;j++) 1976 for (j = 0; j < t - 1; j++) { 1977 pt0 = latLongs.get(j); 1978 pt1 = latLongs.get(j + 1); 1979 pt1.style = -1;//end point 1980 az = mdlGeodesic.GetAzimuth(pt0, pt1); 1981 dist = mdlGeodesic.geodesic_distance(latLongs.get(j), latLongs.get(j + 1), null, null); 1982 if (dist > maxDist) { 1983 maxDist = dist; 1984 } 1985 } 1986 1987 if (interval > maxDist) { 1988 interval = maxDist; 1989 } 1990 1991 //for(j=0;j<latLongs.size()-1;j++) 1992 for (j = 0; j < t - 1; j++) { 1993 pt0 = new POINT2(latLongs.get(j)); 1994 pt0.style = 0;//anchor point 1995 pt1 = new POINT2(latLongs.get(j + 1)); 1996 pt1.style = 0;//anchor point point 1997 az = mdlGeodesic.GetAzimuth(pt0, pt1); 1998 dist = mdlGeodesic.geodesic_distance(latLongs.get(j), latLongs.get(j + 1), null, null); 1999 2000 n = (int) (dist / interval); 2001 if (j == 0) { 2002 resultPts.add(pt0); 2003 } 2004 2005 for (k = 1; k <= n; k++) { 2006 pt = mdlGeodesic.geodesic_coordinate(pt0, interval * k, az); 2007 pt.style = -2; 2008 //we do not want the last segment to be too close to the anchor point 2009 //only add the segment point if it is a distance at least half the inteval 2010 //from the 2nd anchor point 2011 dist = mdlGeodesic.geodesic_distance(pt, pt1, null, null); 2012 if (dist >= interval / 2) { 2013 resultPts.add(pt); 2014 } 2015 } 2016 //ad the 2nd anchor point 2017 resultPts.add(pt1); 2018 } 2019 latLongs = resultPts; 2020 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(latLongs, converter); 2021 } catch (Exception exc) { 2022 ErrorLogger.LogException(_className, "postSegmentFSA", 2023 new RendererException("Failed inside postSegmentFSA", exc)); 2024 } 2025 } 2026 2027 /** 2028 * Similar to Vincenty algorithm for more accurate interpolation of geo 2029 * anchor points 2030 * 2031 * @return the interpolated points 2032 */ 2033 private static ArrayList<POINT2> toGeodesic(TGLight tg, double interval, HashMap<Integer,String> hmap) { 2034 ArrayList<POINT2> locs = new ArrayList<POINT2>(); 2035 try { 2036 int i = 0, k = 0, n = 0; 2037 ArrayList<POINT2> points = tg.LatLongs; 2038 String H = ""; 2039 String color = ""; 2040 boolean bolIsAC = false; 2041 int acWidth = 0; 2042 int linetype = tg.get_LineType(); 2043 switch (linetype) { 2044 case TacticalLines.AC: 2045 case TacticalLines.LLTR: 2046 case TacticalLines.MRR: 2047 case TacticalLines.SL: 2048 case TacticalLines.SAAFR: 2049 case TacticalLines.TC: 2050 case TacticalLines.SC: 2051 bolIsAC = true; 2052 break; 2053 default: 2054 break; 2055 } 2056 for (i = 0; i < points.size() - 1; i++) { 2057 if(bolIsAC) 2058 acWidth=points.get(i).style; 2059 // Convert coordinates from degrees to Radians 2060 //var lat1 = points[i].latitude * (PI / 180); 2061 //var lon1 = points[i].longitude * (PI / 180); 2062 //var lat2 = points[i + 1].latitude * (PI / 180); 2063 //var lon2 = points[i + 1].longitude * (PI / 180); 2064 double lat1 = Math.toRadians(points.get(i).y); 2065 double lon1 = Math.toRadians(points.get(i).x); 2066 double lat2 = Math.toRadians(points.get(i + 1).y); 2067 double lon2 = Math.toRadians(points.get(i + 1).x); 2068 // Calculate the total extent of the route 2069 //var d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cos(lat1) * cos(lat2) * pow((sin((lon1 - lon2) / 2)), 2))); 2070 double d = 2 * Math.asin(Math.sqrt(Math.pow((Math.sin((lat1 - lat2) / 2)), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow((Math.sin((lon1 - lon2) / 2)), 2))); 2071 2072 double dist = mdlGeodesic.geodesic_distance(points.get(i), points.get(i + 1), null, null); 2073 //double dist=d; 2074 float flt = (float) dist / (float) interval; 2075 n = Math.round(flt); 2076 if (n < 1) { 2077 n = 1; 2078 } 2079 if (n > 32) { 2080 n = 32; 2081 } 2082 // Calculate positions at fixed intervals along the route 2083 for (k = 0; k <= n; k++) { 2084 //we must preserve the anchor points 2085 if (k == 0) { 2086 locs.add(new POINT2(points.get(i))); 2087 if (hmap != null && hmap.containsKey(i)) { 2088 if (!H.isEmpty()) { 2089 H += ","; 2090 } 2091 color = (String) hmap.get(i); 2092 H += Integer.toString(locs.size() - 1) + ":" + color; 2093 } 2094 continue; 2095 } else if (k == n) { 2096 if (i == points.size() - 2) { 2097 locs.add(new POINT2(points.get(i + 1))); 2098 if (hmap != null && hmap.containsKey(i + 1)) { 2099 if (!H.isEmpty()) { 2100 H += ","; 2101 } 2102 color = (String) hmap.get(i + 1); 2103 H += Integer.toString(locs.size() - 1) + ":" + color; 2104 } 2105 } 2106 break; 2107 } 2108 //var f = (k / n); 2109 //var A = sin((1 - f) * d) / sin(d); 2110 //var B = sin(f * d) / sin(d); 2111 double f = ((double) k / (double) n); 2112 double A = Math.sin((1 - f) * d) / Math.sin(d); 2113 double B = Math.sin(f * d) / Math.sin(d); 2114 // Obtain 3D Cartesian coordinates of each point 2115 //var x = A * cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2); 2116 //var y = A * cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2); 2117 //var z = A * sin(lat1) + B * sin(lat2); 2118 double x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2); 2119 double y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2); 2120 double z = A * Math.sin(lat1) + B * Math.sin(lat2); 2121 // Convert these to latitude/longitude 2122 //var lat = atan2(z, sqrt(pow(x, 2) + pow(y, 2))); 2123 //var lon = atan2(y, x); 2124 double lat = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))); 2125 double lon = Math.atan2(y, x); 2126 lat *= 180.0 / Math.PI; 2127 lon *= 180.0 / Math.PI; 2128 POINT2 pt = new POINT2(lon, lat); 2129 if(bolIsAC) 2130 pt.style=-acWidth; 2131 locs.add(pt); 2132 if (hmap != null && hmap.containsKey(i)) { 2133 if (!H.isEmpty()) { 2134 H += ","; 2135 } 2136 color = (String) hmap.get(i); 2137 H += Integer.toString(locs.size() - 1) + ":" + color; 2138 } 2139 } 2140 } 2141 if (!H.isEmpty()) { 2142 tg.set_H(H); 2143 } 2144 } catch (Exception exc) { 2145 ErrorLogger.LogException(_className, "toGeodesic", 2146 new RendererException("Failed inside toGeodesic", exc)); 2147 return null; 2148 } 2149 return locs; 2150 } 2151 2152 /** 2153 * Pre-segment the lines based on max or min latitude for the segment 2154 * interval. This is necessary because GeoPixelconversion does not work well 2155 * over distance greater than 1M meters, especially at extreme latitudes. 2156 * 2157 * @param tg 2158 * @param converter 2159 */ 2160 protected static void SegmentGeoPoints(TGLight tg, 2161 IPointConversion converter, 2162 double zoomFactor) { 2163 try { 2164 if (tg.get_Client().equals("2D")) { 2165 return; 2166 } 2167 2168 ArrayList<POINT2> resultPts = new ArrayList(); 2169 int lineType = tg.get_LineType(); 2170 //double interval=1000000; 2171 double interval = 250000; 2172 boolean bolSegmentAC = false, bolIsAC = false; 2173 bolSegmentAC = true; 2174 //conservative interval in meters 2175 //return early for those lines not requiring pre-segmenting geo points 2176 switch (lineType) { 2177 case TacticalLines.AC: 2178 case TacticalLines.LLTR: 2179 case TacticalLines.MRR: 2180 case TacticalLines.SL: 2181 case TacticalLines.SAAFR: 2182 case TacticalLines.TC: 2183 case TacticalLines.SC: 2184 if (!bolSegmentAC) { 2185 return; 2186 } 2187 bolIsAC = true; 2188 break; 2189 case TacticalLines.PLD: 2190 case TacticalLines.CFL: 2191 case TacticalLines.UNSP: 2192 case TacticalLines.TRIPLE: 2193 case TacticalLines.DOUBLEC: 2194 case TacticalLines.SINGLEC: 2195 case TacticalLines.ATDITCH: 2196 case TacticalLines.ATDITCHC: 2197 case TacticalLines.ATDITCHM: 2198 case TacticalLines.ATWALL: 2199 case TacticalLines.LINE: 2200 case TacticalLines.DIRATKAIR: 2201 case TacticalLines.STRONG: 2202 case TacticalLines.ENCIRCLE: 2203 case TacticalLines.FLOT: 2204 case TacticalLines.ZONE: 2205 case TacticalLines.OBSAREA: 2206 case TacticalLines.OBSFAREA: 2207 case TacticalLines.FORT_REVD: 2208 case TacticalLines.FORT: 2209 case TacticalLines.FORTL: 2210 break; 2211 case TacticalLines.HWFENCE: 2212 case TacticalLines.LWFENCE: 2213 case TacticalLines.DOUBLEA: 2214 case TacticalLines.DFENCE: 2215 case TacticalLines.SFENCE: 2216 interval = 500000; 2217 break; 2218 case TacticalLines.LC: 2219 interval = 2000000; 2220 break; 2221 default: 2222 //if the line is an anticipated generic line then segment the line 2223 if (segmentAnticipatedLine(tg)) { 2224 break; 2225 } 2226 return; 2227 } 2228 2229 int j = 0, k = 0, n = 0; 2230 POINT2 pt0 = null, pt1 = null, pt = null; 2231 double dist = 0; 2232 double az = 0; 2233 2234 double maxDist = 0; 2235 int t = tg.LatLongs.size(); 2236 //for(j=0;j<tg.LatLongs.size()-1;j++) 2237 for (j = 0; j < t - 1; j++) { 2238 pt0 = tg.LatLongs.get(j); 2239 pt1 = tg.LatLongs.get(j + 1); 2240 if(!bolIsAC) 2241 pt1.style = -1;//end point 2242 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2243 dist = mdlGeodesic.geodesic_distance(tg.LatLongs.get(j), tg.LatLongs.get(j + 1), null, null); 2244 if (dist > maxDist) { 2245 maxDist = dist; 2246 } 2247 } 2248 2249 if (interval > maxDist) { 2250 interval = maxDist; 2251 } 2252 2253 if (zoomFactor > 0 && zoomFactor < 0.01) { 2254 zoomFactor = 0.01; 2255 } 2256 if (zoomFactor > 0 && zoomFactor < 1) { 2257 interval *= zoomFactor; 2258 } 2259 2260 boolean useVincenty = false; 2261 String H = ""; 2262 String color = ""; 2263 HashMap<Integer,String> hmap = clsUtility.getMSRSegmentColorStrings(tg); 2264 if (hmap != null) { 2265 tg.set_H(""); 2266 } 2267 //uncomment one line to use (similar to) Vincenty algorithm 2268 useVincenty = true; 2269 if (useVincenty) { 2270 resultPts = toGeodesic(tg, interval, hmap); 2271 tg.LatLongs = resultPts; 2272 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(tg.LatLongs, converter); 2273 return; 2274 } 2275 2276 for (j = 0; j < tg.LatLongs.size() - 1; j++) { 2277 pt0 = new POINT2(tg.LatLongs.get(j)); 2278 pt0.style = 0;//anchor point 2279 pt1 = new POINT2(tg.LatLongs.get(j + 1)); 2280 pt1.style = 0;//anchor point point 2281 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2282 dist = mdlGeodesic.geodesic_distance(tg.LatLongs.get(j), tg.LatLongs.get(j + 1), null, null); 2283 2284 n = (int) (dist / interval); 2285 if (j == 0) { 2286 resultPts.add(pt0); 2287 if (hmap != null && hmap.containsKey(j)) { 2288 if (!H.isEmpty()) { 2289 H += ","; 2290 } 2291 color = (String) hmap.get(j); 2292 //H+=(resultPts.size()-1).toString()+":"+color; 2293 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2294 } 2295 } 2296 for (k = 1; k <= n; k++) { 2297 pt = mdlGeodesic.geodesic_coordinate(pt0, interval * k, az); 2298 pt.style = -2; 2299 //we do not want the last segment to be too close to the anchor point 2300 //only add the segment point if it is a distance at least half the inteval 2301 //from the 2nd anchor point 2302 dist = mdlGeodesic.geodesic_distance(pt, pt1, null, null); 2303 if (dist >= interval / 2) { 2304 resultPts.add(pt); 2305 if (hmap != null && hmap.containsKey(j)) { 2306 color = (String) hmap.get(j); 2307 if (!H.isEmpty()) { 2308 H += ","; 2309 } 2310 //H+=(resultPts.size()-1).toString()+":"+color; 2311 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2312 } 2313 } 2314 } 2315 //ad the 2nd anchor point 2316 resultPts.add(pt1); 2317 if (hmap != null && hmap.containsKey(j + 1)) { 2318 if (!H.isEmpty()) { 2319 H += ","; 2320 } 2321 color = (String) hmap.get(j + 1); 2322 //H+=(resultPts.size()-1).toString()+":"+color; 2323 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2324 } 2325 } 2326 if (!H.isEmpty()) { 2327 tg.set_H(H); 2328 } 2329 tg.LatLongs = resultPts; 2330 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(tg.LatLongs, converter); 2331 } catch (Exception exc) { 2332 ErrorLogger.LogException(_className, "SegmentGeoPoints", 2333 new RendererException("Failed inside SegmentGeoPoints", exc)); 2334 } 2335 } 2336 2337}