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.FEBA: 1317 case TacticalLines.LOA: 1318 case TacticalLines.LL: 1319 case TacticalLines.EWL: 1320 case TacticalLines.FCL: 1321 case TacticalLines.LOD: 1322 case TacticalLines.LDLC: 1323 case TacticalLines.PLD: 1324 case TacticalLines.HOLD: 1325 case TacticalLines.HOLD_GE: 1326 case TacticalLines.RELEASE: 1327 case TacticalLines.HOL: 1328 case TacticalLines.BHL: 1329 case TacticalLines.BRDGHD: 1330 case TacticalLines.BRDGHD_GE: 1331 case TacticalLines.NFL: 1332 minSpikeDistance = arraysupport.getScaledSize(5, tg.get_LineThickness(), tg.get_patternScale()); 1333 segmented = false; 1334 break; 1335 case TacticalLines.ATDITCH: 1336 case TacticalLines.ATDITCHC: 1337 case TacticalLines.ATDITCHM: 1338 case TacticalLines.FLOT: 1339 case TacticalLines.FORT_REVD: 1340 case TacticalLines.FORT: 1341 case TacticalLines.FORTL: 1342 case TacticalLines.STRONG: 1343 minSpikeDistance = arraysupport.getScaledSize(25, tg.get_LineThickness(), tg.get_patternScale()); 1344 break; 1345 case TacticalLines.LC: 1346 case TacticalLines.OBSAREA: 1347 case TacticalLines.OBSFAREA: 1348 case TacticalLines.ENCIRCLE: 1349 case TacticalLines.ZONE: 1350 case TacticalLines.LINE: 1351 case TacticalLines.ATWALL: 1352 //case TacticalLines.ATWALL3D: 1353 case TacticalLines.UNSP: 1354 case TacticalLines.SFENCE: 1355 case TacticalLines.DFENCE: 1356 case TacticalLines.DOUBLEA: 1357 case TacticalLines.LWFENCE: 1358 case TacticalLines.HWFENCE: 1359 case TacticalLines.SINGLEC: 1360 case TacticalLines.DOUBLEC: 1361 case TacticalLines.TRIPLE: 1362 minSpikeDistance = arraysupport.getScaledSize(35, tg.get_LineThickness(), tg.get_patternScale()); 1363 break; 1364 case TacticalLines.ICE_EDGE_RADAR: //METOCs 1365 case TacticalLines.ICE_OPENINGS_FROZEN: 1366 case TacticalLines.CRACKS_SPECIFIC_LOCATION: 1367 minSpikeDistance = arraysupport.getScaledSize(35, tg.get_LineThickness(), tg.get_patternScale()); 1368 break; 1369 default: 1370 return; 1371 } 1372 double dist = 0; 1373 1374 ArrayList<POINT2> pts = new ArrayList(); 1375 1376 //stuff pts with tg.Pixels 1377 //loop through pts to remove any points which are too close 1378 //then reset tg.Pixels with the new array with boundary points removed, 1379 int j = 0; 1380 POINT2 pt = null, pt0 = null, pt1 = null; 1381 int n = tg.Pixels.size(); 1382 //for(j=0;j<tg.Pixels.size();j++) 1383 for (j = 0; j < n; j++) { 1384 pt = tg.Pixels.get(j); 1385 pt.style = tg.Pixels.get(j).style; 1386 pts.add(pt); 1387 } 1388 1389 boolean removedPt = true; 1390 //order of priority is: keep anchor points, then boundary points, then segmented points 1391 outer: 1392 while (removedPt == true) { 1393 removedPt = false; 1394 //n=pts.size(); 1395 for (j = 0; j < pts.size() - 1; j++) { 1396 pt0 = pts.get(j); 1397 pt1 = pts.get(j + 1); 1398 dist = lineutility.CalcDistanceDouble(pts.get(j), pts.get(j + 1)); 1399 if (dist < minSpikeDistance) { 1400 if (segmented == false) { 1401 if (j + 1 == pts.size() - 1) { 1402 pts.remove(j); 1403 } else { 1404 pts.remove(j + 1); 1405 } 1406 1407 removedPt = true; 1408 break outer; 1409 } else if (pt0.style == 0 && pt1.style == -1)//-1 are clipped boundary points 1410 { 1411 pts.remove(j + 1); 1412 removedPt = true; 1413 break outer; 1414 } else if (pt0.style == 0 && pt1.style == -2)//-2 are segmented points, this should never happen 1415 { 1416 pts.remove(j + 1); 1417 removedPt = true; 1418 break outer; 1419 } else if (pt0.style == -1 && pt1.style == 0) { 1420 pts.remove(j); 1421 removedPt = true; 1422 break outer; 1423 } else if (pt0.style == -1 && pt1.style == -1) { 1424 pts.remove(j + 1); 1425 removedPt = true; 1426 break outer; 1427 } else if (pt0.style == -1 && pt1.style == -2) { 1428 pts.remove(j + 1); 1429 removedPt = true; 1430 break outer; 1431 } else if (pt0.style == -2 && pt1.style == 0)//this should never happen 1432 { 1433 pts.remove(j); 1434 removedPt = true; 1435 break outer; 1436 } else if (pt0.style == -2 && pt1.style == -1) { 1437 pts.remove(j); 1438 removedPt = true; 1439 break outer; 1440 } else if (pt0.style == -2 && pt1.style == -2) { 1441 pts.remove(j + 1); 1442 removedPt = true; 1443 break outer; 1444 } 1445 } 1446 //n=pts.size(); 1447 } 1448 } 1449 tg.Pixels = pts; 1450 tg.LatLongs = armyc2.c5isr.RenderMultipoints.clsUtility.PixelsToLatLong(pts, converter); 1451 1452 } catch (Exception exc) { 1453 ErrorLogger.LogException(_className, "FilterPoints2", 1454 new RendererException("Failed inside FilterPoints2", exc)); 1455 1456 } 1457 } 1458 1459 /** 1460 * returns true if the line type can be clipped before calculating the 1461 * shapes 1462 * 1463 * @param tg tactical graphic 1464 * @return true if can pre-clip points 1465 */ 1466 public static Boolean canClipPoints(TGLight tg) { 1467 try { 1468 String symbolId = tg.get_SymbolId(); 1469 if (clsMETOC.IsWeather(symbolId) > 0) { 1470 return true; 1471 } 1472 1473 int linetype = tg.get_LineType(); 1474 switch (linetype) { 1475 case TacticalLines.ABATIS: 1476// case TacticalLines.BOUNDARY: 1477 case TacticalLines.FLOT: 1478 case TacticalLines.LC: 1479 case TacticalLines.PL: 1480 case TacticalLines.FEBA: 1481 case TacticalLines.LL: 1482 case TacticalLines.EWL: 1483 case TacticalLines.GENERAL: 1484 case TacticalLines.JTAA: 1485 case TacticalLines.SAA: 1486 case TacticalLines.SGAA: 1487 case TacticalLines.BS_AREA: 1488 case TacticalLines.BS_LINE: 1489 case TacticalLines.ASSY: 1490 case TacticalLines.EA: 1491 case TacticalLines.FORT_REVD: 1492 case TacticalLines.FORT: 1493 case TacticalLines.DZ: 1494 case TacticalLines.EZ: 1495 case TacticalLines.LZ: 1496 case TacticalLines.PZ: 1497 case TacticalLines.LAA: 1498 case TacticalLines.ROZ: 1499 case TacticalLines.AARROZ: 1500 case TacticalLines.UAROZ: 1501 case TacticalLines.WEZ: 1502 case TacticalLines.FEZ: 1503 case TacticalLines.JEZ: 1504 case TacticalLines.FAADZ: 1505 case TacticalLines.HIDACZ: 1506 case TacticalLines.MEZ: 1507 case TacticalLines.LOMEZ: 1508 case TacticalLines.HIMEZ: 1509 case TacticalLines.WFZ_REVD: 1510 case TacticalLines.WFZ: 1511 case TacticalLines.AIRFIELD: 1512 case TacticalLines.BATTLE: 1513 case TacticalLines.PNO: 1514 case TacticalLines.DIRATKAIR: 1515 case TacticalLines.DIRATKGND: 1516 case TacticalLines.DIRATKSPT: 1517 case TacticalLines.INFILTRATION: 1518 case TacticalLines.FCL: 1519 case TacticalLines.HOLD: 1520 case TacticalLines.BRDGHD: 1521 case TacticalLines.HOLD_GE: 1522 case TacticalLines.BRDGHD_GE: 1523 case TacticalLines.LOA: 1524 case TacticalLines.LOD: 1525 case TacticalLines.LDLC: 1526 case TacticalLines.PLD: 1527 case TacticalLines.ASSAULT: 1528 case TacticalLines.ATKPOS: 1529 case TacticalLines.OBJ: 1530 case TacticalLines.PEN: 1531 case TacticalLines.RELEASE: 1532 case TacticalLines.HOL: 1533 case TacticalLines.BHL: 1534 case TacticalLines.AO: 1535 case TacticalLines.AIRHEAD: 1536 case TacticalLines.ENCIRCLE: 1537 case TacticalLines.NAI: 1538 case TacticalLines.TAI: 1539 case TacticalLines.BASE_CAMP_REVD: 1540 case TacticalLines.BASE_CAMP: 1541 case TacticalLines.GUERILLA_BASE_REVD: 1542 case TacticalLines.GUERILLA_BASE: 1543 case TacticalLines.GENERIC_AREA: 1544 case TacticalLines.LINE: 1545 case TacticalLines.ZONE: 1546 case TacticalLines.OBSAREA: 1547 case TacticalLines.OBSFAREA: 1548 case TacticalLines.ATDITCH: 1549 case TacticalLines.ATDITCHC: 1550 case TacticalLines.ATDITCHM: 1551 case TacticalLines.ATWALL: 1552 case TacticalLines.DEPICT: 1553 case TacticalLines.MINED: 1554 case TacticalLines.FENCED: 1555 case TacticalLines.UXO: 1556 case TacticalLines.UNSP: 1557 case TacticalLines.SFENCE: 1558 case TacticalLines.DFENCE: 1559 case TacticalLines.DOUBLEA: 1560 case TacticalLines.LWFENCE: 1561 case TacticalLines.HWFENCE: 1562 case TacticalLines.SINGLEC: 1563 case TacticalLines.DOUBLEC: 1564 case TacticalLines.TRIPLE: 1565 case TacticalLines.FORTL: 1566 case TacticalLines.STRONG: 1567 case TacticalLines.RAD: 1568 case TacticalLines.BIO: 1569 case TacticalLines.NUC: 1570 case TacticalLines.CHEM: 1571 case TacticalLines.DRCL: 1572 case TacticalLines.LINTGT: 1573 case TacticalLines.LINTGTS: 1574 case TacticalLines.FPF: 1575 case TacticalLines.FSCL: 1576 case TacticalLines.BCL_REVD: 1577 case TacticalLines.BCL: 1578 case TacticalLines.ICL: 1579 case TacticalLines.IFF_OFF: 1580 case TacticalLines.IFF_ON: 1581 case TacticalLines.GENERIC_LINE: 1582 case TacticalLines.CFL: 1583 case TacticalLines.TRIP: 1584 case TacticalLines.OVERHEAD_WIRE: 1585 case TacticalLines.NFL: 1586 case TacticalLines.MFP: 1587 case TacticalLines.RFL: 1588 case TacticalLines.AT: 1589 case TacticalLines.SERIES: 1590 case TacticalLines.STRIKWARN: 1591 case TacticalLines.SMOKE: 1592 case TacticalLines.BOMB: 1593 case TacticalLines.FSA: 1594 case TacticalLines.ACA: 1595 case TacticalLines.FFA: 1596 case TacticalLines.NFA: 1597 case TacticalLines.RFA: 1598 case TacticalLines.PAA: 1599 case TacticalLines.ATI: 1600 case TacticalLines.CFFZ: 1601 case TacticalLines.CFZ: 1602 case TacticalLines.SENSOR: 1603 case TacticalLines.CENSOR: 1604 case TacticalLines.DA: 1605 case TacticalLines.ZOR: 1606 case TacticalLines.TBA: 1607 case TacticalLines.TVAR: 1608 case TacticalLines.KILLBOXBLUE: 1609 case TacticalLines.KILLBOXPURPLE: 1610// case TacticalLines.MSR: 1611// case TacticalLines.ASR: 1612 case TacticalLines.MSR_ONEWAY: 1613 case TacticalLines.MSR_TWOWAY: 1614 case TacticalLines.MSR_ALT: 1615 case TacticalLines.ASR_ONEWAY: 1616 case TacticalLines.ASR_TWOWAY: 1617 case TacticalLines.ASR_ALT: 1618 case TacticalLines.TRAFFIC_ROUTE_ONEWAY: 1619 case TacticalLines.TRAFFIC_ROUTE_ALT: 1620 case TacticalLines.DHA_REVD: 1621 case TacticalLines.DHA: 1622 case TacticalLines.KILL_ZONE: 1623 case TacticalLines.EPW: 1624 case TacticalLines.FARP: 1625 case TacticalLines.RHA: 1626 case TacticalLines.BSA: 1627 case TacticalLines.DSA: 1628 case TacticalLines.CSA: 1629 case TacticalLines.RSA: 1630 case TacticalLines.TGMF: 1631 return true; 1632 case TacticalLines.MSR: //post clip these so there are identical points regardless whether segment data is set 10-5-16 1633 case TacticalLines.ASR: 1634 case TacticalLines.TRAFFIC_ROUTE: 1635 case TacticalLines.BOUNDARY: 1636 return false; 1637 default: 1638 return false; 1639 } 1640 } catch (Exception exc) { 1641 ErrorLogger.LogException(_className, "canClipPoints", 1642 new RendererException("Failed inside canClipPoints", exc)); 1643 } 1644 return false; 1645 } 1646 1647 /** 1648 * These get clipped so the fill must be treated as a separate shape. 1649 * Normally lines with fill do not have a separate shape for the fill. 1650 * 1651 * @param linetype 1652 * @return 1653 */ 1654 protected static boolean LinesWithSeparateFill(int linetype, ArrayList<Shape2> shapes) { 1655 if (shapes == null) { 1656 return false; 1657 } 1658 1659 switch (linetype) { 1660 case TacticalLines.MSDZ: 1661 return true; 1662 //treat these as lines: because of the feint they need an extra shape for the fill 1663 case TacticalLines.OBSFAREA: 1664 case TacticalLines.OBSAREA: 1665 case TacticalLines.STRONG: 1666 case TacticalLines.ZONE: 1667 case TacticalLines.FORT_REVD: 1668 case TacticalLines.FORT: 1669 case TacticalLines.ENCIRCLE: 1670 //return true; 1671 case TacticalLines.FIX: 1672 case TacticalLines.BOUNDARY: 1673 case TacticalLines.FLOT: 1674 case TacticalLines.LC: 1675 case TacticalLines.PL: 1676 case TacticalLines.FEBA: 1677 case TacticalLines.LL: 1678 case TacticalLines.EWL: 1679 case TacticalLines.AC: 1680 case TacticalLines.MRR: 1681 case TacticalLines.SL: 1682 case TacticalLines.TC: 1683 case TacticalLines.SAAFR: 1684 case TacticalLines.SC: 1685 case TacticalLines.LLTR: 1686 case TacticalLines.DIRATKAIR: 1687 case TacticalLines.DIRATKGND: 1688 case TacticalLines.DIRATKSPT: 1689 case TacticalLines.INFILTRATION: 1690 case TacticalLines.FCL: 1691 case TacticalLines.HOLD: 1692 case TacticalLines.BRDGHD: 1693 case TacticalLines.HOLD_GE: 1694 case TacticalLines.BRDGHD_GE: 1695 case TacticalLines.LOA: 1696 case TacticalLines.LOD: 1697 case TacticalLines.LDLC: 1698 case TacticalLines.PLD: 1699 case TacticalLines.RELEASE: 1700 case TacticalLines.HOL: 1701 case TacticalLines.BHL: 1702 case TacticalLines.LINE: 1703 case TacticalLines.ABATIS: 1704 case TacticalLines.ATDITCH: 1705 case TacticalLines.ATDITCHC: 1706 case TacticalLines.ATDITCHM: 1707 case TacticalLines.ATWALL: 1708 case TacticalLines.MNFLDFIX: 1709 case TacticalLines.UNSP: 1710 case TacticalLines.SFENCE: 1711 case TacticalLines.DFENCE: 1712 case TacticalLines.DOUBLEA: 1713 case TacticalLines.LWFENCE: 1714 case TacticalLines.HWFENCE: 1715 case TacticalLines.SINGLEC: 1716 case TacticalLines.DOUBLEC: 1717 case TacticalLines.TRIPLE: 1718 case TacticalLines.FORTL: 1719 case TacticalLines.LINTGT: 1720 case TacticalLines.LINTGTS: 1721 case TacticalLines.FSCL: 1722 case TacticalLines.BCL_REVD: 1723 case TacticalLines.BCL: 1724 case TacticalLines.ICL: 1725 case TacticalLines.IFF_OFF: 1726 case TacticalLines.IFF_ON: 1727 case TacticalLines.GENERIC_LINE: 1728 case TacticalLines.CFL: 1729 case TacticalLines.TRIP: 1730 case TacticalLines.NFL: 1731 case TacticalLines.MFP: 1732 case TacticalLines.RFL: 1733 case TacticalLines.MSR: 1734 case TacticalLines.MSR_ONEWAY: 1735 case TacticalLines.MSR_TWOWAY: 1736 case TacticalLines.MSR_ALT: 1737 case TacticalLines.ASR: 1738 case TacticalLines.ASR_ONEWAY: 1739 case TacticalLines.ASR_TWOWAY: 1740 case TacticalLines.ASR_ALT: 1741 case TacticalLines.TRAFFIC_ROUTE: 1742 case TacticalLines.TRAFFIC_ROUTE_ONEWAY: 1743 case TacticalLines.TRAFFIC_ROUTE_ALT: 1744 //undo any fill 1745 Shape2 shape = null; 1746 if (shapes != null && shapes.size() > 0) { 1747 int n = shapes.size(); 1748 //for(int j=0;j<shapes.size();j++) 1749 for (int j = 0; j < n; j++) { 1750 shape = shapes.get(j); 1751 if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) { 1752 shapes.get(j).setFillColor(null); 1753 } 1754 } 1755 } 1756 return true; 1757 default: 1758 return false; 1759 1760 } 1761 } 1762 1763 /** 1764 * uses a hash map to set the POINT2 style when creating tg.Pixels from 1765 * Point2D ArrayList 1766 * 1767 * @param pts2d 1768 * @param hashMap 1769 * @return 1770 */ 1771 protected static ArrayList<POINT2> Point2DtoPOINT2Mapped(ArrayList<Point2D> pts2d, Map<String, Object> hashMap) { 1772 ArrayList<POINT2> pts = new ArrayList(); 1773 try { 1774 Point2D pt2d; 1775 int style = 0; 1776 int n = pts2d.size(); 1777 //for(int j=0;j<pts2d.size();j++) 1778 for (int j = 0; j < n; j++) { 1779 pt2d = pts2d.get(j); 1780 //the hash map contains the original tg.Pixels before clipping 1781 if (hashMap.containsValue(pt2d)) { 1782 style = 0; 1783 } else { 1784 style = -1; //style set to -1 identifies it as a clip bounds point 1785 } 1786 pts.add(new POINT2(pts2d.get(j).getX(), pts2d.get(j).getY(), style)); 1787 } 1788 } catch (Exception exc) { 1789 ErrorLogger.LogException(_className, "Point2DToPOINT2Mapped", 1790 new RendererException("Failed inside Point2DToPOINT2Mapped", exc)); 1791 } 1792 return pts; 1793 } 1794 1795 protected static ArrayList<POINT2> Point2DtoPOINT2(ArrayList<Point2D> pts2d) { 1796 ArrayList<POINT2> pts = new ArrayList(); 1797 try { 1798 int n = pts2d.size(); 1799 //for(int j=0;j<pts2d.size();j++) 1800 for (int j = 0; j < n; j++) { 1801 pts.add(new POINT2(pts2d.get(j).getX(), pts2d.get(j).getY())); 1802 } 1803 } catch (Exception exc) { 1804 ErrorLogger.LogException(_className, "Point2DToPOINT2", 1805 new RendererException("Failed inside Point2DToPOINT2", exc)); 1806 } 1807 return pts; 1808 } 1809 1810 protected static ArrayList<Point2D> POINT2toPoint2D(ArrayList<POINT2> pts) { 1811 ArrayList<Point2D> pts2d = new ArrayList(); 1812 try { 1813 int n = pts.size(); 1814 //for(int j=0;j<pts.size();j++) 1815 for (int j = 0; j < n; j++) { 1816 pts2d.add(new Point2D.Double(pts.get(j).x, pts.get(j).y)); 1817 } 1818 1819 } catch (Exception exc) { 1820 ErrorLogger.LogException(_className, "POINT2toPoint2D", 1821 new RendererException("Failed inside POINT2toPoint2D", exc)); 1822 } 1823 return pts2d; 1824 } 1825 1826 /** 1827 * Builds a single shape from a point array. Currently we assume the array 1828 * represents a moveTo followed by a series of lineTo operations 1829 * 1830 * @param pts2d 1831 * @return 1832 */ 1833 private static Shape BuildShapeFromPoints(ArrayList<Point2D> pts2d) { 1834 GeneralPath shape = new GeneralPath(); 1835 try { 1836 shape.moveTo(pts2d.get(0).getX(), pts2d.get(0).getY()); 1837 int n = pts2d.size(); 1838 //for(int j=1;j<pts2d.size();j++) 1839 for (int j = 1; j < n; j++) { 1840 shape.lineTo(pts2d.get(j).getX(), pts2d.get(j).getY()); 1841 } 1842 } catch (Exception exc) { 1843 ErrorLogger.LogException(_className, "buildShapeFromPoints", 1844 new RendererException("Failed inside buildShapeFromPoints", exc)); 1845 1846 } 1847 return shape; 1848 } 1849 1850 /** 1851 * Clips a ShapeSpec. Assumes we are not post clipping splines, therefore 1852 * all the operations are moveTo, lineTo. Each ShapeSpec is assumed to be: 1853 * moveTo, lineTo ... lineTo, followed by another moveTo, lineTo, ... 1854 * lineTo, followed by ... 1855 * 1856 * @param shapeSpec 1857 * @param pts 1858 * @param clipArea 1859 * @return a single clipped shapeSpec 1860 */ 1861 protected static ArrayList<Shape2> buildShapeSpecFromPoints(TGLight tg0, 1862 Shape2 shapeSpec, //the original ShapeSpec 1863 ArrayList<POINT2> pts, 1864 Object clipArea) { 1865 ArrayList<Shape2> shapeSpecs2 = null; 1866 Shape2 shapeSpec2; 1867 try { 1868 //create a tg to use for the clip 1869 shapeSpecs2 = new ArrayList(); 1870 int j = 0, n = 0; 1871 //return null if it is outside the bounds 1872 Rectangle rect = shapeSpec.getBounds(); 1873 int h = shapeSpec.getBounds().height; 1874 int w = shapeSpec.getBounds().width; 1875 int x = shapeSpec.getBounds().x; 1876 int y = shapeSpec.getBounds().y; 1877// if(h==0 && w==0) 1878// return shapeSpecs2; 1879 1880 if (h == 0) { 1881 h = 1; 1882 } 1883 if (w == 0) { 1884 w = 1; 1885 } 1886 1887 Rectangle2D clipBounds = null; 1888 ArrayList<Point2D> clipPoints = null; 1889 if (clipArea != null && clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) { 1890 clipBounds = (Rectangle2D) clipArea; 1891 } else if (clipArea != null && clipArea.getClass().isAssignableFrom(Rectangle.class)) { 1892 //clipBounds=(Rectangle2D)clipArea; 1893 Rectangle rectx = (Rectangle) clipArea; 1894 clipBounds = new Rectangle2D.Double(rectx.x, rectx.y, rectx.width, rectx.height); 1895 } else if (clipArea != null && clipArea.getClass().isAssignableFrom(ArrayList.class)) { 1896 clipPoints = (ArrayList<Point2D>) clipArea; 1897 } 1898 1899 if (clipBounds != null && clipBounds.contains(shapeSpec.getShape().getBounds2D()) == false 1900 && clipBounds.intersects(shapeSpec.getShape().getBounds2D()) == false) { 1901 //this tests if the shape has height or width 0 1902 //but may be contained within the clipbounds or intersect it 1903 //in that case we gave it a default width or thickness of 1 1904 if (clipBounds.contains(x, y, w, h) == false 1905 && clipBounds.intersects(x, y, w, h) == false) { 1906 return shapeSpecs2; 1907 } 1908 } else if (clipPoints != null) { 1909 GeneralPath poly = new GeneralPath(); 1910 n = clipPoints.size(); 1911 //for(j=0;j<clipPoints.size();j++) 1912 for (j = 0; j < n; j++) { 1913 if (j == 0) { 1914 poly.moveTo(clipPoints.get(j).getX(), clipPoints.get(j).getY()); 1915 } else { 1916 poly.lineTo(clipPoints.get(j).getX(), clipPoints.get(j).getY()); 1917 } 1918 } 1919 poly.closePath(); 1920 if (poly.contains(shapeSpec.getShape().getBounds2D()) == false 1921 && poly.intersects(shapeSpec.getShape().getBounds2D()) == false) { 1922 if (poly.contains(x, y, w, h) == false 1923 && poly.intersects(x, y, w, h) == false) { 1924 return shapeSpecs2; 1925 } 1926 } 1927 } 1928 1929 if (shapeSpec.getShapeType() == Shape2.SHAPE_TYPE_MODIFIER 1930 || shapeSpec.getShapeType() == Shape2.SHAPE_TYPE_MODIFIER_FILL) { 1931 shapeSpecs2.add(shapeSpec); 1932 return shapeSpecs2; 1933 } 1934 TGLight tg = new TGLight(); 1935 POINT2 pt = null; 1936 tg.set_LineType(TacticalLines.PL); 1937 ArrayList<POINT2> pts2 = new ArrayList(); 1938 ArrayList<Point2D> pts2d = null; 1939 Shape shape = null; 1940 GeneralPath gp = new GeneralPath(); 1941 //loop through the points 1942 n = pts.size(); 1943 //for(j=0;j<pts.size();j++) 1944 for (j = 0; j < n; j++) { 1945 pt = pts.get(j); 1946 //new line 1947 switch (pt.style) { 1948 case 0: //moveTo, 1949 //they lifted the pencil, so we build the shape from the existing pts and append it 1950 if (pts2.size() > 1) { 1951 //clip the points 1952 tg = new TGLight(); 1953 tg.set_LineType(TacticalLines.PL); 1954 tg.Pixels = pts2; 1955 if (clipBounds != null) { 1956 pts2d = clsClipPolygon2.ClipPolygon(tg, clipBounds); 1957 } else if (clipPoints != null && !clipPoints.isEmpty()) { 1958 pts2d = clsClipQuad.ClipPolygon(tg, clipPoints); 1959 } 1960 1961 //build a GeneralPath from the points we collected, we will append it 1962 if (pts2d != null && pts2d.size() > 1) { 1963 shape = BuildShapeFromPoints(pts2d); 1964 //append the shape because we want to return only one shape 1965 gp.append(shape, false); 1966 } 1967 //clear the points array and begin the next line 1968 pts2.clear(); 1969 pts2.add(pt); 1970 } else { 1971 pts2.add(pt); 1972 } 1973 break; 1974 case 1: //lineTo 1975 pts2.add(pt); 1976 break; 1977 default: 1978 pts2.add(pt); 1979 break; 1980 } 1981 }//end for 1982 //append the last shape 1983 if (pts2.size() > 1) { 1984 //clip the points 1985 tg = new TGLight(); 1986 tg.set_LineType(TacticalLines.PL); 1987 tg.Pixels = pts2; 1988 if (clipBounds != null) { 1989 pts2d = clsClipPolygon2.ClipPolygon(tg, clipBounds); 1990 } else if (clipPoints != null) { 1991 pts2d = clsClipQuad.ClipPolygon(tg, clipPoints); 1992 } 1993 //build a GeneralPath from the points we collected, we will append it 1994 if (pts2d != null && pts2d.size() > 1) { 1995 shape = BuildShapeFromPoints(pts2d); 1996 gp.append(shape, false); 1997 } 1998 tg0.set_WasClipped(tg.get_WasClipped()); 1999 } 2000 //create the shapespec here 2001 //initialize the clipped ShapeSpec 2002 shapeSpec2 = new Shape2(shapeSpec.getShapeType()); 2003 shapeSpec2.setLineColor(shapeSpec.getLineColor()); 2004 shapeSpec2.setFillColor(shapeSpec.getFillColor()); 2005 shapeSpec2.setStroke(shapeSpec.getStroke()); 2006 shapeSpec2.setTexturePaint(shapeSpec.getTexturePaint()); 2007 shapeSpec2.setShape(gp); 2008 shapeSpecs2.add(shapeSpec2); 2009 } catch (Exception exc) { 2010 ErrorLogger.LogException(_className, "buildShapeSpecFromPoints", 2011 new RendererException("Failed inside buildShapeSpecFromPoints", exc)); 2012 2013 } 2014 return shapeSpecs2; 2015 } 2016 2017 /** 2018 * Currently assumes no MeTOC symbols are post clipped 2019 * 2020 * @param tg 2021 * @param shapeSpecsArray 2022 * @param clipArea 2023 * @return 2024 */ 2025 protected static ArrayList<Shape2> postClipShapes(TGLight tg, ArrayList<Shape2> shapeSpecsArray, Object clipArea) { 2026 ArrayList<Shape2> shapeSpecs2 = null; 2027 ArrayList<Shape2> tempShapes = null; 2028 try { 2029 if (shapeSpecsArray == null || shapeSpecsArray.size() == 0) { 2030 return null; 2031 } 2032 2033 shapeSpecs2 = new ArrayList(); 2034 int j = 0; 2035 ArrayList<Shape2> shapeSpecs = new ArrayList(); 2036 int n = shapeSpecsArray.size(); 2037 //for(j=0;j<shapeSpecsArray.size();j++) 2038 for (j = 0; j < n; j++) { 2039 shapeSpecs.add(shapeSpecsArray.get(j)); 2040 } 2041 2042 ArrayList<POINT2> pts = new ArrayList();//use these 2043 Shape shape = null; 2044 POINT2 pt; 2045 double[] coords = new double[6]; 2046 Shape2 shapeSpec = null; 2047 n = shapeSpecs.size(); 2048 //for(j=0;j<shapeSpecs.size();j++) 2049 for (j = 0; j < n; j++) { 2050 shapeSpec = shapeSpecs.get(j); 2051 shape = shapeSpec.getShape(); 2052 pts.clear(); 2053 for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) { 2054 int type = i.currentSegment(coords); 2055 switch (type) { 2056 case PathIterator.SEG_MOVETO: 2057 pt = new POINT2(coords[0], coords[1]); 2058 pt.style = 0; 2059 pts.add(pt); 2060 break; 2061 case PathIterator.SEG_LINETO: 2062 pt = new POINT2(coords[0], coords[1]); 2063 pt.style = 1; 2064 pts.add(pt); 2065 break; 2066 case PathIterator.SEG_QUADTO: //not using this 2067 pt = new POINT2(coords[0], coords[1]); 2068 pt.style = 2; 2069 pts.add(pt); 2070 pt = new POINT2(coords[2], coords[3]); 2071 pt.style = 2; 2072 pts.add(pt); 2073 break; 2074 case PathIterator.SEG_CUBICTO: //not using this 2075 pt = new POINT2(coords[0], coords[1]); 2076 pt.style = 3; 2077 pts.add(pt); 2078 pt = new POINT2(coords[2], coords[3]); 2079 pt.style = 3; 2080 pts.add(pt); 2081 pt = new POINT2(coords[4], coords[5]); 2082 pt.style = 3; 2083 pts.add(pt); 2084 break; 2085 case PathIterator.SEG_CLOSE://not using this 2086 pt = new POINT2(coords[0], coords[1]); 2087 pt.style = 4; 2088 pts.add(pt); 2089 break; 2090 default: 2091 pt = null; 2092 break; 2093 }//end switch 2094 } //end for pathiterator i 2095 tempShapes = buildShapeSpecFromPoints(tg, shapeSpec, pts, clipArea); 2096 shapeSpecs2.addAll(tempShapes); 2097 } 2098 } catch (Exception exc) { 2099 ErrorLogger.LogException(_className, "postClipShapes", 2100 new RendererException("Failed inside postClipShapes", exc)); 2101 } 2102 return shapeSpecs2; 2103 } 2104 2105 /** 2106 * For the 3d map we cannot pre-segment the auto-shapes or fire support 2107 * areas. We do need to pre-segment generic lines regardless of the status 2108 * if clipping is set. Currently we are not pre-segmenting axis of advance 2109 * symbols. 2110 * 2111 * @param tg 2112 * @return true if pre-segmenting is to be used 2113 */ 2114 private static boolean segmentAnticipatedLine(TGLight tg) { 2115 try { 2116 int linetype = tg.get_LineType(); 2117 //do not pre-segment the fire support rectangular and circular areas 2118 if (clsUtility.IsChange1Area(linetype)) { 2119 return false; 2120 } 2121 //do not pre-segment the autoshapes 2122 if (clsUtility.isAutoshape(tg)) { 2123 return false; 2124 } 2125 if (SymbolUtilities.isBasicShape(linetype)) { 2126 return false; 2127 } 2128 //temporarily do not pre-segment the channel types. 2129 switch (linetype) { 2130 case TacticalLines.OVERHEAD_WIRE: 2131 case TacticalLines.CATK: 2132 case TacticalLines.CATKBYFIRE: 2133 case TacticalLines.MAIN: 2134 case TacticalLines.SPT: 2135 case TacticalLines.FRONTAL_ATTACK: 2136 case TacticalLines.TURNING_MOVEMENT: 2137 case TacticalLines.MOVEMENT_TO_CONTACT: 2138 case TacticalLines.AIRAOA: 2139 case TacticalLines.AAAAA: 2140 return false; 2141 case TacticalLines.MSR_ONEWAY: 2142 case TacticalLines.MSR_TWOWAY: 2143 case TacticalLines.MSR_ALT: 2144 case TacticalLines.ASR_ONEWAY: 2145 case TacticalLines.ASR_TWOWAY: 2146 case TacticalLines.ASR_ALT: 2147 case TacticalLines.TRAFFIC_ROUTE_ONEWAY: 2148 case TacticalLines.TRAFFIC_ROUTE_ALT: 2149 //added because of segment data 4-22-13 2150 //removed from this case block since we now post-clip these because of segment color data 10-5-16 2151// case TacticalLines.MSR: 2152// case TacticalLines.ASR: 2153// case TacticalLines.BOUNDARY: 2154 return false; 2155 default: 2156 break; 2157 } 2158 2159 } catch (Exception exc) { 2160 ErrorLogger.LogException(_className, "segmentGenericLine", 2161 new RendererException("Failed inside segmentGenericLine", exc)); 2162 } 2163 return true; 2164 } 2165 2166 /** 2167 * cannot pre-segment the fire support areas, must post segment them after 2168 * the pixels were calculated 2169 * 2170 * @param tg 2171 * @param converter 2172 */ 2173 protected static void postSegmentFSA(TGLight tg, 2174 IPointConversion converter) { 2175 try { 2176 if (tg.get_Client().equals("2D")) { 2177 return; 2178 } 2179 2180 int linetype = tg.get_LineType(); 2181 switch (linetype) { 2182 case TacticalLines.PAA_RECTANGULAR: 2183 case TacticalLines.FSA_RECTANGULAR: 2184 case TacticalLines.SHIP_AOI_RECTANGULAR: 2185 case TacticalLines.DEFENDED_AREA_RECTANGULAR: 2186 case TacticalLines.FFA_RECTANGULAR: 2187 case TacticalLines.ACA_RECTANGULAR: 2188 case TacticalLines.NFA_RECTANGULAR: 2189 case TacticalLines.RFA_RECTANGULAR: 2190 case TacticalLines.ATI_RECTANGULAR: 2191 case TacticalLines.CFFZ_RECTANGULAR: 2192 case TacticalLines.SENSOR_RECTANGULAR: 2193 case TacticalLines.CENSOR_RECTANGULAR: 2194 case TacticalLines.DA_RECTANGULAR: 2195 case TacticalLines.CFZ_RECTANGULAR: 2196 case TacticalLines.ZOR_RECTANGULAR: 2197 case TacticalLines.TBA_RECTANGULAR: 2198 case TacticalLines.TVAR_RECTANGULAR: 2199 case TacticalLines.KILLBOXBLUE_RECTANGULAR: 2200 case TacticalLines.KILLBOXPURPLE_RECTANGULAR: 2201 break; 2202 default: 2203 return; 2204 } 2205 ArrayList<POINT2> latLongs = new ArrayList(); 2206 ArrayList<POINT2> resultPts = new ArrayList(); 2207 int j = 0, k = 0, n = 0; 2208 POINT2 pt0 = null, pt1 = null, pt = null; 2209 double dist = 0; 2210 //double interval=1000000; 2211 double interval = 250000; 2212 double az = 0; 2213 2214 double maxDist = 0; 2215 Point2D pt2d = null; 2216 int t = tg.Pixels.size(); 2217 //for(j=0;j<tg.Pixels.size();j++) 2218 for (j = 0; j < t; j++) { 2219 pt0 = tg.Pixels.get(j); 2220 pt2d = new Point2D.Double(pt0.x, pt0.y); 2221 pt2d = converter.PixelsToGeo(pt2d); 2222 pt0 = new POINT2(pt2d.getX(), pt2d.getY()); 2223 latLongs.add(pt0); 2224 } 2225 t = latLongs.size(); 2226 //for(j=0;j<latLongs.size()-1;j++) 2227 for (j = 0; j < t - 1; j++) { 2228 pt0 = latLongs.get(j); 2229 pt1 = latLongs.get(j + 1); 2230 pt1.style = -1;//end point 2231 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2232 dist = mdlGeodesic.geodesic_distance(latLongs.get(j), latLongs.get(j + 1), null, null); 2233 if (dist > maxDist) { 2234 maxDist = dist; 2235 } 2236 } 2237 2238 if (interval > maxDist) { 2239 interval = maxDist; 2240 } 2241 2242 //for(j=0;j<latLongs.size()-1;j++) 2243 for (j = 0; j < t - 1; j++) { 2244 pt0 = new POINT2(latLongs.get(j)); 2245 pt0.style = 0;//anchor point 2246 pt1 = new POINT2(latLongs.get(j + 1)); 2247 pt1.style = 0;//anchor point point 2248 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2249 dist = mdlGeodesic.geodesic_distance(latLongs.get(j), latLongs.get(j + 1), null, null); 2250 2251 n = (int) (dist / interval); 2252 if (j == 0) { 2253 resultPts.add(pt0); 2254 } 2255 2256 for (k = 1; k <= n; k++) { 2257 pt = mdlGeodesic.geodesic_coordinate(pt0, interval * k, az); 2258 pt.style = -2; 2259 //we do not want the last segment to be too close to the anchor point 2260 //only add the segment point if it is a distance at least half the inteval 2261 //from the 2nd anchor point 2262 dist = mdlGeodesic.geodesic_distance(pt, pt1, null, null); 2263 if (dist >= interval / 2) { 2264 resultPts.add(pt); 2265 } 2266 } 2267 //ad the 2nd anchor point 2268 resultPts.add(pt1); 2269 } 2270 latLongs = resultPts; 2271 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(latLongs, converter); 2272 } catch (Exception exc) { 2273 ErrorLogger.LogException(_className, "postSegmentFSA", 2274 new RendererException("Failed inside postSegmentFSA", exc)); 2275 } 2276 } 2277 2278 /** 2279 * Similar to Vincenty algorithm for more accurate interpolation of geo 2280 * anchor points 2281 * 2282 * @return the interpolated points 2283 */ 2284 private static ArrayList<POINT2> toGeodesic(TGLight tg, double interval, HashMap<Integer,String> hmap) { 2285 ArrayList<POINT2> locs = new ArrayList<POINT2>(); 2286 try { 2287 int i = 0, k = 0, n = 0; 2288 ArrayList<POINT2> points = tg.LatLongs; 2289 String H = ""; 2290 String color = ""; 2291 boolean bolIsAC = false; 2292 int acWidth = 0; 2293 int linetype = tg.get_LineType(); 2294 switch (linetype) { 2295 case TacticalLines.AC: 2296 case TacticalLines.LLTR: 2297 case TacticalLines.MRR: 2298 case TacticalLines.SL: 2299 case TacticalLines.SAAFR: 2300 case TacticalLines.TC: 2301 case TacticalLines.SC: 2302 bolIsAC = true; 2303 break; 2304 default: 2305 break; 2306 } 2307 for (i = 0; i < points.size() - 1; i++) { 2308 if(bolIsAC) 2309 acWidth=points.get(i).style; 2310 // Convert coordinates from degrees to Radians 2311 //var lat1 = points[i].latitude * (PI / 180); 2312 //var lon1 = points[i].longitude * (PI / 180); 2313 //var lat2 = points[i + 1].latitude * (PI / 180); 2314 //var lon2 = points[i + 1].longitude * (PI / 180); 2315 double lat1 = Math.toRadians(points.get(i).y); 2316 double lon1 = Math.toRadians(points.get(i).x); 2317 double lat2 = Math.toRadians(points.get(i + 1).y); 2318 double lon2 = Math.toRadians(points.get(i + 1).x); 2319 // Calculate the total extent of the route 2320 //var d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cos(lat1) * cos(lat2) * pow((sin((lon1 - lon2) / 2)), 2))); 2321 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))); 2322 2323 double dist = mdlGeodesic.geodesic_distance(points.get(i), points.get(i + 1), null, null); 2324 //double dist=d; 2325 float flt = (float) dist / (float) interval; 2326 n = Math.round(flt); 2327 if (n < 1) { 2328 n = 1; 2329 } 2330 if (n > 32) { 2331 n = 32; 2332 } 2333 // Calculate positions at fixed intervals along the route 2334 for (k = 0; k <= n; k++) { 2335 //we must preserve the anchor points 2336 if (k == 0) { 2337 locs.add(new POINT2(points.get(i))); 2338 if (hmap != null && hmap.containsKey(i)) { 2339 if (!H.isEmpty()) { 2340 H += ","; 2341 } 2342 color = (String) hmap.get(i); 2343 H += Integer.toString(locs.size() - 1) + ":" + color; 2344 } 2345 continue; 2346 } else if (k == n) { 2347 if (i == points.size() - 2) { 2348 locs.add(new POINT2(points.get(i + 1))); 2349 if (hmap != null && hmap.containsKey(i + 1)) { 2350 if (!H.isEmpty()) { 2351 H += ","; 2352 } 2353 color = (String) hmap.get(i + 1); 2354 H += Integer.toString(locs.size() - 1) + ":" + color; 2355 } 2356 } 2357 break; 2358 } 2359 //var f = (k / n); 2360 //var A = sin((1 - f) * d) / sin(d); 2361 //var B = sin(f * d) / sin(d); 2362 double f = ((double) k / (double) n); 2363 double A = Math.sin((1 - f) * d) / Math.sin(d); 2364 double B = Math.sin(f * d) / Math.sin(d); 2365 // Obtain 3D Cartesian coordinates of each point 2366 //var x = A * cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2); 2367 //var y = A * cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2); 2368 //var z = A * sin(lat1) + B * sin(lat2); 2369 double x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2); 2370 double y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2); 2371 double z = A * Math.sin(lat1) + B * Math.sin(lat2); 2372 // Convert these to latitude/longitude 2373 //var lat = atan2(z, sqrt(pow(x, 2) + pow(y, 2))); 2374 //var lon = atan2(y, x); 2375 double lat = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))); 2376 double lon = Math.atan2(y, x); 2377 lat *= 180.0 / Math.PI; 2378 lon *= 180.0 / Math.PI; 2379 POINT2 pt = new POINT2(lon, lat); 2380 if(bolIsAC) 2381 pt.style=-acWidth; 2382 locs.add(pt); 2383 if (hmap != null && hmap.containsKey(i)) { 2384 if (!H.isEmpty()) { 2385 H += ","; 2386 } 2387 color = (String) hmap.get(i); 2388 H += Integer.toString(locs.size() - 1) + ":" + color; 2389 } 2390 } 2391 } 2392 if (!H.isEmpty()) { 2393 tg.set_H(H); 2394 } 2395 } catch (Exception exc) { 2396 ErrorLogger.LogException(_className, "toGeodesic", 2397 new RendererException("Failed inside toGeodesic", exc)); 2398 return null; 2399 } 2400 return locs; 2401 } 2402 2403 /** 2404 * Pre-segment the lines based on max or min latitude for the segment 2405 * interval. This is necessary because GeoPixelconversion does not work well 2406 * over distance greater than 1M meters, especially at extreme latitudes. 2407 * 2408 * @param tg 2409 * @param converter 2410 */ 2411 protected static void SegmentGeoPoints(TGLight tg, 2412 IPointConversion converter, 2413 double zoomFactor) { 2414 try { 2415 if (tg.get_Client().equals("2D")) { 2416 return; 2417 } 2418 2419 ArrayList<POINT2> resultPts = new ArrayList(); 2420 int lineType = tg.get_LineType(); 2421 //double interval=1000000; 2422 double interval = 250000; 2423 boolean bolSegmentAC = false, bolIsAC = false; 2424 bolSegmentAC = true; 2425 //conservative interval in meters 2426 //return early for those lines not requiring pre-segmenting geo points 2427 switch (lineType) { 2428 case TacticalLines.AC: 2429 case TacticalLines.LLTR: 2430 case TacticalLines.MRR: 2431 case TacticalLines.SL: 2432 case TacticalLines.SAAFR: 2433 case TacticalLines.TC: 2434 case TacticalLines.SC: 2435 if (!bolSegmentAC) { 2436 return; 2437 } 2438 bolIsAC = true; 2439 break; 2440 case TacticalLines.PLD: 2441 case TacticalLines.CFL: 2442 case TacticalLines.UNSP: 2443 case TacticalLines.TRIPLE: 2444 case TacticalLines.DOUBLEC: 2445 case TacticalLines.SINGLEC: 2446 case TacticalLines.ATDITCH: 2447 case TacticalLines.ATDITCHC: 2448 case TacticalLines.ATDITCHM: 2449 case TacticalLines.ATWALL: 2450 case TacticalLines.LINE: 2451 case TacticalLines.DIRATKAIR: 2452 case TacticalLines.STRONG: 2453 case TacticalLines.ENCIRCLE: 2454 case TacticalLines.FLOT: 2455 case TacticalLines.ZONE: 2456 case TacticalLines.OBSAREA: 2457 case TacticalLines.OBSFAREA: 2458 case TacticalLines.FORT_REVD: 2459 case TacticalLines.FORT: 2460 case TacticalLines.FORTL: 2461 break; 2462 case TacticalLines.HWFENCE: 2463 case TacticalLines.LWFENCE: 2464 case TacticalLines.DOUBLEA: 2465 case TacticalLines.DFENCE: 2466 case TacticalLines.SFENCE: 2467 interval = 500000; 2468 break; 2469 case TacticalLines.LC: 2470 interval = 2000000; 2471 break; 2472 default: 2473 //if the line is an anticipated generic line then segment the line 2474 if (segmentAnticipatedLine(tg)) { 2475 break; 2476 } 2477 return; 2478 } 2479 2480 int j = 0, k = 0, n = 0; 2481 POINT2 pt0 = null, pt1 = null, pt = null; 2482 double dist = 0; 2483 double az = 0; 2484 2485 double maxDist = 0; 2486 int t = tg.LatLongs.size(); 2487 //for(j=0;j<tg.LatLongs.size()-1;j++) 2488 for (j = 0; j < t - 1; j++) { 2489 pt0 = tg.LatLongs.get(j); 2490 pt1 = tg.LatLongs.get(j + 1); 2491 if(!bolIsAC) 2492 pt1.style = -1;//end point 2493 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2494 dist = mdlGeodesic.geodesic_distance(tg.LatLongs.get(j), tg.LatLongs.get(j + 1), null, null); 2495 if (dist > maxDist) { 2496 maxDist = dist; 2497 } 2498 } 2499 2500 if (interval > maxDist) { 2501 interval = maxDist; 2502 } 2503 2504 if (zoomFactor > 0 && zoomFactor < 0.01) { 2505 zoomFactor = 0.01; 2506 } 2507 if (zoomFactor > 0 && zoomFactor < 1) { 2508 interval *= zoomFactor; 2509 } 2510 2511 boolean useVincenty = false; 2512 String H = ""; 2513 String color = ""; 2514 HashMap<Integer,String> hmap = clsUtility.getMSRSegmentColorStrings(tg); 2515 if (hmap != null) { 2516 tg.set_H(""); 2517 } 2518 //uncomment one line to use (similar to) Vincenty algorithm 2519 useVincenty = true; 2520 if (useVincenty) { 2521 resultPts = toGeodesic(tg, interval, hmap); 2522 tg.LatLongs = resultPts; 2523 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(tg.LatLongs, converter); 2524 return; 2525 } 2526 2527 for (j = 0; j < tg.LatLongs.size() - 1; j++) { 2528 pt0 = new POINT2(tg.LatLongs.get(j)); 2529 pt0.style = 0;//anchor point 2530 pt1 = new POINT2(tg.LatLongs.get(j + 1)); 2531 pt1.style = 0;//anchor point point 2532 az = mdlGeodesic.GetAzimuth(pt0, pt1); 2533 dist = mdlGeodesic.geodesic_distance(tg.LatLongs.get(j), tg.LatLongs.get(j + 1), null, null); 2534 2535 n = (int) (dist / interval); 2536 if (j == 0) { 2537 resultPts.add(pt0); 2538 if (hmap != null && hmap.containsKey(j)) { 2539 if (!H.isEmpty()) { 2540 H += ","; 2541 } 2542 color = (String) hmap.get(j); 2543 //H+=(resultPts.size()-1).toString()+":"+color; 2544 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2545 } 2546 } 2547 for (k = 1; k <= n; k++) { 2548 pt = mdlGeodesic.geodesic_coordinate(pt0, interval * k, az); 2549 pt.style = -2; 2550 //we do not want the last segment to be too close to the anchor point 2551 //only add the segment point if it is a distance at least half the inteval 2552 //from the 2nd anchor point 2553 dist = mdlGeodesic.geodesic_distance(pt, pt1, null, null); 2554 if (dist >= interval / 2) { 2555 resultPts.add(pt); 2556 if (hmap != null && hmap.containsKey(j)) { 2557 color = (String) hmap.get(j); 2558 if (!H.isEmpty()) { 2559 H += ","; 2560 } 2561 //H+=(resultPts.size()-1).toString()+":"+color; 2562 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2563 } 2564 } 2565 } 2566 //ad the 2nd anchor point 2567 resultPts.add(pt1); 2568 if (hmap != null && hmap.containsKey(j + 1)) { 2569 if (!H.isEmpty()) { 2570 H += ","; 2571 } 2572 color = (String) hmap.get(j + 1); 2573 //H+=(resultPts.size()-1).toString()+":"+color; 2574 H += Integer.toString(resultPts.size() - 1) + ":" + color; 2575 } 2576 } 2577 if (!H.isEmpty()) { 2578 tg.set_H(H); 2579 } 2580 tg.LatLongs = resultPts; 2581 tg.Pixels = armyc2.c5isr.RenderMultipoints.clsUtility.LatLongToPixels(tg.LatLongs, converter); 2582 } catch (Exception exc) { 2583 ErrorLogger.LogException(_className, "SegmentGeoPoints", 2584 new RendererException("Failed inside SegmentGeoPoints", exc)); 2585 } 2586 } 2587 2588 /** 2589 * Calculating the signed area will tell you which direction the points are going. 2590 * Negative = Clock-wise, Positive = counter clock-wise 2591 * A = 1/2 * (x1*y2 - x2*y1 + x2*y3 - x3*y2 + ... + xn*y1 - x1*yn) 2592 */ 2593 static double CalculateSignedAreaOfPolygon(ArrayList<POINT2> coords) { 2594 double signedArea = 0; 2595 final int len = coords.size(); 2596 for (int i = 0; i < len; i++) { 2597 double x1 = coords.get(i).x; 2598 double y1 = coords.get(i).y; 2599 double x2 = coords.get((i + 1) % len).x; 2600 double y2 = coords.get((i + 1) % len).y; 2601 signedArea += (x1 * y2 - x2 * y1); 2602 } 2603 return signedArea / 2; 2604 } 2605}