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