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