001package armyc2.c5isr.renderer.utilities; 002 003 004import android.graphics.Point; 005import android.graphics.RectF; 006 007import java.text.SimpleDateFormat; 008import java.util.ArrayList; 009import java.util.Date; 010import java.util.Locale; 011import java.util.TimeZone; 012import java.util.regex.Pattern; 013 014import armyc2.c5isr.JavaLineArray.TacticalLines; 015 016/** 017 * Has various utility functions for prcessing the symbol code. 018 * See {@link SymbolID} for additional functions related to parsing the symbol code. 019* 020 */ 021public class SymbolUtilities { 022 023 private static SimpleDateFormat dateFormatFront = new SimpleDateFormat("ddHHmmss", Locale.US); 024 private static SimpleDateFormat dateFormatBack = new SimpleDateFormat("MMMyyyy", Locale.US); 025 private static SimpleDateFormat dateFormatFull = new SimpleDateFormat("ddHHmmssZMMMyyyy", Locale.US); 026 private static SimpleDateFormat dateFormatZulu = new SimpleDateFormat("Z", Locale.US); 027 028 //this regex is from: https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html 029 private static final String Digits = "(\\p{Digit}+)"; 030 private static final String HexDigits = "(\\p{XDigit}+)"; 031 // an exponent is 'e' or 'E' followed by an optionally 032 // signed decimal integer. 033 private static final String Exp = "[eE][+-]?"+Digits; 034 private static final String fpRegex = 035 ("[\\x00-\\x20]*"+ // Optional leading "whitespace" 036 "[+-]?(" + // Optional sign character 037 "NaN|" + // "NaN" string 038 "Infinity|" + // "Infinity" string 039 040 // A decimal floating-point string representing a finite positive 041 // number without a leading sign has at most five basic pieces: 042 // Digits . Digits ExponentPart FloatTypeSuffix 043 // 044 // Since this method allows integer-only strings as input 045 // in addition to strings of floating-point literals, the 046 // two sub-patterns below are simplifications of the grammar 047 // productions from section 3.10.2 of 048 // The Java™ Language Specification. 049 050 // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt 051 "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+ 052 053 // . Digits ExponentPart_opt FloatTypeSuffix_opt 054 "(\\.("+Digits+")("+Exp+")?)|"+ 055 056 // Hexadecimal strings 057 "((" + 058 // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt 059 "(0[xX]" + HexDigits + "(\\.)?)|" + 060 061 // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt 062 "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + 063 064 ")[pP][+-]?" + Digits + "))" + 065 "[fFdD]?))" + 066 "[\\x00-\\x20]*");// Optional trailing "whitespace" 067 068 private static final Pattern pIsNumber = Pattern.compile(fpRegex); 069 070 /** 071 * Determines if a String represents a valid number 072 * 073 * @param text {@link String} 074 * @return "1.56" == true, "1ab" == false 075 */ 076 public static boolean isNumber(String text) 077 { 078 return pIsNumber.matcher(text).matches(); 079 } 080 081 082 /*private static String convert(int integer) 083 { 084 String hexAlphabet = "0123456789ABCDEF"; 085 String foo = "gfds" + "dhs"; 086 char char1 = hexAlphabet.charAt((integer - integer % 16)/16); 087 char char2 = hexAlphabet.charAt(integer % 16); 088 String returnVal = String.valueOf(char1) + String.valueOf(char2); 089 return returnVal; 090 } 091 092 public static String colorToHexString(Color color, Boolean withAlpha) 093 { 094 if(color != null) { 095 String hex = ""; 096 if (withAlpha == false) { 097 hex = "#" + convert(color.getRed()) + 098 convert(color.getGreen()) + 099 convert(color.getBlue()); 100 } else { 101 hex = "#" + convert(color.getAlpha()) + 102 convert(color.getRed()) + 103 convert(color.getGreen()) + 104 convert(color.getBlue()); 105 } 106 return hex; 107 } 108 else 109 return null; 110 }//*/ 111 112 113 /** 114 * Converts a Java Date object into a properly formatted String for W or W1. 115 * DDHHMMSSZMONYYYY 116 * Field W: D = day, H = hour, M = minute, S = second, Z = Greenwich or local time, MON= month and Y = year. 117 * @param time {@link Date} 118 * @return {@link String} 119 */ 120 public static String getDateLabel(Date time) 121 { 122 123 String modifierString = null; 124 125 String zulu = ""; 126 zulu = dateFormatZulu.format(time); 127 128 if (zulu != null && zulu.length() == 5) 129 { 130 131 if (zulu.startsWith("+"))//Integer.valueOf doesn't like '+' 132 { 133 zulu = zulu.substring(1, 3); 134 } 135 else 136 { 137 zulu = zulu.substring(0, 3); 138 } 139 140 int intZulu = Integer.valueOf(zulu); 141 142 zulu = getZuluCharFromTimeZoneOffset(intZulu); 143 } 144 else 145 { 146 zulu = getZuluCharFromTimeZoneOffset(time); 147 } 148 149 modifierString = dateFormatFront.format(time) + zulu + dateFormatBack.format(time); 150 151 return modifierString.toUpperCase(); 152 } 153 154 /** 155 * Given date, return character String representing which NATO time zone 156 * you're in. 157 * 158 * @param time {@link Date} 159 * @return {@link String} 160 */ 161 private static String getZuluCharFromTimeZoneOffset(Date time) 162 { 163 TimeZone tz = TimeZone.getDefault(); 164 Date offset = new Date(tz.getOffset(time.getTime())); 165 long lOffset = offset.getTime() / 3600000;//3600000 = (1000(ms)*60(s)*60(m)) 166 167 int hour = (int) lOffset; 168 169 return getZuluCharFromTimeZoneOffset(hour); 170 } 171 172 /** 173 * Given hour offset from Zulu return character String representing which 174 * NATO time zone you're in. 175 * 176 * @param hour {@link Integer} 177 * @return {@link String} 178 */ 179 private static String getZuluCharFromTimeZoneOffset(int hour) 180 { 181 if (hour == 0) 182 { 183 return "Z"; 184 } 185 else if (hour == -1) 186 { 187 return "N"; 188 } 189 else if (hour == -2) 190 { 191 return "O"; 192 } 193 else if (hour == -3) 194 { 195 return "P"; 196 } 197 else if (hour == -4) 198 { 199 return "Q"; 200 } 201 else if (hour == -5) 202 { 203 return "R"; 204 } 205 else if (hour == -6) 206 { 207 return "S"; 208 } 209 else if (hour == -7) 210 { 211 return "T"; 212 } 213 else if (hour == -8) 214 { 215 return "U"; 216 } 217 else if (hour == -9) 218 { 219 return "V"; 220 } 221 else if (hour == -10) 222 { 223 return "W"; 224 } 225 else if (hour == -11) 226 { 227 return "X"; 228 } 229 else if (hour == -12) 230 { 231 return "Y"; 232 } 233 else if (hour == 1) 234 { 235 return "A"; 236 } 237 else if (hour == 2) 238 { 239 return "B"; 240 } 241 else if (hour == 3) 242 { 243 return "C"; 244 } 245 else if (hour == 4) 246 { 247 return "D"; 248 } 249 else if (hour == 5) 250 { 251 return "E"; 252 } 253 else if (hour == 6) 254 { 255 return "F"; 256 } 257 else if (hour == 7) 258 { 259 return "G"; 260 } 261 else if (hour == 8) 262 { 263 return "H"; 264 } 265 else if (hour == 9) 266 { 267 return "I"; 268 } 269 else if (hour == 10) 270 { 271 return "K"; 272 } 273 else if (hour == 11) 274 { 275 return "L"; 276 } 277 else if (hour == 12) 278 { 279 return "M"; 280 } 281 else 282 { 283 return "-"; 284 } 285 } 286 287 /** 288 * Determines if a symbol, based on it's symbol ID, can have the specified modifier/amplifier. 289 * @param symbolID 30 Character {@link String} 290 * @param modifier {@link Modifiers} 291 * @return {@link Boolean} 292 */ 293 public static Boolean hasModifier(String symbolID, String modifier) 294 { 295 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 296 297 if(msi != null)// && msi.getDrawRule() != DrawRules.DONOTDRAW) 298 { 299 ArrayList<String> mods = msi.getModifiers(); 300 301 if(mods != null && mods.contains(modifier)) 302 return true; 303 else if(msi.getSymbolSet() == SymbolID.SymbolSet_ControlMeasure && modifier.equals(Modifiers.AB_FEINT_DUMMY_INDICATOR)) 304 return true; 305 else 306 return false; 307 } 308 return false; 309 } 310 311 /** 312 * Gets Basic Symbol ID which is the Symbol Set + Entity Code 313 * @param id 30 Character {@link String} 314 * @return 8 character {@link String} (Symbol Set + Entity Code) 315 */ 316 public static String getBasicSymbolID(String id) 317 { 318 if(id.length() == 8) 319 { 320 return id; 321 } 322 else if(id.startsWith("B")) 323 return id; 324 else if(id.equals("octagon")) 325 return id; 326 else if (id.length() >= 20 && id.length() <= 30) 327 { 328 String key = id.substring(4, 6) + id.substring(10, 16); 329 return key; 330 } 331 else if (id.length()==15) 332 { 333 return getBasicSymbolID2525C(id); 334 } 335 return id; 336 } 337 338 /** 339 * Gets the basic Symbol ID for a 2525C symbol 340 * S*F*GPU---***** 341 * G*G*GPP---****X 342 * @param strSymbolID 15 Character {@link String} 343 * @return 15 Character {@link String} 344 */ 345 public static String getBasicSymbolID2525C(String strSymbolID) 346 { 347 if(strSymbolID != null && strSymbolID.length() == 15) 348 { 349 StringBuilder sb = new StringBuilder(); 350 char scheme = strSymbolID.charAt(0); 351 if (scheme == 'G') 352 { 353 sb.append(strSymbolID.charAt(0)); 354 sb.append("*"); 355 sb.append(strSymbolID.charAt(2)); 356 sb.append("*"); 357 sb.append(strSymbolID.substring(4, 10)); 358 sb.append("****X"); 359 } 360 else if (scheme != 'W' && scheme != 'B' && scheme != 'P') 361 { 362 sb.append(strSymbolID.charAt(0)); 363 sb.append("*"); 364 sb.append(strSymbolID.charAt(2)); 365 sb.append("*"); 366 sb.append(strSymbolID.substring(4, 10)); 367 sb.append("*****"); 368 } 369 else 370 { 371 return strSymbolID; 372 } 373 return sb.toString(); 374 } 375 return strSymbolID; 376 } 377 378 /** 379 * Attempts to resolve a bad symbol ID into a value that can be found in {@link MSLookup}. 380 * If it fails, it will return the symbol code for a invalid symbol which is displayed as 381 * an inverted question mark (110098000010000000000000000000) 382 * @param symbolID 30 character {@link String} 383 * @return 30 character {@link String} representing the resolved symbol ID. 384 */ 385 public static String reconcileSymbolID(String symbolID) 386 { 387 388 String newID = ""; 389 try { 390 391 392 int v = SymbolID.getVersion(symbolID); 393 if (v < SymbolID.Version_APP6D) 394 newID = String.valueOf(SymbolID.Version_2525Dch1); 395 else if(v > SymbolID.Version_APP6Ech2) 396 newID = String.valueOf(SymbolID.Version_2525Ech1); 397 v = SymbolID.getVersion(newID); 398 int c = SymbolID.getContext(symbolID); 399 if (c > 4) 400 newID += String.valueOf(SymbolID.StandardIdentity_Context_Reality); 401 else 402 newID += String.valueOf(c); 403 int a = SymbolID.getAffiliation(symbolID); 404 if (a > 6) 405 newID += String.valueOf(SymbolID.StandardIdentity_Affiliation_Unknown); 406 else 407 newID += String.valueOf(a); 408 int ss = SymbolID.getSymbolSet(symbolID); 409 switch (ss) { 410 case SymbolID.SymbolSet_Unknown: 411 case SymbolID.SymbolSet_Air: 412 case SymbolID.SymbolSet_AirMissile: 413 case SymbolID.SymbolSet_SignalsIntelligence_Air: 414 case SymbolID.SymbolSet_Space: 415 case SymbolID.SymbolSet_SpaceMissile: 416 case SymbolID.SymbolSet_SignalsIntelligence_Space: 417 case SymbolID.SymbolSet_LandUnit: 418 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 419 case SymbolID.SymbolSet_LandEquipment: 420 case SymbolID.SymbolSet_SignalsIntelligence_Land: 421 case SymbolID.SymbolSet_LandInstallation: 422 case SymbolID.SymbolSet_DismountedIndividuals: 423 case SymbolID.SymbolSet_SeaSurface: 424 case SymbolID.SymbolSet_SignalsIntelligence_SeaSurface: 425 case SymbolID.SymbolSet_SeaSubsurface: 426 case SymbolID.SymbolSet_MineWarfare: 427 case SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface: 428 case SymbolID.SymbolSet_Activities: 429 case SymbolID.SymbolSet_ControlMeasure: 430 case SymbolID.SymbolSet_Atmospheric: 431 case SymbolID.SymbolSet_Oceanographic: 432 case SymbolID.SymbolSet_MeteorologicalSpace: 433 case SymbolID.SymbolSet_CyberSpace: 434 newID += String.format("%02d",ss); 435 break; 436 default: 437 newID += String.format("%02d", SymbolID.SymbolSet_Unknown);//String.valueOf(SymbolID.SymbolSet_Unknown); 438 } 439 440 int s = SymbolID.getStatus(symbolID); 441 if (s > SymbolID.Status_Present_FullToCapacity) 442 newID += String.valueOf(SymbolID.Status_Present); 443 else 444 newID += String.valueOf(s); 445 446 newID += String.valueOf(SymbolID.getHQTFD(symbolID));//just add, won't get used if value bad 447 newID += String.format("%02d",SymbolID.getAmplifierDescriptor(symbolID));//just add, won't get used if value bad 448 449 int ec = SymbolID.getEntityCode(symbolID); 450 451 if (ec == 0) 452 newID += "000000";//root symbol for symbol set 453 else if (SVGLookup.getInstance().getSVGLInfo(SVGLookup.getMainIconID(newID + ec + "0000"), v) == null) { 454 //set to blank symbol 455 newID += "000000"; 456 /*//set to invalid symbol since we couldn't find it in the lookup 457 newID = SymbolID.setSymbolSet(newID, 98); 458 newID += 100000;//*/ 459 } 460 else 461 newID += String.format("%06d",ec);//we found it so add the entity code 462 463 //newID += SymbolID.getMod1ID(symbolID);//just add, won't get used if value bad 464 //newID += SymbolID.getMod2ID(symbolID);//just add, won't get used if value bad 465 newID += symbolID.substring(16);//just add, won't get used if value bad 466 } 467 catch(Exception exc) 468 { 469 newID = "110098000010000000000000000000";//invalid symbol 470 } 471 472 return newID; 473 } 474 475 /** 476 * Gets line color used if no line color has been set. The color is specified based on the affiliation of 477 * the symbol and whether it is a unit or not. 478 * @param symbolID 30 character {@link String} 479 * @return {@link Color} 480 */ 481 public static Color getLineColorOfAffiliation(String symbolID) 482 { 483 Color retColor = null; 484 485 int symbolSet = SymbolID.getSymbolSet(symbolID); 486 int set = SymbolID.getSymbolSet(symbolID); 487 int affiliation = SymbolID.getAffiliation(symbolID); 488 int symStd = SymbolID.getVersion(symbolID); 489 int entityCode = SymbolID.getEntityCode(symbolID); 490 491 try 492 { 493 // We can't get the line color if there is no symbol id, since that also means there is no affiliation 494 if((symbolID == null) || (symbolID.equals(""))) 495 { 496 return retColor; 497 } 498 499 if(symbolSet == SymbolID.SymbolSet_ControlMeasure) 500 { 501 int entity = SymbolID.getEntity(symbolID); 502 int entityType = SymbolID.getEntityType(symbolID); 503 int entitySubtype = SymbolID.getEntitySubtype(symbolID); 504 505 if(SymbolUtilities.isGreenProtectionGraphic(entity, entityType, entitySubtype)) 506 { 507 //Obstacles/Protection Graphics, some are green obstacles and we need to 508 //check for those. 509 retColor = AffiliationColors.ObstacleGreen; 510 } 511 //just do color by affiliation if no other color has been set yet. 512 if(retColor == null) 513 { 514 switch (affiliation) { 515 case SymbolID.StandardIdentity_Affiliation_Friend: 516 case SymbolID.StandardIdentity_Affiliation_AssumedFriend: 517 retColor = AffiliationColors.FriendlyGraphicLineColor;//Color.BLACK;//0x000000; // Black 518 break; 519 case SymbolID.StandardIdentity_Affiliation_Hostile_Faker: 520 retColor = AffiliationColors.HostileGraphicLineColor;//Color.RED;//0xff0000; // Red 521 break; 522 case SymbolID.StandardIdentity_Affiliation_Suspect_Joker: 523 if(symStd >= SymbolID.Version_2525E) 524 retColor = AffiliationColors.SuspectGraphicLineColor;//255,188,1 525 else 526 retColor = AffiliationColors.HostileGraphicLineColor;//Color.RED;//0xff0000; // Red 527 break; 528 case SymbolID.StandardIdentity_Affiliation_Neutral: 529 retColor = AffiliationColors.NeutralGraphicLineColor;//Color.GREEN;//0x00ff00; // Green 530 break; 531 default: 532 retColor = AffiliationColors.UnknownGraphicLineColor;//Color.YELLOW;//0xffff00; // Yellow 533 break; 534 } 535 } 536 } 537 else if (set >= 45 && set <= 47)//METOC 538 { 539 // If not black then color will be set in clsMETOC.SetMeTOCProperties() 540 retColor = Color.BLACK; 541 } 542 else if (set == SymbolID.SymbolSet_MineWarfare && (RendererSettings.getInstance().getSeaMineRenderMethod() == RendererSettings.SeaMineRenderMethod_MEDAL)) 543 { 544 if(!(entityCode == 110600 || entityCode == 110700)) 545 { 546 switch(affiliation) 547 { 548 case SymbolID.StandardIdentity_Affiliation_Friend: 549 case SymbolID.StandardIdentity_Affiliation_AssumedFriend: 550 retColor = AffiliationColors.FriendlyUnitFillColor;//0x00ffff; // Cyan 551 break; 552 case SymbolID.StandardIdentity_Affiliation_Hostile_Faker: 553 retColor = AffiliationColors.HostileUnitFillColor;//Color.RED;//0xff0000; // Red 554 break; 555 case SymbolID.StandardIdentity_Affiliation_Suspect_Joker: 556 if(symStd >= SymbolID.Version_2525E) 557 retColor = AffiliationColors.SuspectUnitFillColor;//255,188,1 558 else 559 retColor = AffiliationColors.HostileUnitFillColor;//Color.RED;//0xff0000; // Red 560 break; 561 case SymbolID.StandardIdentity_Affiliation_Neutral: 562 retColor = AffiliationColors.NeutralUnitFillColor;//0x7fff00; // Light Green 563 break; 564 default://unknown, pending, everything else 565 retColor = AffiliationColors.UnknownUnitFillColor;//new Color(255,250, 205); //0xfffacd; // LemonChiffon 255 250 205 566 break; 567 } 568 } 569 else 570 { 571 retColor = Color.BLACK; 572 } 573 } 574 else//everything else 575 { 576 //stopped doing check because all warfighting 577 //should have black for line color. 578 retColor = Color.BLACK; 579 } 580 } 581 catch(Exception e) 582 { 583 // Log Error 584 ErrorLogger.LogException("SymbolUtilities", "getLineColorOfAffiliation", e); 585 //throw e; 586 } // End catch 587 return retColor; 588 } // End get LineColorOfAffiliation 589 590 /** 591 * For Control Measures, returns the default color for a symbol when it differs from the 592 * affiliation line color. If there is no default color, returns the value from {@link #getLineColorOfAffiliation} 593 * @param symbolID 30 Character {@link String} 594 * @return {@link Color} 595 */ 596 public static Color getDefaultLineColor(String symbolID) { 597 try { 598 if (symbolID == null || symbolID.equals("")) { 599 return null; 600 } 601 602 int symbolSet = SymbolID.getSymbolSet(symbolID); 603 int entityCode = SymbolID.getEntityCode(symbolID); 604 int version = SymbolID.getVersion(symbolID); 605 606 if (symbolSet == SymbolID.SymbolSet_ControlMeasure) { 607 if (entityCode == 200600) { 608 return Color.WHITE; 609 } else if (entityCode == 200700) { 610 return new Color(51, 136, 136); 611 } else if (entityCode == 200101) { 612 return new Color(255, 155, 0); 613 } else if (entityCode == 200201 || entityCode == 200202) { 614 return new Color(85, 119, 136); 615 } else if (version >= SymbolID.Version_2525E && 616 (entityCode == 132100 || //key terrain 617 entityCode == 282001 || //Tower, Low 618 entityCode == 282002 || //Tower, High 619 entityCode == 282003)) { // Overhead Wire 620 return new Color(128, 0, 128);//purple 621 } 622 } 623 } catch (Exception e) { 624 ErrorLogger.LogException("SymbolUtilities", "getDefaultLineColor", e); 625 } 626 return getLineColorOfAffiliation(symbolID); 627 } 628 629 /** 630 * Checks if a symbol should be filled by default 631 * 632 * @param strSymbolID The 20 digit representation of the 2525D symbol 633 * @return true if there is a default fill 634 */ 635 public static boolean hasDefaultFill(String strSymbolID) { 636 int ec = SymbolID.getEntityCode(strSymbolID); 637 switch (ec) { 638 case 200101: 639 case 200201: 640 case 200202: 641 case 200600: 642 case 200700: 643 return true; 644 default: 645 return !SymbolUtilities.isTacticalGraphic(strSymbolID); 646 } 647 } 648 649 /** 650 * Determines if the symbol is a tactical graphic 651 * 652 * @param strSymbolID 30 Character {@link String} 653 * @return true if symbol set is 25 (control measure), or is a weather graphic 654 */ 655 public static boolean isTacticalGraphic(String strSymbolID) { 656 try { 657 int ss = SymbolID.getSymbolSet(strSymbolID); 658 659 if(ss == SymbolID.SymbolSet_ControlMeasure || isWeather(strSymbolID)) { 660 return true; 661 } 662 } 663 catch (Exception e) { 664 ErrorLogger.LogException("SymbolUtilities", "getFillColorOfAffiliation", e); 665 } 666 return false; 667 } 668 669 /** 670 * Determines if the Symbol can be rendered as a multipoint graphic and not just as an icon 671 * @param symbolID 30 Character {@link String} 672 * @return {@link Boolean} 673 */ 674 public static boolean isMultiPoint(String symbolID) 675 { 676 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 677 if (msi == null) { 678 return false; 679 } 680 int drawRule = msi.getDrawRule(); 681 int ss = msi.getSymbolSet(); 682 if(ss != SymbolID.SymbolSet_ControlMeasure && ss != SymbolID.SymbolSet_Oceanographic && ss != SymbolID.SymbolSet_Atmospheric && ss != SymbolID.SymbolSet_MeteorologicalSpace) 683 { 684 return false; 685 } 686 else if (ss == SymbolID.SymbolSet_ControlMeasure) 687 { 688 if(msi.getMaxPointCount() > 1) 689 return true; 690 else if((drawRule < DrawRules.POINT1 || drawRule > DrawRules.POINT16 || drawRule == DrawRules.POINT12) && 691 drawRule != DrawRules.DONOTDRAW && drawRule != DrawRules.AREA22) 692 { 693 return true; 694 } 695 else 696 return false; 697 } 698 else if(ss == SymbolID.SymbolSet_Oceanographic || ss == SymbolID.SymbolSet_Atmospheric || ss == SymbolID.SymbolSet_MeteorologicalSpace) 699 { 700 if(msi.getMaxPointCount() > 1) 701 return true; 702 else 703 return false; 704 } 705 return false; 706 } 707 708 public static boolean isActionPoint(String symbolID) 709 { 710 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 711 if(msi.getDrawRule()==DrawRules.POINT1) 712 { 713 int ec = SymbolID.getEntityCode(symbolID); 714 if(ec != 131300 && ec != 131301 && ec != 182600 && ec != 212800 715 && ec != 360100 && ec != 360200 && ec != 360300) 716 return true; 717 } 718 return false; 719 } 720 721 /** 722 * Control Measures and Tactical Graphics that have labels but not with the Action Point layout 723 * @param strSymbolID 30 Character {@link String} 724 * @return {@link Boolean} 725 + @deprecated see {@link #isSPWithSpecialModifierLayout(String)} 726 */ 727 public static boolean isTGSPWithSpecialModifierLayout(String strSymbolID) 728 { 729 try 730 { 731 int ss = SymbolID.getSymbolSet(strSymbolID); 732 int entityCode = SymbolID.getEntityCode(strSymbolID); 733 if(ss == SymbolID.SymbolSet_ControlMeasure) //|| isWeather(strSymbolID)) { 734 { 735 if(SymbolUtilities.isCBRNEvent(strSymbolID)) 736 return true; 737 738 if(SymbolUtilities.isSonobuoy(strSymbolID)) 739 return true; 740 741 switch (entityCode) 742 { 743 case 130500: //contact point 744 case 130700: //decision point 745 case 212800: //harbor 746 case 210300: //Defended Asset 747 case 210600: //Air Detonation 748 case 131300: //point of interest 749 case 131800: //waypoint 750 case 240900: //fire support station 751 case 180100: //Air Control point 752 case 180200: //Communications Check point 753 case 160300: //T (target reference point) 754 case 240601: //ap,ap1,x,h (Point/Single Target) 755 case 240602: //ap (nuclear target) 756 case 270701: //static depiction 757 case 282001: //tower, low 758 case 282002: //tower, high 759 return true; 760 default: 761 return false; 762 } 763 } 764 else if(ss == SymbolID.SymbolSet_Atmospheric) 765 { 766 switch (entityCode) 767 { 768 case 162300: //Freezing Level 769 case 162200: //tropopause Level 770 case 110102: //tropopause Low 771 case 110202: //tropopause High 772 return true; 773 default: 774 return false; 775 } 776 } 777 } 778 catch (Exception e) { 779 ErrorLogger.LogException("SymbolUtilities", "getFillColorOfAffiliation", e); 780 } 781 return false; 782 } 783 784 /** 785 * Returns the fill color for the symbol based on its affiliation 786 * @param symbolID 30 Character {@link String} 787 * @return {@link Color} 788 */ 789 public static Color getFillColorOfAffiliation(String symbolID) 790 { 791 Color retColor = null; 792 int entityCode = SymbolID.getEntityCode(symbolID); 793 int entity = SymbolID.getEntity(symbolID); 794 int entityType = SymbolID.getEntityType(symbolID); 795 int entitySubtype = SymbolID.getEntitySubtype(symbolID); 796 797 int affiliation = SymbolID.getAffiliation(symbolID); 798 799 try 800 { 801 // We can't get the fill color if there is no symbol id, since that also means there is no affiliation 802 if ((symbolID == null) || (symbolID.equals(""))) { 803 return retColor; 804 } 805 if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure) { 806 switch (entityCode) { 807 case 200101: 808 retColor = new Color(255, 155, 0, (int) (.25 * 255)); 809 break; 810 case 200201: 811 case 200202: 812 case 200600: 813 retColor = new Color(85, 119, 136, (int) (.25 * 255)); 814 break; 815 case 200700: 816 retColor = new Color(51, 136, 136, (int) (.25 * 255)); 817 break; 818 } 819 } 820 else if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_MineWarfare && 821 (RendererSettings.getInstance().getSeaMineRenderMethod() == RendererSettings.SeaMineRenderMethod_MEDAL) && 822 (!(entityCode == 110600 || entityCode == 110700))) 823 { 824 retColor = new Color(0,0,0,0);//transparent 825 } 826 //just do color by affiliation if no other color has been set yet 827 if (retColor == null) { 828 switch(affiliation) 829 { 830 case SymbolID.StandardIdentity_Affiliation_Friend: 831 case SymbolID.StandardIdentity_Affiliation_AssumedFriend: 832 retColor = AffiliationColors.FriendlyUnitFillColor;//0x00ffff; // Cyan 833 break; 834 case SymbolID.StandardIdentity_Affiliation_Hostile_Faker: 835 retColor = AffiliationColors.HostileUnitFillColor;//0xfa8072; // Salmon 836 break; 837 case SymbolID.StandardIdentity_Affiliation_Suspect_Joker: 838 if(SymbolID.getVersion(symbolID) >= SymbolID.Version_2525E) 839 retColor = AffiliationColors.SuspectGraphicFillColor;//255,229,153 840 else 841 retColor = AffiliationColors.HostileGraphicFillColor;//Color.RED;//0xff0000; // Red 842 break; 843 case SymbolID.StandardIdentity_Affiliation_Neutral: 844 retColor = AffiliationColors.NeutralUnitFillColor;//0x7fff00; // Light Green 845 break; 846 default://unknown, pending, everything else 847 retColor = AffiliationColors.UnknownUnitFillColor;//new Color(255,250, 205); //0xfffacd; // LemonChiffon 255 250 205 848 break; 849 } 850 } 851 } // End try 852 catch (Exception e) 853 { 854 // Log Error 855 ErrorLogger.LogException("SymbolUtilities", "getFillColorOfAffiliation", e); 856 //throw e; 857 } // End catch 858 859 return retColor; 860 } // End FillColorOfAffiliation 861 862 /** 863 * 864 * @param symbolID 30 Character {@link String} 865 * @param modifier {@link Modifiers} 866 * @return {@link Boolean} 867 * @deprecated see {@link #hasModifier(String, String)} 868 */ 869 public static Boolean canSymbolHaveModifier(String symbolID, String modifier) 870 { 871 return hasModifier(symbolID, modifier); 872 } 873 874 /** 875 * Checks if the Symbol Code has FDI set. 876 * Does not check if the symbol can have an FDI. 877 * @param symbolID 30 Character {@link String} 878 * @return {@link Boolean} 879 */ 880 public static Boolean hasFDI(String symbolID) 881 { 882 int hqtfd = SymbolID.getHQTFD(symbolID); 883 if(hqtfd == SymbolID.HQTFD_FeintDummy 884 || hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce 885 || hqtfd == SymbolID.HQTFD_FeintDummy_Headquarters 886 || hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce_Headquarters) 887 { 888 return true; 889 } 890 else 891 return false; 892 } 893 894 /* 895 * For Renderer Use Only 896 * Assumes a fresh SVG String from the SVGLookup with its default values 897 * @param symbolID 898 * @param svg 899 * @param strokeColor 900 * @param fillColor 901 * @return 902 */ 903 /*public static String setSVGFrameColors(String symbolID, String svg, Color strokeColor, Color fillColor) 904 { 905 String hexStrokeColor = null; 906 String hexFillColor = null; 907 908 if(strokeColor != null) 909 hexStrokeColor = colorToHexString(strokeColor,false); 910 if(fillColor != null) 911 hexFillColor = colorToHexString(fillColor,false); 912 return setSVGFrameColors(symbolID, svg, hexStrokeColor,hexFillColor); 913 }//*/ 914 915 /*** 916 * Returns true if graphic is protection graphic (obstacles which render green) 917 * Assumes control measure symbol code where SS == 25 918 * @param entity {@link Integer} 919 * @param entityType {@link Integer} 920 * @param entitySubtype {@link Integer} 921 * @return {@link Boolean} 922 */ 923 public static boolean isGreenProtectionGraphic(int entity, int entityType, int entitySubtype) 924 { 925 if(entity >= 27 && entity <= 29)//Protection Areas, Points and Lines 926 { 927 if(entity == 27) 928 { 929 if(entityType > 0 && entityType <= 5) 930 return true; 931 else if(entityType == 7 || entityType == 8 || entityType == 10 || entityType == 12) 932 { 933 return true; 934 } 935 else 936 return false; 937 } 938 else if(entity == 28) 939 { 940 if(entityType > 0 && entityType <= 7) 941 return true; 942 if(entityType == 19) 943 return true; 944 else 945 return false; 946 } 947 else if(entity == 29) 948 { 949 if(entityType >= 01 && entityType <= 05) 950 return true; 951 else 952 return false; 953 } 954 } 955 else 956 { 957 return false; 958 } 959 return false; 960 } 961 962 /** 963 * Returns true if graphic is protection graphic (obstacles which render green) 964 * @param symbolID 30 Character {@link String} 965 * @return {@link Boolean} 966 */ 967 public static boolean isGreenProtectionGraphic(String symbolID){ 968 if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure) { 969 return SymbolUtilities.isGreenProtectionGraphic(SymbolID.getEntity(symbolID), SymbolID.getEntityType(symbolID), SymbolID.getEntitySubtype(symbolID)); 970 } else { 971 return false; 972 } 973 } 974 975 /** 976 * Returns true if Symbol ID represents a chemical, biological, radiological or nuclear incident. 977 * @param symbolID 30 Character {@link String} 978 * @return {@link Boolean} 979 */ 980 public static boolean isCBRNEvent(String symbolID) 981 { 982 int ss = SymbolID.getSymbolSet(symbolID); 983 int ec = SymbolID.getEntityCode(symbolID); 984 985 if(ss == SymbolID.SymbolSet_ControlMeasure) { 986 switch (ec) 987 { 988 case 281300: 989 case 281301: 990 case 281400: 991 case 281401: 992 case 281500: 993 case 281600: 994 case 281700: 995 case 281701: 996 return true; 997 default: 998 } 999 } 1000 return false; 1001 } 1002 1003 /** 1004 * Returns true if Symbol ID represents a Sonobuoy. 1005 * @param symbolID 30 Character {@link String} 1006 * @return {@link Boolean} 1007 */ 1008 public static boolean isSonobuoy(String symbolID) 1009 { 1010 int ss = SymbolID.getSymbolSet(symbolID); 1011 int e = SymbolID.getEntity(symbolID); 1012 int et = SymbolID.getEntityType(symbolID); 1013 if(ss == 25 && e == 21 && et == 35) 1014 return true; 1015 else 1016 return false; 1017 } 1018 1019 /** 1020 * Obstacles are generally required to have a green line color 1021 * @param symbolID 30 Character {@link String} 1022 * @return {@link Boolean} 1023 * @deprecated see {@link #isGreenProtectionGraphic(String)} 1024 */ 1025 public static boolean isObstacle(String symbolID) 1026 { 1027 1028 if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure && 1029 SymbolID.getEntity(symbolID) == 27) 1030 { 1031 return true; 1032 } 1033 else 1034 return false; 1035 } 1036 1037 /** 1038 * Return true if symbol is from the Atmospheric, Oceanographic or Meteorological Space Symbol Sets. 1039 * @param symbolID 30 Character {@link String} 1040 * @return {@link Boolean} 1041 */ 1042 public static boolean isWeather(String symbolID) 1043 { 1044 int ss = SymbolID.getSymbolSet(symbolID); 1045 if(ss >= SymbolID.SymbolSet_Atmospheric && ss <= SymbolID.SymbolSet_MeteorologicalSpace) 1046 return true; 1047 else 1048 return false; 1049 } 1050 1051 /** 1052 * Returns true if the symbol has the HQ staff indicated by the symbol ID 1053 * @param symbolID 30 Character {@link String} 1054 * @return {@link Boolean} 1055 */ 1056 public static boolean isHQ(String symbolID) 1057 { 1058 int hq = SymbolID.getHQTFD(symbolID); 1059 if(SymbolUtilities.hasModifier(symbolID, Modifiers.S_HQ_STAFF_INDICATOR) && 1060 (hq == SymbolID.HQTFD_FeintDummy_Headquarters || 1061 hq == SymbolID.HQTFD_Headquarters || 1062 hq == SymbolID.HQTFD_FeintDummy_TaskForce_Headquarters || 1063 hq == SymbolID.HQTFD_TaskForce_Headquarters)) 1064 return true; 1065 else 1066 return false; 1067 } 1068 1069 /** 1070 * Checks if this is a single point control measure or meteorological graphic with a unique layout. 1071 * Basically anything that's not an action point style graphic with modifiers 1072 * @param symbolID 30 Character {@link String} 1073 * @return {@link Boolean} 1074 */ 1075 public static boolean isSPWithSpecialModifierLayout(String symbolID) 1076 { 1077 int ss = SymbolID.getSymbolSet(symbolID); 1078 int ec = SymbolID.getEntityCode(symbolID); 1079 1080 if(ss == SymbolID.SymbolSet_ControlMeasure) 1081 { 1082 switch(ec) 1083 { 1084 case 130500: //Control Point 1085 case 130700: //Decision Point 1086 case 131300: //Point of Interest 1087 case 131800: //Waypoint 1088 case 131900: //Airfield (AEGIS Only) 1089 case 132000: //Target Handover 1090 case 132100: //Key Terrain 1091 case 132300: //Vital Ground 1092 case 160300: //Target Point Reference 1093 case 180100: //Air Control Point 1094 case 180200: //Communications Check Point 1095 case 180600: //TACAN 1096 case 210300: //Defended Asset 1097 case 210600: //Air Detonation 1098 case 210800: //Impact Point 1099 case 211000: //Launched Torpedo 1100 case 212800: //Harbor 1101 case 213400: //Navigational reference waypoint 1102 case 213500: //Sonobuoy 1103 case 213501: //Ambient Noise Sonobuoy 1104 case 213502: //Air Transportable Communication (ATAC) (Sonobuoy) 1105 case 213503: //Barra (Sonobuoy) 1106 case 213504: 1107 case 213505: 1108 case 213506: 1109 case 213507: 1110 case 213508: 1111 case 213509: 1112 case 213510: 1113 case 213511: 1114 case 213512: 1115 case 213513: 1116 case 213514: 1117 case 213515: 1118 case 214900: //General Sea Subsurface Station 1119 case 215600: //General Sea Station 1120 case 217000: //Shore Control Station 1121 case 240601: //Point or Single Target 1122 case 240602: //Nuclear Target 1123 case 240900: //Fire Support Station 1124 case 250600: //Known Point 1125 case 270701: //Static Depiction 1126 case 282001: //Tower, Low 1127 case 282002: //Tower, High 1128 case 281300: //Chemical Event 1129 case 281301: //Chemical Event - toxic material 1130 case 281400: //Biological Event 1131 case 281402: //Biological Event - toxic material 1132 case 281500: //Nuclear Event 1133 case 281600: //Nuclear Fallout Producing Event 1134 case 281700: //Radiological Event 1135 case 281701: //Radiological Event - toxic material 1136 case 360100: //Protection of cultural property - General 1137 case 360200: //Protection of cultural property - Special 1138 case 360300: //Protection of cultural property - Enhanced 1139 return true; 1140 default: 1141 return false; 1142 } 1143 } 1144 else if(ss == SymbolID.SymbolSet_Atmospheric) 1145 { 1146 switch(ec) 1147 { 1148 case 162300: //Freezing Level 1149 case 162200: //tropopause Level 1150 case 110102: //tropopause low 1151 case 110202: //tropopause high 1152 return true; 1153 default: 1154 return false; 1155 } 1156 } 1157 return false; 1158 } 1159 1160 /** 1161 * Gets the anchor point for single point Control Measure as the anchor point isn't always they center of the symbol. 1162 * @param symbolID 30 Character {@link String} 1163 * @param bounds {@link RectF} representing the bound of the core symbol in the image. 1164 * @return {@link Point} representing the point in the image that is the anchor point of the symbol. 1165 */ 1166 public static Point getCMSymbolAnchorPoint(String symbolID, RectF bounds) { 1167 float centerX = (bounds.width() / 2f) - 1;//-1 because width might be 37 but the points are only 0 - 36 1168 float centerY = (bounds.height() / 2f) - 1; 1169 1170 int ss = SymbolID.getSymbolSet(symbolID); 1171 int ec = SymbolID.getEntityCode(symbolID); 1172 int drawRule = 0; 1173 1174 //center/anchor point is always half width and half height except for control measures 1175 //and meteorological 1176 if (ss == SymbolID.SymbolSet_ControlMeasure) { 1177 drawRule = MSLookup.getInstance().getMSLInfo(symbolID).getDrawRule(); 1178 switch (drawRule)//here we check the 'Y' value for the anchor point 1179 { 1180 case DrawRules.POINT1://action points 1301 //bottom center 1181 case DrawRules.POINT5://entry point 2105 1182 case DrawRules.POINT6://ground zero 2107 1183 case DrawRules.POINT7://missile detection point 2111 1184 centerY = bounds.height()-1; 1185 break; 1186 case DrawRules.POINT4://drop point 2104 //almost bottom and center 1187 centerY = (bounds.height() * 0.80f); 1188 break; 1189 case DrawRules.POINT10://Sonobuoy 2135 //center of circle which isn't center of symbol 1190 centerY = (bounds.height() * 0.75f); 1191 break; 1192 case DrawRules.POINT13://booby trap 2807 //almost bottom and center 1193 centerY = (bounds.height() * 0.74f); 1194 break; 1195 case DrawRules.POINT15://Marine Life 2189 //center left 1196 centerX = 0; 1197 break; 1198 case DrawRules.POINT16://Tower 282001 //circle at base of tower 1199 centerY = (bounds.height() * 0.87f); 1200 break; 1201 case DrawRules.POINT2://Several different symbols 1202 if (ec == 280500)//Wide Area Antitank Mine 1203 centerY = (bounds.height() * 0.35f); 1204 else if (ec == 280400)//Antitank Mine w/ Anti-handling Device 1205 centerY = (bounds.height() * 0.33f); 1206 else if (ec == 280200)//Antipersonnel Mine 1207 centerY = (bounds.height() * 0.7f); 1208 else if (ec == 280201)//Antipersonnel Mine with Directional Effects 1209 centerY = (bounds.height() * 0.65f); 1210 else if (ec == 219000)//Sea Anomaly 1211 centerY = (bounds.height() * 0.7f); 1212 else if (ec == 212500)//Electromagnetic - Magnetic Anomaly Detections (MAD) 1213 centerY = (bounds.height() * 0.4f); 1214 else if (ec/100 == 2135) {//2525E sonobuoys 1215 centerY = (bounds.height() * 0.75f); 1216 } 1217 break; 1218 default: 1219 } 1220 1221 switch (ec) 1222 //have to adjust center X as some graphics have integrated text outside the symbol 1223 { 1224 case 180400: //Pickup Point (PUP) 1225 centerX = bounds.width() * 0.3341f; 1226 break; 1227 case 240900: //Fire Support Station 1228 centerX = bounds.width() * 0.38f; 1229 break; 1230 case 280201: //Antipersonnel Mine with Directional Effects 1231 centerX = bounds.width() * 0.43f; 1232 break; 1233 case 182300: //Orbit - Figure Eight 1234 case 182400: //Orbit - Race Track 1235 case 182500: //Orbit - Random Closed 1236 if(SymbolID.getVersion(symbolID) >= SymbolID.Version_2525E) 1237 centerY = bounds.height() * 0.27f; 1238 break; 1239 } 1240 } 1241 1242 return new Point(Math.round(centerX), Math.round(centerY)); 1243 } 1244 1245 /** 1246 * Returns true if the symbol is an installation 1247 * @param symbolID 30 Character {@link String} 1248 * @return {@link Boolean} 1249 */ 1250 public static Boolean isInstallation(String symbolID) 1251 { 1252 int ss = SymbolID.getSymbolSet(symbolID); 1253 int entity = SymbolID.getEntity(symbolID); 1254 if(ss == SymbolID.SymbolSet_LandInstallation && entity == 11) 1255 return true; 1256 else 1257 return false; 1258 } 1259 1260 /** 1261 * Returns true if the symbol is from an air based symbol set 1262 * @param symbolID 30 Character {@link String} 1263 * @return {@link Boolean} 1264 */ 1265 public static Boolean isAir(String symbolID) 1266 { 1267 int ss = SymbolID.getSymbolSet(symbolID); 1268 int entity = SymbolID.getEntity(symbolID); 1269 if(ss == SymbolID.SymbolSet_Air || 1270 ss == SymbolID.SymbolSet_AirMissile || 1271 ss == SymbolID.SymbolSet_SignalsIntelligence_Air) 1272 return true; 1273 else 1274 return false; 1275 } 1276 1277 /** 1278 * Returns true if the symbol is from a space based symbol set 1279 * @param symbolID 30 Character {@link String} 1280 * @return {@link Boolean} 1281 */ 1282 public static Boolean isSpace(String symbolID) 1283 { 1284 int ss = SymbolID.getSymbolSet(symbolID); 1285 int entity = SymbolID.getEntity(symbolID); 1286 if(ss == SymbolID.SymbolSet_Space || 1287 ss == SymbolID.SymbolSet_SpaceMissile || 1288 ss == SymbolID.SymbolSet_SignalsIntelligence_Space) 1289 return true; 1290 else 1291 return false; 1292 } 1293 1294 /** 1295 * Returns true if the symbol is from a land based symbol set 1296 * @param symbolID 30 Character {@link String} 1297 * @return {@link Boolean} 1298 */ 1299 public static Boolean isLand(String symbolID) 1300 { 1301 int ss = SymbolID.getSymbolSet(symbolID); 1302 int entity = SymbolID.getEntity(symbolID); 1303 if(ss == SymbolID.SymbolSet_LandUnit || 1304 ss == SymbolID.SymbolSet_LandCivilianUnit_Organization || 1305 ss == SymbolID.SymbolSet_LandEquipment || 1306 ss == SymbolID.SymbolSet_LandInstallation || 1307 ss == SymbolID.SymbolSet_SignalsIntelligence_Land) 1308 return true; 1309 else 1310 return false; 1311 } 1312 1313 /** 1314 * Returns true if the symbol ID has the task for indicator 1315 * @param symbolID 30 Character {@link String} 1316 * @return {@link Boolean} 1317 */ 1318 public static Boolean isTaskForce(String symbolID) 1319 { 1320 int hqtfd = SymbolID.getHQTFD(symbolID); 1321 if((hqtfd == SymbolID.HQTFD_TaskForce || 1322 hqtfd == SymbolID.HQTFD_TaskForce_Headquarters || 1323 hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce || 1324 hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce_Headquarters) && 1325 SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.B_ECHELON)) 1326 return true; 1327 else 1328 return false; 1329 } 1330 1331 /** 1332 * Returns true if the symbol ID indicates the context is Reality 1333 * @param symbolID 30 Character {@link String} 1334 * @return {@link Boolean} 1335 */ 1336 public static Boolean isReality(String symbolID) 1337 { 1338 int c = SymbolID.getContext(symbolID); 1339 if(c == SymbolID.StandardIdentity_Context_Reality || 1340 c == 3 || c == 4) 1341 return true; 1342 else 1343 return false; 1344 } 1345 1346 /** 1347 * Returns true if the symbol ID indicates the context is Exercise 1348 * @param symbolID 30 Character {@link String} 1349 * @return {@link Boolean} 1350 */ 1351 public static Boolean isExercise(String symbolID) 1352 { 1353 int c = SymbolID.getContext(symbolID); 1354 if(c == SymbolID.StandardIdentity_Context_Exercise || 1355 c == 5 || c == 6) 1356 return true; 1357 else 1358 return false; 1359 } 1360 1361 /** 1362 * Returns true if the symbol ID indicates the context is Simulation 1363 * @param symbolID 30 Character {@link String} 1364 * @return {@link Boolean} 1365 */ 1366 public static Boolean isSimulation(String symbolID) 1367 { 1368 int c = SymbolID.getContext(symbolID); 1369 if(c == SymbolID.StandardIdentity_Context_Simulation || 1370 c == 7 || c == 8) 1371 return true; 1372 else 1373 return false; 1374 } 1375 1376 1377 /** 1378 * Reads the Symbol ID string and returns the text that represents the echelon 1379 * code. 1380 * @param echelon {@link Integer} from positions 9-10 in the symbol ID 1381 * See {@link SymbolID#getAmplifierDescriptor(String)} 1382 * @return {@link String} (23 (Army) would be "XXXX") 1383 */ 1384 public static String getEchelonText(int echelon) 1385 { 1386 char[] dots = new char[3]; 1387 dots[0] = (char)8226; 1388 dots[1] = (char)8226; 1389 dots[2] = (char)8226; 1390 String dot = new String(dots); 1391 String text = null; 1392 if(echelon == SymbolID.Echelon_Team_Crew) 1393 { 1394 text = (char) 216 + ""; 1395 } 1396 else if(echelon == SymbolID.Echelon_Squad) 1397 { 1398 text = dot.substring(0, 1); 1399 } 1400 else if(echelon == SymbolID.Echelon_Section) 1401 { 1402 text = dot.substring(0, 2); 1403 } 1404 else if(echelon == SymbolID.Echelon_Platoon_Detachment) 1405 { 1406 text = dot; 1407 } 1408 else if(echelon == SymbolID.Echelon_Company_Battery_Troop) 1409 { 1410 text = "I"; 1411 } 1412 else if(echelon == SymbolID.Echelon_Battalion_Squadron) 1413 { 1414 text = "II"; 1415 } 1416 else if(echelon == SymbolID.Echelon_Regiment_Group) 1417 { 1418 text = "III"; 1419 } 1420 else if(echelon == SymbolID.Echelon_Brigade) 1421 { 1422 text = "X"; 1423 } 1424 else if(echelon == SymbolID.Echelon_Division) 1425 { 1426 text = "XX"; 1427 } 1428 else if(echelon == SymbolID.Echelon_Corps_MEF) 1429 { 1430 text = "XXX"; 1431 } 1432 else if(echelon == SymbolID.Echelon_Army) 1433 { 1434 text = "XXXX"; 1435 } 1436 else if(echelon == SymbolID.Echelon_ArmyGroup_Front) 1437 { 1438 text = "XXXXX"; 1439 } 1440 else if(echelon == SymbolID.Echelon_Region_Theater) 1441 { 1442 text = "XXXXXX"; 1443 } 1444 else if(echelon == SymbolID.Echelon_Region_Command) 1445 { 1446 text = "++"; 1447 } 1448 return text; 1449 } 1450 1451 /** 1452 * Returns the Standard Identity Modifier based on the Symbol ID 1453 * @param symbolID 30 Character {@link String} 1454 * @return {@link String} 1455 */ 1456 public static String getStandardIdentityModifier(String symbolID) 1457 { 1458 String textChar = null; 1459 int si = SymbolID.getStandardIdentity(symbolID); 1460 int context = SymbolID.getContext(symbolID); 1461 int affiliation = SymbolID.getAffiliation(symbolID); 1462 1463 if(context == SymbolID.StandardIdentity_Context_Simulation)//Simulation 1464 textChar = "S"; 1465 else if(context == SymbolID.StandardIdentity_Context_Exercise) 1466 { 1467 if(affiliation == SymbolID.StandardIdentity_Affiliation_Suspect_Joker)//exercise Joker 1468 textChar = "J"; 1469 else if(affiliation == SymbolID.StandardIdentity_Affiliation_Hostile_Faker)//exercise faker 1470 textChar = "K"; 1471 else if(context == SymbolID.StandardIdentity_Context_Exercise)//exercise 1472 textChar = "X"; 1473 } 1474 1475 return textChar; 1476 } 1477 1478 /** 1479 * 1480 * @param symbolID 1481 * @return 1482 */ 1483 public static boolean hasRectangleFrame(String symbolID) 1484 { 1485 int affiliation = SymbolID.getAffiliation(symbolID); 1486 int ss = SymbolID.getSymbolSet(symbolID); 1487 if(ss != SymbolID.SymbolSet_ControlMeasure) 1488 { 1489 if (affiliation == SymbolID.StandardIdentity_Affiliation_Friend 1490 || affiliation == SymbolID.StandardIdentity_Affiliation_AssumedFriend 1491 || (SymbolID.getContext(symbolID)==SymbolID.StandardIdentity_Context_Exercise && 1492 (affiliation == SymbolID.StandardIdentity_Affiliation_Hostile_Faker 1493 || affiliation == SymbolID.StandardIdentity_Affiliation_Suspect_Joker))) 1494 { 1495 return true; 1496 } 1497 else 1498 return false; 1499 } 1500 else 1501 return false; 1502 } 1503 1504 /** 1505 * Returns the height ratio for the unit specified by the symbol ID 1506 * Based on Figure 4 in 2525E. 1507 * @param symbolID 30 Character {@link String} 1508 * @return {@link Float} 1509 */ 1510 public static float getUnitRatioHeight(String symbolID) 1511 { 1512 int ver = SymbolID.getVersion(symbolID); 1513 int aff = SymbolID.getAffiliation(symbolID); 1514 1515 float rh = 0; 1516 1517 if(ver < SymbolID.Version_2525E) 1518 { 1519 int ss = SymbolID.getSymbolSet(symbolID); 1520 1521 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1522 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1523 { 1524 switch (ss){ 1525 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1526 case SymbolID.SymbolSet_LandUnit: 1527 case SymbolID.SymbolSet_LandInstallation: 1528 case SymbolID.SymbolSet_LandEquipment: 1529 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1530 case SymbolID.SymbolSet_Activities: 1531 case SymbolID.SymbolSet_CyberSpace: 1532 rh = 1.44f; 1533 break; 1534 default: 1535 rh=1.3f; 1536 } 1537 } 1538 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1539 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1540 { 1541 switch (ss){ 1542 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1543 case SymbolID.SymbolSet_LandUnit: 1544 case SymbolID.SymbolSet_LandInstallation: 1545 case SymbolID.SymbolSet_Activities: 1546 case SymbolID.SymbolSet_CyberSpace: 1547 rh = 1f; 1548 break; 1549 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1550 default: 1551 rh=1.2f; 1552 } 1553 } 1554 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1555 { 1556 switch (ss){ 1557 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1558 case SymbolID.SymbolSet_LandUnit: 1559 case SymbolID.SymbolSet_LandInstallation: 1560 case SymbolID.SymbolSet_LandEquipment: 1561 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1562 case SymbolID.SymbolSet_Activities: 1563 case SymbolID.SymbolSet_CyberSpace: 1564 rh = 1.1f; 1565 break; 1566 default: 1567 rh=1.2f; 1568 } 1569 } 1570 else //UNKNOWN 1571 { 1572 switch (ss){ 1573 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1574 case SymbolID.SymbolSet_LandUnit: 1575 case SymbolID.SymbolSet_LandInstallation: 1576 case SymbolID.SymbolSet_LandEquipment: 1577 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1578 case SymbolID.SymbolSet_Activities: 1579 case SymbolID.SymbolSet_CyberSpace: 1580 rh = 1.44f; 1581 break; 1582 default: 1583 rh=1.3f; 1584 } 1585 } 1586 } 1587 else //2525E and up 1588 { 1589 String frameID = SVGLookup.getFrameID(symbolID); 1590 if(frameID.length()==6) 1591 aff = Integer.parseInt(frameID.substring(2,3)); 1592 else //"octagon" 1593 return 1f; 1594 char fs = (frameID.charAt(3)); 1595 1596 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1597 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1598 { 1599 switch (fs){ 1600 case SymbolID.FrameShape_LandUnit: 1601 case SymbolID.FrameShape_LandInstallation: 1602 case SymbolID.FrameShape_LandEquipment: 1603 case SymbolID.FrameShape_SeaSurface: 1604 case SymbolID.FrameShape_Activity_Event: 1605 case SymbolID.FrameShape_Cyberspace: 1606 rh = 1.44f; 1607 break; 1608 default: 1609 rh=1.3f; 1610 } 1611 } 1612 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1613 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1614 { 1615 switch (fs){ 1616 case SymbolID.FrameShape_LandUnit: 1617 case SymbolID.FrameShape_LandInstallation: 1618 case SymbolID.FrameShape_Activity_Event: 1619 case SymbolID.FrameShape_Cyberspace: 1620 rh = 1f; 1621 break; 1622 default: 1623 rh=1.2f; 1624 } 1625 } 1626 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1627 { 1628 switch (fs){ 1629 case SymbolID.FrameShape_LandUnit: 1630 case SymbolID.FrameShape_LandInstallation: 1631 case SymbolID.FrameShape_LandEquipment: 1632 case SymbolID.FrameShape_SeaSurface: 1633 case SymbolID.FrameShape_Activity_Event: 1634 case SymbolID.FrameShape_Cyberspace: 1635 rh = 1.1f; 1636 break; 1637 default: 1638 rh=1.2f; 1639 } 1640 } 1641 else //UNKNOWN 1642 { 1643 switch (fs){ 1644 case SymbolID.FrameShape_LandUnit: 1645 case SymbolID.FrameShape_LandInstallation: 1646 case SymbolID.FrameShape_LandEquipment: 1647 case SymbolID.FrameShape_SeaSurface: 1648 case SymbolID.FrameShape_Activity_Event: 1649 case SymbolID.FrameShape_Cyberspace: 1650 rh = 1.44f; 1651 break; 1652 default: 1653 rh=1.3f; 1654 } 1655 } 1656 1657 1658 } 1659 1660 return rh; 1661 } 1662 1663 /** 1664 * Returns the width ratio for the unit specified by the symbol ID 1665 * Based on Figure 4 in 2525E. 1666 * @param symbolID 30 Character {@link String} 1667 * @return {@link Float} 1668 */ 1669 public static float getUnitRatioWidth(String symbolID) 1670 { 1671 int ver = SymbolID.getVersion(symbolID); 1672 int aff = SymbolID.getAffiliation(symbolID); 1673 1674 float rw = 0; 1675 1676 if(ver < SymbolID.Version_2525E) 1677 { 1678 int ss = SymbolID.getSymbolSet(symbolID); 1679 1680 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1681 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1682 { 1683 switch (ss){ 1684 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1685 case SymbolID.SymbolSet_LandUnit: 1686 case SymbolID.SymbolSet_LandInstallation: 1687 case SymbolID.SymbolSet_LandEquipment: 1688 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1689 case SymbolID.SymbolSet_Activities: 1690 case SymbolID.SymbolSet_CyberSpace: 1691 rw = 1.44f; 1692 break; 1693 default: 1694 rw=1.1f; 1695 } 1696 } 1697 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1698 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1699 { 1700 switch (ss){ 1701 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1702 case SymbolID.SymbolSet_LandUnit: 1703 case SymbolID.SymbolSet_LandInstallation: 1704 case SymbolID.SymbolSet_Activities: 1705 case SymbolID.SymbolSet_CyberSpace: 1706 rw = 1.5f; 1707 break; 1708 case SymbolID.SymbolSet_LandEquipment: 1709 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1710 rw = 1.2f; 1711 break; 1712 default: 1713 rw=1.1f; 1714 } 1715 } 1716 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1717 { 1718 rw = 1.1f; 1719 } 1720 else //UNKNOWN 1721 { 1722 switch (ss){ 1723 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1724 case SymbolID.SymbolSet_LandUnit: 1725 case SymbolID.SymbolSet_LandInstallation: 1726 case SymbolID.SymbolSet_LandEquipment: 1727 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1728 case SymbolID.SymbolSet_Activities: 1729 case SymbolID.SymbolSet_CyberSpace: 1730 rw = 1.44f; 1731 break; 1732 default: 1733 rw=1.5f; 1734 } 1735 } 1736 } 1737 else //2525E and above 1738 { 1739 String frameID = SVGLookup.getFrameID(symbolID); 1740 if(frameID.length()==6) 1741 aff = Integer.parseInt(frameID.substring(2,3)); 1742 else //"octagon" 1743 return 1f; 1744 char fs = (frameID.charAt(3)); 1745 1746 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1747 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1748 { 1749 switch (fs){ 1750 case SymbolID.FrameShape_LandUnit: 1751 case SymbolID.FrameShape_LandInstallation: 1752 case SymbolID.FrameShape_LandEquipment: 1753 case SymbolID.FrameShape_SeaSurface: 1754 case SymbolID.FrameShape_Activity_Event: 1755 case SymbolID.FrameShape_Cyberspace: 1756 rw = 1.44f; 1757 break; 1758 default: 1759 rw=1.1f; 1760 } 1761 } 1762 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1763 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1764 { 1765 switch (fs){ 1766 case SymbolID.FrameShape_LandUnit: 1767 case SymbolID.FrameShape_LandInstallation: 1768 case SymbolID.FrameShape_Activity_Event: 1769 case SymbolID.FrameShape_Cyberspace: 1770 rw = 1.5f; 1771 break; 1772 case SymbolID.FrameShape_LandEquipment: 1773 case SymbolID.FrameShape_SeaSurface: 1774 rw = 1.2f; 1775 break; 1776 default: 1777 rw=1.1f; 1778 } 1779 } 1780 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1781 { 1782 rw = 1.1f; 1783 } 1784 else //UNKNOWN 1785 { 1786 switch (fs){ 1787 case SymbolID.FrameShape_LandUnit: 1788 case SymbolID.FrameShape_LandInstallation: 1789 case SymbolID.FrameShape_LandEquipment: 1790 case SymbolID.FrameShape_SeaSurface: 1791 case SymbolID.FrameShape_Activity_Event: 1792 case SymbolID.FrameShape_Cyberspace: 1793 rw = 1.44f; 1794 break; 1795 default: 1796 rw=1.5f; 1797 } 1798 } 1799 } 1800 1801 return rw; 1802 } 1803 1804 /** 1805 * @param linetype the line type 1806 * @return true if the line is a basic shape 1807 */ 1808 public static boolean isBasicShape(int linetype) { 1809 switch (linetype) { 1810 case TacticalLines.BS_AREA: 1811 case TacticalLines.BS_LINE: 1812 case TacticalLines.BS_CROSS: 1813 case TacticalLines.BS_ELLIPSE: 1814 case TacticalLines.PBS_ELLIPSE: 1815 case TacticalLines.PBS_CIRCLE: 1816 case TacticalLines.PBS_SQUARE: 1817 case TacticalLines.PBS_RECTANGLE: 1818 case TacticalLines.BS_RECTANGLE: 1819 case TacticalLines.BBS_AREA: 1820 case TacticalLines.BBS_LINE: 1821 case TacticalLines.BBS_POINT: 1822 case TacticalLines.BBS_RECTANGLE: 1823 case TacticalLines.BS_BBOX: 1824 case TacticalLines.BS_ROUTE: 1825 case TacticalLines.BS_TRACK: 1826 case TacticalLines.BS_RADARC: 1827 case TacticalLines.BS_CAKE: 1828 case TacticalLines.BS_ORBIT: 1829 case TacticalLines.BS_POLYARC: 1830 return true; 1831 default: 1832 return false; 1833 } 1834 } 1835}