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(), tg.get_patternScale()); 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(), tg.get_patternScale()); 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(), tg.get_patternScale()); 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(), tg.get_patternScale()); 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.TRIP: 1343 case TacticalLines.OVERHEAD_WIRE: 1344 case TacticalLines.NFL: 1345 case TacticalLines.MFP: 1346 case TacticalLines.RFL: 1347 case TacticalLines.AT: 1348 case TacticalLines.SERIES: 1349 case TacticalLines.STRIKWARN: 1350 case TacticalLines.SMOKE: 1351 case TacticalLines.BOMB: 1352 case TacticalLines.FSA: 1353 case TacticalLines.ACA: 1354 case TacticalLines.FFA: 1355 case TacticalLines.NFA: 1356 case TacticalLines.RFA: 1357 case TacticalLines.PAA: 1358 case TacticalLines.ATI: 1359 case TacticalLines.CFFZ: 1360 case TacticalLines.CFZ: 1361 case TacticalLines.SENSOR: 1362 case TacticalLines.CENSOR: 1363 case TacticalLines.DA: 1364 case TacticalLines.ZOR: 1365 case TacticalLines.TBA: 1366 case TacticalLines.TVAR: 1367 case TacticalLines.KILLBOXBLUE: 1368 case TacticalLines.KILLBOXPURPLE: 1369// case TacticalLines.MSR: 1370// case TacticalLines.ASR: 1371 case TacticalLines.MSR_ONEWAY: 1372 case TacticalLines.MSR_TWOWAY: 1373 case TacticalLines.MSR_ALT: 1374 case TacticalLines.ASR_ONEWAY: 1375 case TacticalLines.ASR_TWOWAY: 1376 case TacticalLines.ASR_ALT: 1377 case TacticalLines.ROUTE_ONEWAY: 1378 case TacticalLines.ROUTE_ALT: 1379 case TacticalLines.DHA_REVD: 1380 case TacticalLines.DHA: 1381 case TacticalLines.EPW: 1382 case TacticalLines.FARP: 1383 case TacticalLines.RHA: 1384 case TacticalLines.BSA: 1385 case TacticalLines.DSA: 1386 case TacticalLines.CSA: 1387 case TacticalLines.RSA: 1388 case TacticalLines.TGMF: 1389 return true; 1390 case TacticalLines.MSR: //post clip these so there are identical points regardless whether segment data is set 10-5-16 1391 case TacticalLines.ASR: 1392 case TacticalLines.ROUTE: 1393 case TacticalLines.BOUNDARY: 1394 return false; 1395 default: 1396 return false; 1397 } 1398 } catch (Exception exc) { 1399 ErrorLogger.LogException(_className, "canClipPoints", 1400 new RendererException("Failed inside canClipPoints", exc)); 1401 } 1402 return false; 1403 } 1404 1405 /** 1406 * These get clipped so the fill must be treated as a separate shape. 1407 * Normally lines with fill do not have a separate shape for the fill. 1408 * 1409 * @param linetype 1410 * @return 1411 */ 1412 protected static boolean LinesWithSeparateFill(int linetype, ArrayList<Shape2> shapes) { 1413 if (shapes == null) { 1414 return false; 1415 } 1416 1417 switch (linetype) { 1418 case TacticalLines.MSDZ: 1419 return true; 1420 //treat these as lines: because of the feint they need an extra shape for the fill 1421 case TacticalLines.OBSFAREA: 1422 case TacticalLines.OBSAREA: 1423 case TacticalLines.STRONG: 1424 case TacticalLines.ZONE: 1425 case TacticalLines.FORT_REVD: 1426 case TacticalLines.FORT: 1427 case TacticalLines.ENCIRCLE: 1428 //return true; 1429 case TacticalLines.FIX: 1430 case TacticalLines.BOUNDARY: 1431 case TacticalLines.FLOT: 1432 case TacticalLines.LC: 1433 case TacticalLines.PL: 1434 case TacticalLines.FEBA: 1435 case TacticalLines.LL: 1436 case TacticalLines.EWL: 1437 case TacticalLines.AC: 1438 case TacticalLines.MRR: 1439 case TacticalLines.SL: 1440 case TacticalLines.TC: 1441 case TacticalLines.SAAFR: 1442 case TacticalLines.SC: 1443 case TacticalLines.LLTR: 1444 case TacticalLines.DIRATKAIR: 1445 case TacticalLines.DIRATKGND: 1446 case TacticalLines.DIRATKSPT: 1447 case TacticalLines.FCL: 1448 case TacticalLines.HOLD: 1449 case TacticalLines.BRDGHD: 1450 case TacticalLines.HOLD_GE: 1451 case TacticalLines.BRDGHD_GE: 1452 case TacticalLines.LOA: 1453 case TacticalLines.LOD: 1454 case TacticalLines.LDLC: 1455 case TacticalLines.PLD: 1456 case TacticalLines.RELEASE: 1457 case TacticalLines.HOL: 1458 case TacticalLines.BHL: 1459 case TacticalLines.LINE: 1460 case TacticalLines.ABATIS: 1461 case TacticalLines.ATDITCH: 1462 case TacticalLines.ATDITCHC: 1463 case TacticalLines.ATDITCHM: 1464 case TacticalLines.ATWALL: 1465 case TacticalLines.MNFLDFIX: 1466 case TacticalLines.UNSP: 1467 case TacticalLines.SFENCE: 1468 case TacticalLines.DFENCE: 1469 case TacticalLines.DOUBLEA: 1470 case TacticalLines.LWFENCE: 1471 case TacticalLines.HWFENCE: 1472 case TacticalLines.SINGLEC: 1473 case TacticalLines.DOUBLEC: 1474 case TacticalLines.TRIPLE: 1475 case TacticalLines.FORTL: 1476 case TacticalLines.LINTGT: 1477 case TacticalLines.LINTGTS: 1478 case TacticalLines.FSCL: 1479 case TacticalLines.BCL_REVD: 1480 case TacticalLines.BCL: 1481 case TacticalLines.ICL: 1482 case TacticalLines.IFF_OFF: 1483 case TacticalLines.IFF_ON: 1484 case TacticalLines.GENERIC_LINE: 1485 case TacticalLines.CFL: 1486 case TacticalLines.TRIP: 1487 case TacticalLines.NFL: 1488 case TacticalLines.MFP: 1489 case TacticalLines.RFL: 1490 case TacticalLines.MSR: 1491 case TacticalLines.MSR_ONEWAY: 1492 case TacticalLines.MSR_TWOWAY: 1493 case TacticalLines.MSR_ALT: 1494 case TacticalLines.ASR: 1495 case TacticalLines.ASR_ONEWAY: 1496 case TacticalLines.ASR_TWOWAY: 1497 case TacticalLines.ASR_ALT: 1498 case TacticalLines.ROUTE: 1499 case TacticalLines.ROUTE_ONEWAY: 1500 case TacticalLines.ROUTE_ALT: 1501 //undo any fill 1502 Shape2 shape = null; 1503 if (shapes != null && shapes.size() > 0) { 1504 int n = shapes.size(); 1505 //for(int j=0;j<shapes.size();j++) 1506 for (int j = 0; j < n; j++) { 1507 shape = shapes.get(j); 1508 if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) { 1509 shapes.get(j).setFillColor(null); 1510 } 1511 } 1512 } 1513 return true; 1514 default: 1515 return false; 1516 1517 } 1518 } 1519 1520 /** 1521 * uses a hash map to set the POINT2 style when creating tg.Pixels from 1522 * Point2D ArrayList 1523 * 1524 * @param pts2d 1525 * @param hashMap 1526 * @return 1527 */ 1528 protected static ArrayList<POINT2> Point2DtoPOINT2Mapped(ArrayList<Point2D> pts2d, Map<String, Object> hashMap) { 1529 ArrayList<POINT2> pts = new ArrayList(); 1530 try { 1531 Point2D pt2d; 1532 int style = 0; 1533 int n = pts2d.size(); 1534 //for(int j=0;j<pts2d.size();j++) 1535 for (int j = 0; j < n; j++) { 1536 pt2d = pts2d.get(j); 1537 //the hash map contains the original tg.Pixels before clipping 1538 if (hashMap.containsValue(pt2d)) { 1539 style = 0; 1540 } else { 1541 style = -1; //style set to -1 identifies it as a clip bounds point 1542 } 1543 pts.add(new POINT2(pts2d.get(j).getX(), pts2d.get(j).getY(), style)); 1544 } 1545 } catch (Exception exc) { 1546 ErrorLogger.LogException(_className, "Point2DToPOINT2Mapped", 1547 new RendererException("Failed inside Point2DToPOINT2Mapped", exc)); 1548 } 1549 return pts; 1550 } 1551 1552 protected static ArrayList<POINT2> Point2DtoPOINT2(ArrayList<Point2D> pts2d) { 1553 ArrayList<POINT2> pts = new ArrayList(); 1554 try { 1555 int n = pts2d.size(); 1556 //for(int j=0;j<pts2d.size();j++) 1557 for (int j = 0; j < n; j++) { 1558 pts.add(new POINT2(pts2d.get(j).getX(), pts2d.get(j).getY())); 1559 } 1560 } catch (Exception exc) { 1561 ErrorLogger.LogException(_className, "Point2DToPOINT2", 1562 new RendererException("Failed inside Point2DToPOINT2", exc)); 1563 } 1564 return pts; 1565 } 1566 1567 protected static ArrayList<Point2D> POINT2toPoint2D(ArrayList<POINT2> pts) { 1568 ArrayList<Point2D> pts2d = new ArrayList(); 1569 try { 1570 int n = pts.size(); 1571 //for(int j=0;j<pts.size();j++) 1572 for (int j = 0; j < n; j++) { 1573 pts2d.add(new Point2D.Double(pts.get(j).x, pts.get(j).y)); 1574 } 1575 1576 } catch (Exception exc) { 1577 ErrorLogger.LogException(_className, "POINT2toPoint2D", 1578 new RendererException("Failed inside POINT2toPoint2D", exc)); 1579 } 1580 return pts2d; 1581 } 1582 1583 /** 1584 * Builds a single shape from a point array. Currently we assume the array 1585 * represents a moveTo followed by a series of lineTo operations 1586 * 1587 * @param pts2d 1588 * @return 1589 */ 1590 private static Shape BuildShapeFromPoints(ArrayList<Point2D> pts2d) { 1591 GeneralPath shape = new GeneralPath(); 1592 try { 1593 shape.moveTo(pts2d.get(0).getX(), pts2d.get(0).getY()); 1594 int n = pts2d.size(); 1595 //for(int j=1;j<pts2d.size();j++) 1596 for (int j = 1; j < n; j++) { 1597 shape.lineTo(pts2d.get(j).getX(), pts2d.get(j).getY()); 1598 } 1599 } catch (Exception exc) { 1600 ErrorLogger.LogException(_className, "buildShapeFromPoints", 1601 new RendererException("Failed inside buildShapeFromPoints", exc)); 1602 1603 } 1604 return shape; 1605 } 1606 1607 /** 1608 * Clips a ShapeSpec. Assumes we are not post clipping splines, therefore 1609 * all the operations are moveTo, lineTo. Each ShapeSpec is assumed to be: 1610 * moveTo, lineTo ... lineTo, followed by another moveTo, lineTo, ... 1611 * lineTo, followed by ... 1612 * 1613 * @param shapeSpec 1614 * @param pts 1615 * @param clipArea 1616 * @return a single clipped shapeSpec 1617 */ 1618 protected static ArrayList<Shape2> buildShapeSpecFromPoints(TGLight tg0, 1619 Shape2 shapeSpec, //the original ShapeSpec 1620 ArrayList<POINT2> pts, 1621 Object clipArea) { 1622 ArrayList<Shape2> shapeSpecs2 = null; 1623 Shape2 shapeSpec2; 1624 try { 1625 //create a tg to use for the clip 1626 shapeSpecs2 = new ArrayList(); 1627 int j = 0, n = 0; 1628 //return null if it is outside the bounds 1629 Rectangle rect = shapeSpec.getBounds(); 1630 int h = shapeSpec.getBounds().height; 1631 int w = shapeSpec.getBounds().width; 1632 int x = shapeSpec.getBounds().x; 1633 int y = shapeSpec.getBounds().y; 1634// if(h==0 && w==0) 1635// return shapeSpecs2; 1636 1637 if (h == 0) { 1638 h = 1; 1639 } 1640 if (w == 0) { 1641 w = 1; 1642 } 1643 1644 Rectangle2D clipBounds = null; 1645 ArrayList<Point2D> clipPoints = null; 1646 if (clipArea != null && clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) { 1647 clipBounds = (Rectangle2D) clipArea; 1648 } else if (clipArea != null && clipArea.getClass().isAssignableFrom(Rectangle.class)) { 1649 //clipBounds=(Rectangle2D)clipArea; 1650 Rectangle rectx = (Rectangle) clipArea; 1651 clipBounds = new Rectangle2D.Double(rectx.x, rectx.y, rectx.width, rectx.height); 1652 } else if (clipArea != null && clipArea.getClass().isAssignableFrom(ArrayList.class)) { 1653 clipPoints = (ArrayList<Point2D>) clipArea; 1654 } 1655 1656 if (clipBounds != null && clipBounds.contains(shapeSpec.getShape().getBounds2D()) == false 1657 && clipBounds.intersects(shapeSpec.getShape().getBounds2D()) == false) { 1658 //this tests if the shape has height or width 0 1659 //but may be contained within the clipbounds or intersect it 1660 //in that case we gave it a default width or thickness of 1 1661 if (clipBounds.contains(x, y, w, h) == false 1662 && clipBounds.intersects(x, y, w, h) == false) { 1663 return shapeSpecs2; 1664 } 1665 } else if (clipPoints != null) { 1666 GeneralPath poly = new GeneralPath(); 1667 n = clipPoints.size(); 1668 //for(j=0;j<clipPoints.size();j++) 1669 for (j = 0; j < n; j++) { 1670 if (j == 0) { 1671 poly.moveTo(clipPoints.get(j).getX(), clipPoints.get(j).getY()); 1672 } else { 1673 poly.lineTo(clipPoints.get(j).getX(), clipPoints.get(j).getY()); 1674 } 1675 } 1676 poly.closePath(); 1677 if (poly.contains(shapeSpec.getShape().getBounds2D()) == false 1678 && poly.intersects(shapeSpec.getShape().getBounds2D()) == false) { 1679 if (poly.contains(x, y, w, h) == false 1680 && poly.intersects(x, y, w, h) == false) { 1681 return shapeSpecs2; 1682 } 1683 } 1684 } 1685 1686 if (shapeSpec.getShapeType() == Shape2.SHAPE_TYPE_MODIFIER 1687 || shapeSpec.getShapeType() == Shape2.SHAPE_TYPE_MODIFIER_FILL) { 1688 shapeSpecs2.add(shapeSpec); 1689 return shapeSpecs2; 1690 } 1691 TGLight tg = new TGLight(); 1692 POINT2 pt = null; 1693 tg.set_LineType(TacticalLines.PL); 1694 ArrayList<POINT2> pts2 = new ArrayList(); 1695 ArrayList<Point2D> pts2d = null; 1696 Shape shape = null; 1697 GeneralPath gp = new GeneralPath(); 1698 //loop through the points 1699 n = pts.size(); 1700 //for(j=0;j<pts.size();j++) 1701 for (j = 0; j < n; j++) { 1702 pt = pts.get(j); 1703 //new line 1704 switch (pt.style) { 1705 case 0: //moveTo, 1706 //they lifted the pencil, so we build the shape from the existing pts and append it 1707 if (pts2.size() > 1) { 1708 //clip the points 1709 tg = new TGLight(); 1710 tg.set_LineType(TacticalLines.PL); 1711 tg.Pixels = pts2; 1712 if (clipBounds != null) { 1713 pts2d = clsClipPolygon2.ClipPolygon(tg, clipBounds); 1714 } else if (clipPoints != null && !clipPoints.isEmpty()) { 1715 pts2d = clsClipQuad.ClipPolygon(tg, clipPoints); 1716 } 1717 1718 //build a GeneralPath from the points we collected, we will append it 1719 if (pts2d != null && pts2d.size() > 1) { 1720 shape = BuildShapeFromPoints(pts2d); 1721 //append the shape because we want to return only one shape 1722 gp.append(shape, false); 1723 } 1724 //clear the points array and begin the next line 1725 pts2.clear(); 1726 pts2.add(pt); 1727 } else { 1728 pts2.add(pt); 1729 } 1730 break; 1731 case 1: //lineTo 1732 pts2.add(pt); 1733 break; 1734 default: 1735 pts2.add(pt); 1736 break; 1737 } 1738 }//end for 1739 //append the last shape 1740 if (pts2.size() > 1) { 1741 //clip the points 1742 tg = new TGLight(); 1743 tg.set_LineType(TacticalLines.PL); 1744 tg.Pixels = pts2; 1745 if (clipBounds != null) { 1746 pts2d = clsClipPolygon2.ClipPolygon(tg, clipBounds); 1747 } else if (clipPoints != null) { 1748 pts2d = clsClipQuad.ClipPolygon(tg, clipPoints); 1749 } 1750 //build a GeneralPath from the points we collected, we will append it 1751 if (pts2d != null && pts2d.size() > 1) { 1752 shape = BuildShapeFromPoints(pts2d); 1753 gp.append(shape, false); 1754 } 1755 tg0.set_WasClipped(tg.get_WasClipped()); 1756 } 1757 //create the shapespec here 1758 //initialize the clipped ShapeSpec 1759 shapeSpec2 = new Shape2(shapeSpec.getShapeType()); 1760 shapeSpec2.setLineColor(shapeSpec.getLineColor()); 1761 shapeSpec2.setFillColor(shapeSpec.getFillColor()); 1762 shapeSpec2.setStroke(shapeSpec.getStroke()); 1763 shapeSpec2.setTexturePaint(shapeSpec.getTexturePaint()); 1764 shapeSpec2.setShape(gp); 1765 shapeSpecs2.add(shapeSpec2); 1766 } catch (Exception exc) { 1767 ErrorLogger.LogException(_className, "buildShapeSpecFromPoints", 1768 new RendererException("Failed inside buildShapeSpecFromPoints", exc)); 1769 1770 } 1771 return shapeSpecs2; 1772 } 1773 1774 /** 1775 * Currently assumes no MeTOC symbols are post clipped 1776 * 1777 * @param tg 1778 * @param shapeSpecsArray 1779 * @param clipArea 1780 * @return 1781 */ 1782 protected static ArrayList<Shape2> postClipShapes(TGLight tg, ArrayList<Shape2> shapeSpecsArray, Object clipArea) { 1783 ArrayList<Shape2> shapeSpecs2 = null; 1784 ArrayList<Shape2> tempShapes = null; 1785 try { 1786 if (shapeSpecsArray == null || shapeSpecsArray.size() == 0) { 1787 return null; 1788 } 1789 1790 shapeSpecs2 = new ArrayList(); 1791 int j = 0; 1792 ArrayList<Shape2> shapeSpecs = new ArrayList(); 1793 int n = shapeSpecsArray.size(); 1794 //for(j=0;j<shapeSpecsArray.size();j++) 1795 for (j = 0; j < n; j++) { 1796 shapeSpecs.add(shapeSpecsArray.get(j)); 1797 } 1798 1799 ArrayList<POINT2> pts = new ArrayList();//use these 1800 Shape shape = null; 1801 POINT2 pt; 1802 double[] coords = new double[6]; 1803 Shape2 shapeSpec = null; 1804 n = shapeSpecs.size(); 1805 //for(j=0;j<shapeSpecs.size();j++) 1806 for (j = 0; j < n; j++) { 1807 shapeSpec = shapeSpecs.get(j); 1808 shape = shapeSpec.getShape(); 1809 pts.clear(); 1810 for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) { 1811 int type = i.currentSegment(coords); 1812 switch (type) { 1813 case PathIterator.SEG_MOVETO: 1814 pt = new POINT2(coords[0], coords[1]); 1815 pt.style = 0; 1816 pts.add(pt); 1817 break; 1818 case PathIterator.SEG_LINETO: 1819 pt = new POINT2(coords[0], coords[1]); 1820 pt.style = 1; 1821 pts.add(pt); 1822 break; 1823 case PathIterator.SEG_QUADTO: //not using this 1824 pt = new POINT2(coords[0], coords[1]); 1825 pt.style = 2; 1826 pts.add(pt); 1827 pt = new POINT2(coords[2], coords[3]); 1828 pt.style = 2; 1829 pts.add(pt); 1830 break; 1831 case PathIterator.SEG_CUBICTO: //not using this 1832 pt = new POINT2(coords[0], coords[1]); 1833 pt.style = 3; 1834 pts.add(pt); 1835 pt = new POINT2(coords[2], coords[3]); 1836 pt.style = 3; 1837 pts.add(pt); 1838 pt = new POINT2(coords[4], coords[5]); 1839 pt.style = 3; 1840 pts.add(pt); 1841 break; 1842 case PathIterator.SEG_CLOSE://not using this 1843 pt = new POINT2(coords[0], coords[1]); 1844 pt.style = 4; 1845 pts.add(pt); 1846 break; 1847 default: 1848 pt = null; 1849 break; 1850 }//end switch 1851 } //end for pathiterator i 1852 tempShapes = buildShapeSpecFromPoints(tg, shapeSpec, pts, clipArea); 1853 shapeSpecs2.addAll(tempShapes); 1854 } 1855 } catch (Exception exc) { 1856 ErrorLogger.LogException(_className, "postClipShapes", 1857 new RendererException("Failed inside postClipShapes", exc)); 1858 } 1859 return shapeSpecs2; 1860 } 1861 1862 /** 1863 * For the 3d map we cannot pre-segment the auto-shapes or fire support 1864 * areas. We do need to pre-segment generic lines regardless of the status 1865 * if clipping is set. Currently we are not pre-segmenting axis of advance 1866 * symbols. 1867 * 1868 * @param tg 1869 * @return true if pre-segmenting is to be used 1870 */ 1871 private static boolean segmentAnticipatedLine(TGLight tg) { 1872 try { 1873 int linetype = tg.get_LineType(); 1874 //do not pre-segment the fire support rectangular and circular areas 1875 if (clsUtility.IsChange1Area(linetype)) { 1876 return false; 1877 } 1878 //do not pre-segment the autoshapes 1879 if (clsUtility.isAutoshape(tg)) { 1880 return false; 1881 } 1882 //temporarily do not pre-segment the channel types. 1883 switch (linetype) { 1884 case TacticalLines.OVERHEAD_WIRE: 1885 case TacticalLines.CATK: 1886 case TacticalLines.CATKBYFIRE: 1887 case TacticalLines.MAIN: 1888 case TacticalLines.SPT: 1889 case TacticalLines.AIRAOA: 1890 case TacticalLines.AAAAA: 1891 return false; 1892 case TacticalLines.MSR_ONEWAY: 1893 case TacticalLines.MSR_TWOWAY: 1894 case TacticalLines.MSR_ALT: 1895 case TacticalLines.ASR_ONEWAY: 1896 case TacticalLines.ASR_TWOWAY: 1897 case TacticalLines.ASR_ALT: 1898 case TacticalLines.ROUTE_ONEWAY: 1899 case TacticalLines.ROUTE_ALT: 1900 //added because of segment data 4-22-13 1901 //removed from this case block since we now post-clip these because of segment color data 10-5-16 1902// case TacticalLines.MSR: 1903// case TacticalLines.ASR: 1904// case TacticalLines.BOUNDARY: 1905 return false; 1906 default: 1907 break; 1908 } 1909 1910 } catch (Exception exc) { 1911 ErrorLogger.LogException(_className, "segmentGenericLine", 1912 new RendererException("Failed inside segmentGenericLine", exc)); 1913 } 1914 return true; 1915 } 1916 1917 /** 1918 * cannot pre-segment the fire support areas, must post segment them after 1919 * the pixels were calculated 1920 * 1921 * @param tg 1922 * @param converter 1923 */ 1924 protected static void postSegmentFSA(TGLight tg, 1925 IPointConversion converter) { 1926 try { 1927 if (tg.get_Client().equals("2D")) { 1928 return; 1929 } 1930 1931 int linetype = tg.get_LineType(); 1932 switch (linetype) { 1933 case TacticalLines.PAA_RECTANGULAR: 1934 case TacticalLines.FSA_RECTANGULAR: 1935 case TacticalLines.SHIP_AOI_RECTANGULAR: 1936 case TacticalLines.DEFENDED_AREA_RECTANGULAR: 1937 case TacticalLines.FFA_RECTANGULAR: 1938 case TacticalLines.ACA_RECTANGULAR: 1939 case TacticalLines.NFA_RECTANGULAR: 1940 case TacticalLines.RFA_RECTANGULAR: 1941 case TacticalLines.ATI_RECTANGULAR: 1942 case TacticalLines.CFFZ_RECTANGULAR: 1943 case TacticalLines.SENSOR_RECTANGULAR: 1944 case TacticalLines.CENSOR_RECTANGULAR: 1945 case TacticalLines.DA_RECTANGULAR: 1946 case TacticalLines.CFZ_RECTANGULAR: 1947 case TacticalLines.ZOR_RECTANGULAR: 1948 case TacticalLines.TBA_RECTANGULAR: 1949 case TacticalLines.TVAR_RECTANGULAR: 1950 case TacticalLines.KILLBOXBLUE_RECTANGULAR: 1951 case TacticalLines.KILLBOXPURPLE_RECTANGULAR: 1952 break; 1953 default: 1954 return; 1955 } 1956 ArrayList<POINT2> latLongs = new ArrayList(); 1957 ArrayList<POINT2> resultPts = new ArrayList(); 1958 int j = 0, k = 0, n = 0; 1959 POINT2 pt0 = null, pt1 = null, pt = null; 1960 double dist = 0; 1961 //double interval=1000000; 1962 double interval = 250000; 1963 double az = 0; 1964 1965 double maxDist = 0; 1966 Point2D pt2d = null; 1967 int t = tg.Pixels.size(); 1968 //for(j=0;j<tg.Pixels.size();j++) 1969 for (j = 0; j < t; j++) { 1970 pt0 = tg.Pixels.get(j); 1971 pt2d = new Point2D.Double(pt0.x, pt0.y); 1972 pt2d = converter.PixelsToGeo(pt2d); 1973 pt0 = new POINT2(pt2d.getX(), pt2d.getY()); 1974 latLongs.add(pt0); 1975 } 1976 t = latLongs.size(); 1977 //for(j=0;j<latLongs.size()-1;j++) 1978 for (j = 0; j < t - 1; j++) { 1979 pt0 = latLongs.get(j); 1980 pt1 = latLongs.get(j + 1); 1981 pt1.style = -1;//end point 1982 az = mdlGeodesic.GetAzimuth(pt0, pt1); 1983 dist = mdlGeodesic.geodesic_distance(latLongs.get(j), latLongs.get(j + 1), null, null); 1984 if (dist > maxDist) { 1985 maxDist = dist; 1986 } 1987 } 1988 1989 if (interval > maxDist) { 1990 interval = maxDist; 1991 } 1992 1993 //for(j=0;j<latLongs.size()-1;j++) 1994 for (j = 0; j < t - 1; j++) { 1995 pt0 = new POINT2(latLongs.get(j)); 1996 pt0.style = 0;//anchor point 1997 pt1 = new POINT2(latLongs.get(j + 1)); 1998 pt1.style = 0;//anchor point point 1999 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2000 dist = mdlGeodesic.geodesic_distance(latLongs.get(j), latLongs.get(j + 1), null, null); 2001 2002 n = (int) (dist / interval); 2003 if (j == 0) { 2004 resultPts.add(pt0); 2005 } 2006 2007 for (k = 1; k <= n; k++) { 2008 pt = mdlGeodesic.geodesic_coordinate(pt0, interval * k, az); 2009 pt.style = -2; 2010 //we do not want the last segment to be too close to the anchor point 2011 //only add the segment point if it is a distance at least half the inteval 2012 //from the 2nd anchor point 2013 dist = mdlGeodesic.geodesic_distance(pt, pt1, null, null); 2014 if (dist >= interval / 2) { 2015 resultPts.add(pt); 2016 } 2017 } 2018 //ad the 2nd anchor point 2019 resultPts.add(pt1); 2020 } 2021 latLongs = resultPts; 2022 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(latLongs, converter); 2023 } catch (Exception exc) { 2024 ErrorLogger.LogException(_className, "postSegmentFSA", 2025 new RendererException("Failed inside postSegmentFSA", exc)); 2026 } 2027 } 2028 2029 /** 2030 * Similar to Vincenty algorithm for more accurate interpolation of geo 2031 * anchor points 2032 * 2033 * @return the interpolated points 2034 */ 2035 private static ArrayList<POINT2> toGeodesic(TGLight tg, double interval, HashMap<Integer,String> hmap) { 2036 ArrayList<POINT2> locs = new ArrayList<POINT2>(); 2037 try { 2038 int i = 0, k = 0, n = 0; 2039 ArrayList<POINT2> points = tg.LatLongs; 2040 String H = ""; 2041 String color = ""; 2042 boolean bolIsAC = false; 2043 int acWidth = 0; 2044 int linetype = tg.get_LineType(); 2045 switch (linetype) { 2046 case TacticalLines.AC: 2047 case TacticalLines.LLTR: 2048 case TacticalLines.MRR: 2049 case TacticalLines.SL: 2050 case TacticalLines.SAAFR: 2051 case TacticalLines.TC: 2052 case TacticalLines.SC: 2053 bolIsAC = true; 2054 break; 2055 default: 2056 break; 2057 } 2058 for (i = 0; i < points.size() - 1; i++) { 2059 if(bolIsAC) 2060 acWidth=points.get(i).style; 2061 // Convert coordinates from degrees to Radians 2062 //var lat1 = points[i].latitude * (PI / 180); 2063 //var lon1 = points[i].longitude * (PI / 180); 2064 //var lat2 = points[i + 1].latitude * (PI / 180); 2065 //var lon2 = points[i + 1].longitude * (PI / 180); 2066 double lat1 = Math.toRadians(points.get(i).y); 2067 double lon1 = Math.toRadians(points.get(i).x); 2068 double lat2 = Math.toRadians(points.get(i + 1).y); 2069 double lon2 = Math.toRadians(points.get(i + 1).x); 2070 // Calculate the total extent of the route 2071 //var d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cos(lat1) * cos(lat2) * pow((sin((lon1 - lon2) / 2)), 2))); 2072 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))); 2073 2074 double dist = mdlGeodesic.geodesic_distance(points.get(i), points.get(i + 1), null, null); 2075 //double dist=d; 2076 float flt = (float) dist / (float) interval; 2077 n = Math.round(flt); 2078 if (n < 1) { 2079 n = 1; 2080 } 2081 if (n > 32) { 2082 n = 32; 2083 } 2084 // Calculate positions at fixed intervals along the route 2085 for (k = 0; k <= n; k++) { 2086 //we must preserve the anchor points 2087 if (k == 0) { 2088 locs.add(new POINT2(points.get(i))); 2089 if (hmap != null && hmap.containsKey(i)) { 2090 if (!H.isEmpty()) { 2091 H += ","; 2092 } 2093 color = (String) hmap.get(i); 2094 H += Integer.toString(locs.size() - 1) + ":" + color; 2095 } 2096 continue; 2097 } else if (k == n) { 2098 if (i == points.size() - 2) { 2099 locs.add(new POINT2(points.get(i + 1))); 2100 if (hmap != null && hmap.containsKey(i + 1)) { 2101 if (!H.isEmpty()) { 2102 H += ","; 2103 } 2104 color = (String) hmap.get(i + 1); 2105 H += Integer.toString(locs.size() - 1) + ":" + color; 2106 } 2107 } 2108 break; 2109 } 2110 //var f = (k / n); 2111 //var A = sin((1 - f) * d) / sin(d); 2112 //var B = sin(f * d) / sin(d); 2113 double f = ((double) k / (double) n); 2114 double A = Math.sin((1 - f) * d) / Math.sin(d); 2115 double B = Math.sin(f * d) / Math.sin(d); 2116 // Obtain 3D Cartesian coordinates of each point 2117 //var x = A * cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2); 2118 //var y = A * cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2); 2119 //var z = A * sin(lat1) + B * sin(lat2); 2120 double x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2); 2121 double y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2); 2122 double z = A * Math.sin(lat1) + B * Math.sin(lat2); 2123 // Convert these to latitude/longitude 2124 //var lat = atan2(z, sqrt(pow(x, 2) + pow(y, 2))); 2125 //var lon = atan2(y, x); 2126 double lat = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))); 2127 double lon = Math.atan2(y, x); 2128 lat *= 180.0 / Math.PI; 2129 lon *= 180.0 / Math.PI; 2130 POINT2 pt = new POINT2(lon, lat); 2131 if(bolIsAC) 2132 pt.style=-acWidth; 2133 locs.add(pt); 2134 if (hmap != null && hmap.containsKey(i)) { 2135 if (!H.isEmpty()) { 2136 H += ","; 2137 } 2138 color = (String) hmap.get(i); 2139 H += Integer.toString(locs.size() - 1) + ":" + color; 2140 } 2141 } 2142 } 2143 if (!H.isEmpty()) { 2144 tg.set_H(H); 2145 } 2146 } catch (Exception exc) { 2147 ErrorLogger.LogException(_className, "toGeodesic", 2148 new RendererException("Failed inside toGeodesic", exc)); 2149 return null; 2150 } 2151 return locs; 2152 } 2153 2154 /** 2155 * Pre-segment the lines based on max or min latitude for the segment 2156 * interval. This is necessary because GeoPixelconversion does not work well 2157 * over distance greater than 1M meters, especially at extreme latitudes. 2158 * 2159 * @param tg 2160 * @param converter 2161 */ 2162 protected static void SegmentGeoPoints(TGLight tg, 2163 IPointConversion converter, 2164 double zoomFactor) { 2165 try { 2166 if (tg.get_Client().equals("2D")) { 2167 return; 2168 } 2169 2170 ArrayList<POINT2> resultPts = new ArrayList(); 2171 int lineType = tg.get_LineType(); 2172 //double interval=1000000; 2173 double interval = 250000; 2174 boolean bolSegmentAC = false, bolIsAC = false; 2175 bolSegmentAC = true; 2176 //conservative interval in meters 2177 //return early for those lines not requiring pre-segmenting geo points 2178 switch (lineType) { 2179 case TacticalLines.AC: 2180 case TacticalLines.LLTR: 2181 case TacticalLines.MRR: 2182 case TacticalLines.SL: 2183 case TacticalLines.SAAFR: 2184 case TacticalLines.TC: 2185 case TacticalLines.SC: 2186 if (!bolSegmentAC) { 2187 return; 2188 } 2189 bolIsAC = true; 2190 break; 2191 case TacticalLines.PLD: 2192 case TacticalLines.CFL: 2193 case TacticalLines.UNSP: 2194 case TacticalLines.TRIPLE: 2195 case TacticalLines.DOUBLEC: 2196 case TacticalLines.SINGLEC: 2197 case TacticalLines.ATDITCH: 2198 case TacticalLines.ATDITCHC: 2199 case TacticalLines.ATDITCHM: 2200 case TacticalLines.ATWALL: 2201 case TacticalLines.LINE: 2202 case TacticalLines.DIRATKAIR: 2203 case TacticalLines.STRONG: 2204 case TacticalLines.ENCIRCLE: 2205 case TacticalLines.FLOT: 2206 case TacticalLines.ZONE: 2207 case TacticalLines.OBSAREA: 2208 case TacticalLines.OBSFAREA: 2209 case TacticalLines.FORT_REVD: 2210 case TacticalLines.FORT: 2211 case TacticalLines.FORTL: 2212 break; 2213 case TacticalLines.HWFENCE: 2214 case TacticalLines.LWFENCE: 2215 case TacticalLines.DOUBLEA: 2216 case TacticalLines.DFENCE: 2217 case TacticalLines.SFENCE: 2218 interval = 500000; 2219 break; 2220 case TacticalLines.LC: 2221 interval = 2000000; 2222 break; 2223 default: 2224 //if the line is an anticipated generic line then segment the line 2225 if (segmentAnticipatedLine(tg)) { 2226 break; 2227 } 2228 return; 2229 } 2230 2231 int j = 0, k = 0, n = 0; 2232 POINT2 pt0 = null, pt1 = null, pt = null; 2233 double dist = 0; 2234 double az = 0; 2235 2236 double maxDist = 0; 2237 int t = tg.LatLongs.size(); 2238 //for(j=0;j<tg.LatLongs.size()-1;j++) 2239 for (j = 0; j < t - 1; j++) { 2240 pt0 = tg.LatLongs.get(j); 2241 pt1 = tg.LatLongs.get(j + 1); 2242 if(!bolIsAC) 2243 pt1.style = -1;//end point 2244 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2245 dist = mdlGeodesic.geodesic_distance(tg.LatLongs.get(j), tg.LatLongs.get(j + 1), null, null); 2246 if (dist > maxDist) { 2247 maxDist = dist; 2248 } 2249 } 2250 2251 if (interval > maxDist) { 2252 interval = maxDist; 2253 } 2254 2255 if (zoomFactor > 0 && zoomFactor < 0.01) { 2256 zoomFactor = 0.01; 2257 } 2258 if (zoomFactor > 0 && zoomFactor < 1) { 2259 interval *= zoomFactor; 2260 } 2261 2262 boolean useVincenty = false; 2263 String H = ""; 2264 String color = ""; 2265 HashMap<Integer,String> hmap = clsUtility.getMSRSegmentColorStrings(tg); 2266 if (hmap != null) { 2267 tg.set_H(""); 2268 } 2269 //uncomment one line to use (similar to) Vincenty algorithm 2270 useVincenty = true; 2271 if (useVincenty) { 2272 resultPts = toGeodesic(tg, interval, hmap); 2273 tg.LatLongs = resultPts; 2274 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(tg.LatLongs, converter); 2275 return; 2276 } 2277 2278 for (j = 0; j < tg.LatLongs.size() - 1; j++) { 2279 pt0 = new POINT2(tg.LatLongs.get(j)); 2280 pt0.style = 0;//anchor point 2281 pt1 = new POINT2(tg.LatLongs.get(j + 1)); 2282 pt1.style = 0;//anchor point point 2283 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2284 dist = mdlGeodesic.geodesic_distance(tg.LatLongs.get(j), tg.LatLongs.get(j + 1), null, null); 2285 2286 n = (int) (dist / interval); 2287 if (j == 0) { 2288 resultPts.add(pt0); 2289 if (hmap != null && hmap.containsKey(j)) { 2290 if (!H.isEmpty()) { 2291 H += ","; 2292 } 2293 color = (String) hmap.get(j); 2294 //H+=(resultPts.size()-1).toString()+":"+color; 2295 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2296 } 2297 } 2298 for (k = 1; k <= n; k++) { 2299 pt = mdlGeodesic.geodesic_coordinate(pt0, interval * k, az); 2300 pt.style = -2; 2301 //we do not want the last segment to be too close to the anchor point 2302 //only add the segment point if it is a distance at least half the inteval 2303 //from the 2nd anchor point 2304 dist = mdlGeodesic.geodesic_distance(pt, pt1, null, null); 2305 if (dist >= interval / 2) { 2306 resultPts.add(pt); 2307 if (hmap != null && hmap.containsKey(j)) { 2308 color = (String) hmap.get(j); 2309 if (!H.isEmpty()) { 2310 H += ","; 2311 } 2312 //H+=(resultPts.size()-1).toString()+":"+color; 2313 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2314 } 2315 } 2316 } 2317 //ad the 2nd anchor point 2318 resultPts.add(pt1); 2319 if (hmap != null && hmap.containsKey(j + 1)) { 2320 if (!H.isEmpty()) { 2321 H += ","; 2322 } 2323 color = (String) hmap.get(j + 1); 2324 //H+=(resultPts.size()-1).toString()+":"+color; 2325 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2326 } 2327 } 2328 if (!H.isEmpty()) { 2329 tg.set_H(H); 2330 } 2331 tg.LatLongs = resultPts; 2332 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(tg.LatLongs, converter); 2333 } catch (Exception exc) { 2334 ErrorLogger.LogException(_className, "SegmentGeoPoints", 2335 new RendererException("Failed inside SegmentGeoPoints", exc)); 2336 } 2337 } 2338 2339}