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