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 * @deprecated function will be removed 345 */ 346 public static String getBasicSymbolID2525C(String strSymbolID) 347 { 348 if(strSymbolID != null && strSymbolID.length() == 15) 349 { 350 StringBuilder sb = new StringBuilder(); 351 char scheme = strSymbolID.charAt(0); 352 if (scheme == 'G') 353 { 354 sb.append(strSymbolID.charAt(0)); 355 sb.append("*"); 356 sb.append(strSymbolID.charAt(2)); 357 sb.append("*"); 358 sb.append(strSymbolID.substring(4, 10)); 359 sb.append("****X"); 360 } 361 else if (scheme != 'W' && scheme != 'B' && scheme != 'P') 362 { 363 sb.append(strSymbolID.charAt(0)); 364 sb.append("*"); 365 sb.append(strSymbolID.charAt(2)); 366 sb.append("*"); 367 sb.append(strSymbolID.substring(4, 10)); 368 sb.append("*****"); 369 } 370 else 371 { 372 return strSymbolID; 373 } 374 return sb.toString(); 375 } 376 return strSymbolID; 377 } 378 379 /** 380 * Attempts to resolve a bad symbol ID into a value that can be found in {@link MSLookup}. 381 * If it fails, it will return the symbol code for a invalid symbol which is displayed as 382 * an inverted question mark (110098000010000000000000000000) 383 * @param symbolID 30 character {@link String} 384 * @return 30 character {@link String} representing the resolved symbol ID. 385 */ 386 public static String reconcileSymbolID(String symbolID) 387 { 388 389 String newID = ""; 390 try { 391 392 393 int v = SymbolID.getVersion(symbolID); 394 if (v < SymbolID.Version_2525E) 395 newID = String.valueOf(SymbolID.Version_2525Dch1); 396 else 397 newID = String.valueOf(SymbolID.Version_2525E); 398 int c = SymbolID.getContext(symbolID); 399 if (c > 2) 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 invalid symbol since we couldn't find it in the lookup 455 newID = SymbolID.setSymbolSet(newID, 98); 456 newID += 100000; 457 } 458 else 459 newID += String.format("%06d",ec);//we found it so add the entity code 460 461 //newID += SymbolID.getMod1ID(symbolID);//just add, won't get used if value bad 462 //newID += SymbolID.getMod2ID(symbolID);//just add, won't get used if value bad 463 newID += symbolID.substring(16);//just add, won't get used if value bad 464 } 465 catch(Exception exc) 466 { 467 newID = "110098000010000000000000000000";//invalid symbol 468 } 469 470 return newID; 471 } 472 473 /** 474 * Gets line color used if no line color has been set. The color is specified based on the affiliation of 475 * the symbol and whether it is a unit or not. 476 * @param symbolID 30 character {@link String} 477 * @return {@link Color} 478 */ 479 public static Color getLineColorOfAffiliation(String symbolID) 480 { 481 Color retColor = null; 482 483 int symbolSet = SymbolID.getSymbolSet(symbolID); 484 int set = SymbolID.getSymbolSet(symbolID); 485 int affiliation = SymbolID.getAffiliation(symbolID); 486 int symStd = SymbolID.getVersion(symbolID); 487 int entityCode = SymbolID.getEntityCode(symbolID); 488 489 try 490 { 491 // We can't get the line color if there is no symbol id, since that also means there is no affiliation 492 if((symbolID == null) || (symbolID.equals(""))) 493 { 494 return retColor; 495 } 496 497 if(symbolSet == SymbolID.SymbolSet_ControlMeasure) 498 { 499 int entity = SymbolID.getEntity(symbolID); 500 int entityType = SymbolID.getEntityType(symbolID); 501 int entitySubtype = SymbolID.getEntitySubtype(symbolID); 502 503 if(SymbolUtilities.isGreenProtectionGraphic(entity, entityType, entitySubtype)) 504 { 505 //Obstacles/Protection Graphics, some are green obstacles and we need to 506 //check for those. 507 retColor = AffiliationColors.ObstacleGreen; 508 } 509 //just do color by affiliation if no other color has been set yet. 510 if(retColor == null) 511 { 512 switch (affiliation) { 513 case SymbolID.StandardIdentity_Affiliation_Friend: 514 case SymbolID.StandardIdentity_Affiliation_AssumedFriend: 515 retColor = AffiliationColors.FriendlyGraphicLineColor;//Color.BLACK;//0x000000; // Black 516 break; 517 case SymbolID.StandardIdentity_Affiliation_Hostile_Faker: 518 retColor = AffiliationColors.HostileGraphicLineColor;//Color.RED;//0xff0000; // Red 519 break; 520 case SymbolID.StandardIdentity_Affiliation_Suspect_Joker: 521 if(symStd >= SymbolID.Version_2525E) 522 retColor = AffiliationColors.SuspectGraphicLineColor;//255,188,1 523 else 524 retColor = AffiliationColors.HostileGraphicLineColor;//Color.RED;//0xff0000; // Red 525 break; 526 case SymbolID.StandardIdentity_Affiliation_Neutral: 527 retColor = AffiliationColors.NeutralGraphicLineColor;//Color.GREEN;//0x00ff00; // Green 528 break; 529 default: 530 retColor = AffiliationColors.UnknownGraphicLineColor;//Color.YELLOW;//0xffff00; // Yellow 531 break; 532 } 533 } 534 } 535 else if (set >= 45 && set <= 47)//METOC 536 { 537 // If not black then color will be set in clsMETOC.SetMeTOCProperties() 538 retColor = Color.BLACK; 539 } 540 else if (set == SymbolID.SymbolSet_MineWarfare && (RendererSettings.getInstance().getSeaMineRenderMethod() == RendererSettings.SeaMineRenderMethod_MEDAL)) 541 { 542 if(!(entityCode == 110600 || entityCode == 110700)) 543 { 544 switch(affiliation) 545 { 546 case SymbolID.StandardIdentity_Affiliation_Friend: 547 case SymbolID.StandardIdentity_Affiliation_AssumedFriend: 548 retColor = AffiliationColors.FriendlyUnitFillColor;//0x00ffff; // Cyan 549 break; 550 case SymbolID.StandardIdentity_Affiliation_Hostile_Faker: 551 retColor = AffiliationColors.HostileGraphicLineColor;//Color.RED;//0xff0000; // Red 552 break; 553 case SymbolID.StandardIdentity_Affiliation_Suspect_Joker: 554 if(symStd >= SymbolID.Version_2525E) 555 retColor = AffiliationColors.SuspectGraphicLineColor;//255,188,1 556 else 557 retColor = AffiliationColors.HostileGraphicLineColor;//Color.RED;//0xff0000; // Red 558 break; 559 case SymbolID.StandardIdentity_Affiliation_Neutral: 560 retColor = AffiliationColors.NeutralUnitFillColor;//0x7fff00; // Light Green 561 break; 562 default://unknown, pending, everything else 563 retColor = AffiliationColors.UnknownUnitFillColor;//new Color(255,250, 205); //0xfffacd; // LemonChiffon 255 250 205 564 break; 565 } 566 } 567 else 568 { 569 retColor = Color.BLACK; 570 } 571 } 572 else//everything else 573 { 574 //stopped doing check because all warfighting 575 //should have black for line color. 576 retColor = Color.BLACK; 577 } 578 } 579 catch(Exception e) 580 { 581 // Log Error 582 ErrorLogger.LogException("SymbolUtilities", "getLineColorOfAffiliation", e); 583 //throw e; 584 } // End catch 585 return retColor; 586 } // End get LineColorOfAffiliation 587 588 /** 589 * For Control Measures, returns the default color for a symbol when it differs from the 590 * affiliation line color. If there is no default color, returns the value from {@link #getLineColorOfAffiliation} 591 * @param symbolID 30 Character {@link String} 592 * @return {@link Color} 593 */ 594 public static Color getDefaultLineColor(String symbolID) { 595 try { 596 if (symbolID == null || symbolID.equals("")) { 597 return null; 598 } 599 600 int symbolSet = SymbolID.getSymbolSet(symbolID); 601 int entityCode = SymbolID.getEntityCode(symbolID); 602 int version = SymbolID.getVersion(symbolID); 603 604 if (symbolSet == SymbolID.SymbolSet_ControlMeasure) { 605 if (entityCode == 200600) { 606 return Color.WHITE; 607 } else if (entityCode == 200700) { 608 return new Color(51, 136, 136); 609 } else if (entityCode == 200101) { 610 return new Color(255, 155, 0); 611 } else if (entityCode == 200201 || entityCode == 200202) { 612 return new Color(85, 119, 136); 613 } else if (version >= SymbolID.Version_2525E && 614 (entityCode == 132100 || //key terrain 615 entityCode == 282001 || //Tower, Low 616 entityCode == 282002 || //Tower, High 617 entityCode == 282003)) { // Overhead Wire 618 return new Color(128, 0, 128);//purple 619 } 620 } 621 } catch (Exception e) { 622 ErrorLogger.LogException("SymbolUtilities", "getDefaultLineColor", e); 623 } 624 return getLineColorOfAffiliation(symbolID); 625 } 626 627 /** 628 * Checks if a symbol should be filled by default 629 * 630 * @param strSymbolID The 20 digit representation of the 2525D symbol 631 * @return true if there is a default fill 632 */ 633 public static boolean hasDefaultFill(String strSymbolID) { 634 int ec = SymbolID.getEntityCode(strSymbolID); 635 switch (ec) { 636 case 200101: 637 case 200201: 638 case 200202: 639 case 200600: 640 case 200700: 641 return true; 642 default: 643 return !SymbolUtilities.isTacticalGraphic(strSymbolID); 644 } 645 } 646 647 /** 648 * Determines if the symbol is a tactical graphic 649 * 650 * @param strSymbolID 30 Character {@link String} 651 * @return true if symbol set is 25 (control measure), or is a weather graphic 652 */ 653 public static boolean isTacticalGraphic(String strSymbolID) { 654 try { 655 int ss = SymbolID.getSymbolSet(strSymbolID); 656 657 if(ss == SymbolID.SymbolSet_ControlMeasure || isWeather(strSymbolID)) { 658 return true; 659 } 660 } 661 catch (Exception e) { 662 ErrorLogger.LogException("SymbolUtilities", "getFillColorOfAffiliation", e); 663 } 664 return false; 665 } 666 667 /** 668 * Determines if the Symbol can be rendered as a multipoint graphic and not just as an icon 669 * @param symbolID 30 Character {@link String} 670 * @return {@link Boolean} 671 */ 672 public static boolean isMultiPoint(String symbolID) 673 { 674 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 675 if (msi == null) { 676 return false; 677 } 678 int drawRule = msi.getDrawRule(); 679 int ss = msi.getSymbolSet(); 680 if(ss != SymbolID.SymbolSet_ControlMeasure && ss != SymbolID.SymbolSet_Oceanographic && ss != SymbolID.SymbolSet_Atmospheric && ss != SymbolID.SymbolSet_MeteorologicalSpace) 681 { 682 return false; 683 } 684 else if (ss == SymbolID.SymbolSet_ControlMeasure) 685 { 686 if(msi.getMaxPointCount() > 1) 687 return true; 688 else if((drawRule < DrawRules.POINT1 || drawRule > DrawRules.POINT16 || drawRule == DrawRules.POINT12) && 689 drawRule != DrawRules.DONOTDRAW && drawRule != DrawRules.AREA22) 690 { 691 return true; 692 } 693 else 694 return false; 695 } 696 else if(ss == SymbolID.SymbolSet_Oceanographic || ss == SymbolID.SymbolSet_Atmospheric || ss == SymbolID.SymbolSet_MeteorologicalSpace) 697 { 698 if(msi.getMaxPointCount() > 1) 699 return true; 700 else 701 return false; 702 } 703 return false; 704 } 705 706 public static boolean isActionPoint(String symbolID) 707 { 708 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 709 if(msi.getDrawRule()==DrawRules.POINT1) 710 { 711 int ec = SymbolID.getEntityCode(symbolID); 712 if(ec != 131300 && ec != 131301 && ec != 182600 && ec != 212800) 713 return true; 714 } 715 return false; 716 } 717 718 /** 719 * Control Measures and Tactical Graphics that have labels but not with the Action Point layout 720 * @param strSymbolID 30 Character {@link String} 721 * @return {@link Boolean} 722 + @deprecated see {@link #isSPWithSpecialModifierLayout(String)} 723 */ 724 public static boolean isTGSPWithSpecialModifierLayout(String strSymbolID) 725 { 726 try 727 { 728 int ss = SymbolID.getSymbolSet(strSymbolID); 729 int entityCode = SymbolID.getEntityCode(strSymbolID); 730 if(ss == SymbolID.SymbolSet_ControlMeasure) //|| isWeather(strSymbolID)) { 731 { 732 if(SymbolUtilities.isCBRNEvent(strSymbolID)) 733 return true; 734 735 if(SymbolUtilities.isSonobuoy(strSymbolID)) 736 return true; 737 738 switch (entityCode) 739 { 740 case 130500: //contact point 741 case 130700: //decision point 742 case 212800: //harbor 743 case 210300: //Defended Asset 744 case 210600: //Air Detonation 745 case 131300: //point of interest 746 case 131800: //waypoint 747 case 240900: //fire support station 748 case 180100: //Air Control point 749 case 180200: //Communications Check point 750 case 160300: //T (target reference point) 751 case 240601: //ap,ap1,x,h (Point/Single Target) 752 case 240602: //ap (nuclear target) 753 case 270701: //static depiction 754 case 282001: //tower, low 755 case 282002: //tower, high 756 return true; 757 default: 758 return false; 759 } 760 } 761 else if(ss == SymbolID.SymbolSet_Atmospheric) 762 { 763 switch (entityCode) 764 { 765 case 162300: //Freezing Level 766 case 162200: //tropopause Level 767 case 110102: //tropopause Low 768 case 110202: //tropopause High 769 return true; 770 default: 771 return false; 772 } 773 } 774 } 775 catch (Exception e) { 776 ErrorLogger.LogException("SymbolUtilities", "getFillColorOfAffiliation", e); 777 } 778 return false; 779 } 780 781 /** 782 * Returns the fill color for the symbol based on its affiliation 783 * @param symbolID 30 Character {@link String} 784 * @return {@link Color} 785 */ 786 public static Color getFillColorOfAffiliation(String symbolID) 787 { 788 Color retColor = null; 789 int entityCode = SymbolID.getEntityCode(symbolID); 790 int entity = SymbolID.getEntity(symbolID); 791 int entityType = SymbolID.getEntityType(symbolID); 792 int entitySubtype = SymbolID.getEntitySubtype(symbolID); 793 794 int affiliation = SymbolID.getAffiliation(symbolID); 795 796 try 797 { 798 // We can't get the fill color if there is no symbol id, since that also means there is no affiliation 799 if ((symbolID == null) || (symbolID.equals(""))) { 800 return retColor; 801 } 802 if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure) { 803 switch (entityCode) { 804 case 200101: 805 retColor = new Color(255, 155, 0, (int) (.25 * 255)); 806 break; 807 case 200201: 808 case 200202: 809 case 200600: 810 retColor = new Color(85, 119, 136, (int) (.25 * 255)); 811 break; 812 case 200700: 813 retColor = new Color(51, 136, 136, (int) (.25 * 255)); 814 break; 815 } 816 } 817 else if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_MineWarfare && 818 (RendererSettings.getInstance().getSeaMineRenderMethod() == RendererSettings.SeaMineRenderMethod_MEDAL) && 819 (!(entityCode == 110600 || entityCode == 110700))) 820 { 821 retColor = new Color(0,0,0,0);//transparent 822 } 823 //just do color by affiliation if no other color has been set yet 824 if (retColor == null) { 825 switch(affiliation) 826 { 827 case SymbolID.StandardIdentity_Affiliation_Friend: 828 case SymbolID.StandardIdentity_Affiliation_AssumedFriend: 829 retColor = AffiliationColors.FriendlyUnitFillColor;//0x00ffff; // Cyan 830 break; 831 case SymbolID.StandardIdentity_Affiliation_Hostile_Faker: 832 retColor = AffiliationColors.HostileUnitFillColor;//0xfa8072; // Salmon 833 break; 834 case SymbolID.StandardIdentity_Affiliation_Suspect_Joker: 835 if(SymbolID.getVersion(symbolID) >= SymbolID.Version_2525E) 836 retColor = AffiliationColors.SuspectGraphicFillColor;//255,229,153 837 else 838 retColor = AffiliationColors.HostileGraphicFillColor;//Color.RED;//0xff0000; // Red 839 break; 840 case SymbolID.StandardIdentity_Affiliation_Neutral: 841 retColor = AffiliationColors.NeutralUnitFillColor;//0x7fff00; // Light Green 842 break; 843 default://unknown, pending, everything else 844 retColor = AffiliationColors.UnknownUnitFillColor;//new Color(255,250, 205); //0xfffacd; // LemonChiffon 255 250 205 845 break; 846 } 847 } 848 } // End try 849 catch (Exception e) 850 { 851 // Log Error 852 ErrorLogger.LogException("SymbolUtilities", "getFillColorOfAffiliation", e); 853 //throw e; 854 } // End catch 855 856 return retColor; 857 } // End FillColorOfAffiliation 858 859 /** 860 * 861 * @param symbolID 30 Character {@link String} 862 * @param modifier {@link Modifiers} 863 * @return {@link Boolean} 864 * @deprecated see {@link #hasModifier(String, String)} 865 */ 866 public static Boolean canSymbolHaveModifier(String symbolID, String modifier) 867 { 868 return hasModifier(symbolID, modifier); 869 } 870 871 /** 872 * Checks if the Symbol Code has FDI set. 873 * Does not check if the symbol can have an FDI. 874 * @param symbolID 30 Character {@link String} 875 * @return {@link Boolean} 876 */ 877 public static Boolean hasFDI(String symbolID) 878 { 879 int hqtfd = SymbolID.getHQTFD(symbolID); 880 if(hqtfd == SymbolID.HQTFD_FeintDummy 881 || hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce 882 || hqtfd == SymbolID.HQTFD_FeintDummy_Headquarters 883 || hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce_Headquarters) 884 { 885 return true; 886 } 887 else 888 return false; 889 } 890 891 /* 892 * For Renderer Use Only 893 * Assumes a fresh SVG String from the SVGLookup with its default values 894 * @param symbolID 895 * @param svg 896 * @param strokeColor 897 * @param fillColor 898 * @return 899 */ 900 /*public static String setSVGFrameColors(String symbolID, String svg, Color strokeColor, Color fillColor) 901 { 902 String hexStrokeColor = null; 903 String hexFillColor = null; 904 905 if(strokeColor != null) 906 hexStrokeColor = colorToHexString(strokeColor,false); 907 if(fillColor != null) 908 hexFillColor = colorToHexString(fillColor,false); 909 return setSVGFrameColors(symbolID, svg, hexStrokeColor,hexFillColor); 910 }//*/ 911 912 /*** 913 * Returns true if graphic is protection graphic (obstacles which render green) 914 * Assumes control measure symbol code where SS == 25 915 * @param entity {@link Integer} 916 * @param entityType {@link Integer} 917 * @param entitySubtype {@link Integer} 918 * @return {@link Boolean} 919 */ 920 public static boolean isGreenProtectionGraphic(int entity, int entityType, int entitySubtype) 921 { 922 if(entity >= 27 && entity <= 29)//Protection Areas, Points and Lines 923 { 924 if(entity == 27) 925 { 926 if(entityType > 0 && entityType <= 5) 927 return true; 928 else if(entityType == 7 || entityType == 8 || entityType == 10 || entityType == 12) 929 { 930 return true; 931 } 932 else 933 return false; 934 } 935 else if(entity == 28) 936 { 937 if(entityType > 0 && entityType <= 7) 938 return true; 939 if(entityType == 19) 940 return true; 941 else 942 return false; 943 } 944 else if(entity == 29) 945 { 946 if(entityType >= 01 && entityType <= 05) 947 return true; 948 else 949 return false; 950 } 951 } 952 else 953 { 954 return false; 955 } 956 return false; 957 } 958 959 /** 960 * Returns true if graphic is protection graphic (obstacles which render green) 961 * @param symbolID 30 Character {@link String} 962 * @return {@link Boolean} 963 */ 964 public static boolean isGreenProtectionGraphic(String symbolID){ 965 if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure) { 966 return SymbolUtilities.isGreenProtectionGraphic(SymbolID.getEntity(symbolID), SymbolID.getEntityType(symbolID), SymbolID.getEntitySubtype(symbolID)); 967 } else { 968 return false; 969 } 970 } 971 972 /** 973 * Returns true if Symbol ID represents a chemical, biological, radiological or nuclear incident. 974 * @param symbolID 30 Character {@link String} 975 * @return {@link Boolean} 976 */ 977 public static boolean isCBRNEvent(String symbolID) 978 { 979 int ss = SymbolID.getSymbolSet(symbolID); 980 int ec = SymbolID.getEntityCode(symbolID); 981 982 if(ss == SymbolID.SymbolSet_ControlMeasure) { 983 switch (ec) 984 { 985 case 281300: 986 case 281400: 987 case 281500: 988 case 281600: 989 case 281700: 990 return true; 991 default: 992 } 993 } 994 return false; 995 } 996 997 /** 998 * Returns true if Symbol ID represents a Sonobuoy. 999 * @param symbolID 30 Character {@link String} 1000 * @return {@link Boolean} 1001 */ 1002 public static boolean isSonobuoy(String symbolID) 1003 { 1004 int ss = SymbolID.getSymbolSet(symbolID); 1005 int e = SymbolID.getEntity(symbolID); 1006 int et = SymbolID.getEntityType(symbolID); 1007 if(ss == 25 && e == 21 && et == 35) 1008 return true; 1009 else 1010 return false; 1011 } 1012 1013 /** 1014 * Obstacles are generally required to have a green line color 1015 * @param symbolID 30 Character {@link String} 1016 * @return {@link Boolean} 1017 * @deprecated see {@link #isGreenProtectionGraphic(String)} 1018 */ 1019 public static boolean isObstacle(String symbolID) 1020 { 1021 1022 if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure && 1023 SymbolID.getEntity(symbolID) == 27) 1024 { 1025 return true; 1026 } 1027 else 1028 return false; 1029 } 1030 1031 /** 1032 * Return true if symbol is from the Atmospheric, Oceanographic or Meteorological Space Symbol Sets. 1033 * @param symbolID 30 Character {@link String} 1034 * @return {@link Boolean} 1035 */ 1036 public static boolean isWeather(String symbolID) 1037 { 1038 int ss = SymbolID.getSymbolSet(symbolID); 1039 if(ss >= SymbolID.SymbolSet_Atmospheric && ss <= SymbolID.SymbolSet_MeteorologicalSpace) 1040 return true; 1041 else 1042 return false; 1043 } 1044 1045 /** 1046 * Returns true if the symbol has the HQ staff indicated by the symbol ID 1047 * @param symbolID 30 Character {@link String} 1048 * @return {@link Boolean} 1049 */ 1050 public static boolean isHQ(String symbolID) 1051 { 1052 int hq = SymbolID.getHQTFD(symbolID); 1053 if(SymbolUtilities.hasModifier(symbolID, Modifiers.S_HQ_STAFF_INDICATOR) && 1054 (hq == SymbolID.HQTFD_FeintDummy_Headquarters || 1055 hq == SymbolID.HQTFD_Headquarters || 1056 hq == SymbolID.HQTFD_FeintDummy_TaskForce_Headquarters || 1057 hq == SymbolID.HQTFD_TaskForce_Headquarters)) 1058 return true; 1059 else 1060 return false; 1061 } 1062 1063 /** 1064 * Checks if this is a single point control measure or meteorological graphic with a unique layout. 1065 * Basically anything that's not an action point style graphic with modifiers 1066 * @param symbolID 30 Character {@link String} 1067 * @return {@link Boolean} 1068 */ 1069 public static boolean isSPWithSpecialModifierLayout(String symbolID) 1070 { 1071 int ss = SymbolID.getSymbolSet(symbolID); 1072 int ec = SymbolID.getEntityCode(symbolID); 1073 1074 if(ss == SymbolID.SymbolSet_ControlMeasure) 1075 { 1076 switch(ec) 1077 { 1078 case 130500: //Control Point 1079 case 130700: //Decision Point 1080 case 131300: //Point of Interest 1081 case 131800: //Waypoint 1082 case 131900: //Airfield (AEGIS Only) 1083 case 132000: //Target Handover 1084 case 132100: //Key Terrain 1085 case 160300: //Target Point Reference 1086 case 180100: //Air Control Point 1087 case 180200: //Communications Check Point 1088 case 180600: //TACAN 1089 case 210300: //Defended Asset 1090 case 210600: //Air Detonation 1091 case 210800: //Impact Point 1092 case 211000: //Launched Torpedo 1093 case 212800: //Harbor 1094 case 213500: //Sonobuoy 1095 case 213501: //Ambient Noise Sonobuoy 1096 case 213502: //Air Transportable Communication (ATAC) (Sonobuoy) 1097 case 213503: //Barra (Sonobuoy) 1098 case 213504: 1099 case 213505: 1100 case 213506: 1101 case 213507: 1102 case 213508: 1103 case 213509: 1104 case 213510: 1105 case 213511: 1106 case 213512: 1107 case 213513: 1108 case 213514: 1109 case 213515: 1110 case 214900: //General Sea Subsurface Station 1111 case 215600: //General Sea Station 1112 case 217000: //Shore Control Station 1113 case 240601: //Point or Single Target 1114 case 240602: //Nuclear Target 1115 case 240900: //Fire Support Station 1116 case 250600: //Known Point 1117 case 270701: //Static Depiction 1118 case 282001: //Tower, Low 1119 case 282002: //Tower, High 1120 case 281300: //Chemical Event 1121 case 281400: //Biological Event 1122 case 281500: //Nuclear Event 1123 case 281600: //Nuclear Fallout Producing Event 1124 case 281700: //Radiological Event 1125 return true; 1126 default: 1127 return false; 1128 } 1129 } 1130 else if(ss == SymbolID.SymbolSet_Atmospheric) 1131 { 1132 switch(ec) 1133 { 1134 case 162300: //Freezing Level 1135 case 162200: //tropopause Level 1136 case 110102: //tropopause low 1137 case 110202: //tropopause high 1138 return true; 1139 default: 1140 return false; 1141 } 1142 } 1143 return false; 1144 } 1145 1146 /** 1147 * Gets the anchor point for single point Control Measure as the anchor point isn't always they center of the symbol. 1148 * @param symbolID 30 Character {@link String} 1149 * @param bounds {@link RectF} representing the bound of the core symbol in the image. 1150 * @return {@link Point} representing the point in the image that is the anchor point of the symbol. 1151 */ 1152 public static Point getCMSymbolAnchorPoint(String symbolID, RectF bounds) { 1153 float centerX = bounds.width() / 2f; 1154 float centerY = bounds.height() / 2f; 1155 1156 int ss = SymbolID.getSymbolSet(symbolID); 1157 int ec = SymbolID.getEntityCode(symbolID); 1158 int drawRule = 0; 1159 1160 //center/anchor point is always half width and half height except for control measures 1161 //and meteorological 1162 if (ss == SymbolID.SymbolSet_ControlMeasure) { 1163 drawRule = MSLookup.getInstance().getMSLInfo(symbolID).getDrawRule(); 1164 switch (drawRule)//here we check the 'Y' value for the anchor point 1165 { 1166 case DrawRules.POINT1://action points 1301 //bottom center 1167 case DrawRules.POINT5://entry point 2105 1168 case DrawRules.POINT6://ground zero 2107 1169 case DrawRules.POINT7://missile detection point 2111 1170 centerY = bounds.height(); 1171 break; 1172 case DrawRules.POINT4://drop point 2104 //almost bottom and center 1173 centerY = (bounds.height() * 0.80f); 1174 break; 1175 case DrawRules.POINT10://Sonobuoy 2135 //center of circle which isn't center of symbol 1176 centerY = (bounds.height() * 0.75f); 1177 break; 1178 case DrawRules.POINT13://booby trap 2807 //almost bottom and center 1179 centerY = (bounds.height() * 0.74f); 1180 break; 1181 case DrawRules.POINT15://Marine Life 2189 //center left 1182 centerX = 0; 1183 break; 1184 case DrawRules.POINT16://Tower 282001 //circle at base of tower 1185 centerY = (bounds.height() * 0.87f); 1186 break; 1187 case DrawRules.POINT2://Several different symbols 1188 if (ec == 280500)//Wide Area Antitank Mine 1189 centerY = (bounds.height() * 0.35f); 1190 else if (ec == 280400)//Antitank Mine w/ Anti-handling Device 1191 centerY = (bounds.height() * 0.33f); 1192 else if (ec == 280200)//Antipersonnel Mine 1193 centerY = (bounds.height() * 0.7f); 1194 else if (ec == 280201)//Antipersonnel Mine with Directional Effects 1195 centerY = (bounds.height() * 0.65f); 1196 else if (ec == 219000)//Sea Anomaly 1197 centerY = (bounds.height() * 0.7f); 1198 else if (ec == 212500)//Electromagnetic - Magnetic Anomaly Detections (MAD) 1199 centerY = (bounds.height() * 0.4f); 1200 break; 1201 default: 1202 } 1203 1204 switch (ec) 1205 //have to adjust center X as some graphics have integrated text outside the symbol 1206 { 1207 case 180400: //Pickup Point (PUP) 1208 centerX = bounds.width() * 0.3341f; 1209 break; 1210 case 240900: //Fire Support Station 1211 centerX = bounds.width() * 0.38f; 1212 break; 1213 case 280201: //Antipersonnel Mine with Directional Effects 1214 centerX = bounds.width() * 0.43f; 1215 break; 1216 } 1217 } 1218 1219 return new Point(Math.round(centerX), Math.round(centerY)); 1220 } 1221 1222 /** 1223 * Returns true if the symbol is an installation 1224 * @param symbolID 30 Character {@link String} 1225 * @return {@link Boolean} 1226 */ 1227 public static Boolean isInstallation(String symbolID) 1228 { 1229 int ss = SymbolID.getSymbolSet(symbolID); 1230 int entity = SymbolID.getEntity(symbolID); 1231 if(ss == SymbolID.SymbolSet_LandInstallation && entity == 11) 1232 return true; 1233 else 1234 return false; 1235 } 1236 1237 /** 1238 * Returns true if the symbol is from an air based symbol set 1239 * @param symbolID 30 Character {@link String} 1240 * @return {@link Boolean} 1241 */ 1242 public static Boolean isAir(String symbolID) 1243 { 1244 int ss = SymbolID.getSymbolSet(symbolID); 1245 int entity = SymbolID.getEntity(symbolID); 1246 if(ss == SymbolID.SymbolSet_Air || 1247 ss == SymbolID.SymbolSet_AirMissile || 1248 ss == SymbolID.SymbolSet_SignalsIntelligence_Air) 1249 return true; 1250 else 1251 return false; 1252 } 1253 1254 /** 1255 * Returns true if the symbol is from a space based symbol set 1256 * @param symbolID 30 Character {@link String} 1257 * @return {@link Boolean} 1258 */ 1259 public static Boolean isSpace(String symbolID) 1260 { 1261 int ss = SymbolID.getSymbolSet(symbolID); 1262 int entity = SymbolID.getEntity(symbolID); 1263 if(ss == SymbolID.SymbolSet_Space || 1264 ss == SymbolID.SymbolSet_SpaceMissile || 1265 ss == SymbolID.SymbolSet_SignalsIntelligence_Space) 1266 return true; 1267 else 1268 return false; 1269 } 1270 1271 /** 1272 * Returns true if the symbol is from a land based symbol set 1273 * @param symbolID 30 Character {@link String} 1274 * @return {@link Boolean} 1275 */ 1276 public static Boolean isLand(String symbolID) 1277 { 1278 int ss = SymbolID.getSymbolSet(symbolID); 1279 int entity = SymbolID.getEntity(symbolID); 1280 if(ss == SymbolID.SymbolSet_LandUnit || 1281 ss == SymbolID.SymbolSet_LandCivilianUnit_Organization || 1282 ss == SymbolID.SymbolSet_LandEquipment || 1283 ss == SymbolID.SymbolSet_LandInstallation || 1284 ss == SymbolID.SymbolSet_SignalsIntelligence_Land) 1285 return true; 1286 else 1287 return false; 1288 } 1289 1290 /** 1291 * Returns true if the symbol ID has the task for indicator 1292 * @param symbolID 30 Character {@link String} 1293 * @return {@link Boolean} 1294 */ 1295 public static Boolean isTaskForce(String symbolID) 1296 { 1297 int hqtfd = SymbolID.getHQTFD(symbolID); 1298 if((hqtfd == SymbolID.HQTFD_TaskForce || 1299 hqtfd == SymbolID.HQTFD_TaskForce_Headquarters || 1300 hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce || 1301 hqtfd == SymbolID.HQTFD_FeintDummy_TaskForce_Headquarters) && 1302 SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.B_ECHELON)) 1303 return true; 1304 else 1305 return false; 1306 } 1307 1308 /** 1309 * Returns true if the symbol ID indicates the context is Reality 1310 * @param symbolID 30 Character {@link String} 1311 * @return {@link Boolean} 1312 */ 1313 public static Boolean isReality(String symbolID) 1314 { 1315 int c = SymbolID.getContext(symbolID); 1316 if(c == SymbolID.StandardIdentity_Context_Reality || 1317 c == 3 || c == 4) 1318 return true; 1319 else 1320 return false; 1321 } 1322 1323 /** 1324 * Returns true if the symbol ID indicates the context is Exercise 1325 * @param symbolID 30 Character {@link String} 1326 * @return {@link Boolean} 1327 */ 1328 public static Boolean isExercise(String symbolID) 1329 { 1330 int c = SymbolID.getContext(symbolID); 1331 if(c == SymbolID.StandardIdentity_Context_Exercise || 1332 c == 5 || c == 6) 1333 return true; 1334 else 1335 return false; 1336 } 1337 1338 /** 1339 * Returns true if the symbol ID indicates the context is Simulation 1340 * @param symbolID 30 Character {@link String} 1341 * @return {@link Boolean} 1342 */ 1343 public static Boolean isSimulation(String symbolID) 1344 { 1345 int c = SymbolID.getContext(symbolID); 1346 if(c == SymbolID.StandardIdentity_Context_Simulation || 1347 c == 7 || c == 8) 1348 return true; 1349 else 1350 return false; 1351 } 1352 1353 1354 /** 1355 * Reads the Symbol ID string and returns the text that represents the echelon 1356 * code. 1357 * @param echelon {@link Integer} from positions 9-10 in the symbol ID 1358 * See {@link SymbolID#getAmplifierDescriptor(String)} 1359 * @return {@link String} (23 (Army) would be "XXXX") 1360 */ 1361 public static String getEchelonText(int echelon) 1362 { 1363 char[] dots = new char[3]; 1364 dots[0] = (char)8226; 1365 dots[1] = (char)8226; 1366 dots[2] = (char)8226; 1367 String dot = new String(dots); 1368 String text = null; 1369 if(echelon == SymbolID.Echelon_Team_Crew) 1370 { 1371 text = (char) 216 + ""; 1372 } 1373 else if(echelon == SymbolID.Echelon_Squad) 1374 { 1375 text = dot.substring(0, 1); 1376 } 1377 else if(echelon == SymbolID.Echelon_Section) 1378 { 1379 text = dot.substring(0, 2); 1380 } 1381 else if(echelon == SymbolID.Echelon_Platoon_Detachment) 1382 { 1383 text = dot; 1384 } 1385 else if(echelon == SymbolID.Echelon_Company_Battery_Troop) 1386 { 1387 text = "I"; 1388 } 1389 else if(echelon == SymbolID.Echelon_Battalion_Squadron) 1390 { 1391 text = "II"; 1392 } 1393 else if(echelon == SymbolID.Echelon_Regiment_Group) 1394 { 1395 text = "III"; 1396 } 1397 else if(echelon == SymbolID.Echelon_Brigade) 1398 { 1399 text = "X"; 1400 } 1401 else if(echelon == SymbolID.Echelon_Division) 1402 { 1403 text = "XX"; 1404 } 1405 else if(echelon == SymbolID.Echelon_Corps_MEF) 1406 { 1407 text = "XXX"; 1408 } 1409 else if(echelon == SymbolID.Echelon_Army) 1410 { 1411 text = "XXXX"; 1412 } 1413 else if(echelon == SymbolID.Echelon_ArmyGroup_Front) 1414 { 1415 text = "XXXXX"; 1416 } 1417 else if(echelon == SymbolID.Echelon_Region_Theater) 1418 { 1419 text = "XXXXXX"; 1420 } 1421 else if(echelon == SymbolID.Echelon_Region_Command) 1422 { 1423 text = "++"; 1424 } 1425 return text; 1426 } 1427 1428 /** 1429 * Returns the Standard Identity Modifier based on the Symbol ID 1430 * @param symbolID 30 Character {@link String} 1431 * @return {@link String} 1432 */ 1433 public static String getStandardIdentityModifier(String symbolID) 1434 { 1435 String textChar = null; 1436 int si = SymbolID.getStandardIdentity(symbolID); 1437 int context = SymbolID.getContext(symbolID); 1438 int affiliation = SymbolID.getAffiliation(symbolID); 1439 1440 if(context == SymbolID.StandardIdentity_Context_Simulation)//Simulation 1441 textChar = "S"; 1442 else if(context == SymbolID.StandardIdentity_Context_Exercise) 1443 { 1444 if(affiliation == SymbolID.StandardIdentity_Affiliation_Suspect_Joker)//exercise Joker 1445 textChar = "J"; 1446 else if(affiliation == SymbolID.StandardIdentity_Affiliation_Hostile_Faker)//exercise faker 1447 textChar = "K"; 1448 else if(context == SymbolID.StandardIdentity_Context_Exercise)//exercise 1449 textChar = "X"; 1450 } 1451 1452 return textChar; 1453 } 1454 1455 /** 1456 * 1457 * @param symbolID 1458 * @return 1459 */ 1460 public static boolean hasRectangleFrame(String symbolID) 1461 { 1462 int affiliation = SymbolID.getAffiliation(symbolID); 1463 int ss = SymbolID.getSymbolSet(symbolID); 1464 if(ss != SymbolID.SymbolSet_ControlMeasure) 1465 { 1466 if (affiliation == SymbolID.StandardIdentity_Affiliation_Friend 1467 || affiliation == SymbolID.StandardIdentity_Affiliation_AssumedFriend 1468 || (SymbolID.getContext(symbolID)==SymbolID.StandardIdentity_Context_Exercise && 1469 (affiliation == SymbolID.StandardIdentity_Affiliation_Hostile_Faker 1470 || affiliation == SymbolID.StandardIdentity_Affiliation_Suspect_Joker))) 1471 { 1472 return true; 1473 } 1474 else 1475 return false; 1476 } 1477 else 1478 return false; 1479 } 1480 1481 /** 1482 * Returns the height ratio for the unit specified by the symbol ID 1483 * Based on Figure 4 in 2525E. 1484 * @param symbolID 30 Character {@link String} 1485 * @return {@link Float} 1486 */ 1487 public static float getUnitRatioHeight(String symbolID) 1488 { 1489 int ver = SymbolID.getVersion(symbolID); 1490 int aff = SymbolID.getAffiliation(symbolID); 1491 1492 float rh = 0; 1493 1494 if(ver < SymbolID.Version_2525E) 1495 { 1496 int ss = SymbolID.getSymbolSet(symbolID); 1497 1498 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1499 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1500 { 1501 switch (ss){ 1502 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1503 case SymbolID.SymbolSet_LandUnit: 1504 case SymbolID.SymbolSet_LandInstallation: 1505 case SymbolID.SymbolSet_LandEquipment: 1506 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1507 case SymbolID.SymbolSet_Activities: 1508 case SymbolID.SymbolSet_CyberSpace: 1509 rh = 1.44f; 1510 break; 1511 default: 1512 rh=1.3f; 1513 } 1514 } 1515 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1516 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1517 { 1518 switch (ss){ 1519 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1520 case SymbolID.SymbolSet_LandUnit: 1521 case SymbolID.SymbolSet_LandInstallation: 1522 case SymbolID.SymbolSet_Activities: 1523 case SymbolID.SymbolSet_CyberSpace: 1524 rh = 1f; 1525 break; 1526 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1527 default: 1528 rh=1.2f; 1529 } 1530 } 1531 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1532 { 1533 switch (ss){ 1534 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1535 case SymbolID.SymbolSet_LandUnit: 1536 case SymbolID.SymbolSet_LandInstallation: 1537 case SymbolID.SymbolSet_LandEquipment: 1538 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1539 case SymbolID.SymbolSet_Activities: 1540 case SymbolID.SymbolSet_CyberSpace: 1541 rh = 1.1f; 1542 break; 1543 default: 1544 rh=1.2f; 1545 } 1546 } 1547 else //UNKNOWN 1548 { 1549 switch (ss){ 1550 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1551 case SymbolID.SymbolSet_LandUnit: 1552 case SymbolID.SymbolSet_LandInstallation: 1553 case SymbolID.SymbolSet_LandEquipment: 1554 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1555 case SymbolID.SymbolSet_Activities: 1556 case SymbolID.SymbolSet_CyberSpace: 1557 rh = 1.44f; 1558 break; 1559 default: 1560 rh=1.3f; 1561 } 1562 } 1563 } 1564 else //2525E and up 1565 { 1566 String frameID = SVGLookup.getFrameID(symbolID); 1567 if(frameID.length()==6) 1568 aff = Integer.parseInt(frameID.substring(2,3)); 1569 else //"octagon" 1570 return 1f; 1571 char fs = (frameID.charAt(3)); 1572 1573 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1574 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1575 { 1576 switch (fs){ 1577 case SymbolID.FrameShape_LandUnit: 1578 case SymbolID.FrameShape_LandInstallation: 1579 case SymbolID.FrameShape_LandEquipment_SeaSurface: 1580 case SymbolID.FrameShape_Activity_Event: 1581 case SymbolID.FrameShape_Cyberspace: 1582 rh = 1.44f; 1583 break; 1584 default: 1585 rh=1.3f; 1586 } 1587 } 1588 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1589 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1590 { 1591 switch (fs){ 1592 case SymbolID.FrameShape_LandUnit: 1593 case SymbolID.FrameShape_LandInstallation: 1594 case SymbolID.FrameShape_Activity_Event: 1595 case SymbolID.FrameShape_Cyberspace: 1596 rh = 1f; 1597 break; 1598 default: 1599 rh=1.2f; 1600 } 1601 } 1602 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1603 { 1604 switch (fs){ 1605 case SymbolID.FrameShape_LandUnit: 1606 case SymbolID.FrameShape_LandInstallation: 1607 case SymbolID.FrameShape_LandEquipment_SeaSurface: 1608 case SymbolID.FrameShape_Activity_Event: 1609 case SymbolID.FrameShape_Cyberspace: 1610 rh = 1.1f; 1611 break; 1612 default: 1613 rh=1.2f; 1614 } 1615 } 1616 else //UNKNOWN 1617 { 1618 switch (fs){ 1619 case SymbolID.FrameShape_LandUnit: 1620 case SymbolID.FrameShape_LandInstallation: 1621 case SymbolID.FrameShape_LandEquipment_SeaSurface: 1622 case SymbolID.FrameShape_Activity_Event: 1623 case SymbolID.FrameShape_Cyberspace: 1624 rh = 1.44f; 1625 break; 1626 default: 1627 rh=1.3f; 1628 } 1629 } 1630 1631 1632 } 1633 1634 return rh; 1635 } 1636 1637 /** 1638 * Returns the width ratio for the unit specified by the symbol ID 1639 * Based on Figure 4 in 2525E. 1640 * @param symbolID 30 Character {@link String} 1641 * @return {@link Float} 1642 */ 1643 public static float getUnitRatioWidth(String symbolID) 1644 { 1645 int ver = SymbolID.getVersion(symbolID); 1646 int aff = SymbolID.getAffiliation(symbolID); 1647 1648 float rw = 0; 1649 1650 if(ver < SymbolID.Version_2525E) 1651 { 1652 int ss = SymbolID.getSymbolSet(symbolID); 1653 1654 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1655 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1656 { 1657 switch (ss){ 1658 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1659 case SymbolID.SymbolSet_LandUnit: 1660 case SymbolID.SymbolSet_LandInstallation: 1661 case SymbolID.SymbolSet_LandEquipment: 1662 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1663 case SymbolID.SymbolSet_Activities: 1664 case SymbolID.SymbolSet_CyberSpace: 1665 rw = 1.44f; 1666 break; 1667 default: 1668 rw=1.1f; 1669 } 1670 } 1671 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1672 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1673 { 1674 switch (ss){ 1675 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1676 case SymbolID.SymbolSet_LandUnit: 1677 case SymbolID.SymbolSet_LandInstallation: 1678 case SymbolID.SymbolSet_Activities: 1679 case SymbolID.SymbolSet_CyberSpace: 1680 rw = 1.5f; 1681 break; 1682 case SymbolID.SymbolSet_LandEquipment: 1683 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1684 rw = 1.2f; 1685 break; 1686 default: 1687 rw=1.1f; 1688 } 1689 } 1690 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1691 { 1692 rw = 1.1f; 1693 } 1694 else //UNKNOWN 1695 { 1696 switch (ss){ 1697 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 1698 case SymbolID.SymbolSet_LandUnit: 1699 case SymbolID.SymbolSet_LandInstallation: 1700 case SymbolID.SymbolSet_LandEquipment: 1701 case SymbolID.SymbolSet_SignalsIntelligence_Land: 1702 case SymbolID.SymbolSet_Activities: 1703 case SymbolID.SymbolSet_CyberSpace: 1704 rw = 1.44f; 1705 break; 1706 default: 1707 rw=1.5f; 1708 } 1709 } 1710 } 1711 else //2525E and above 1712 { 1713 String frameID = SVGLookup.getFrameID(symbolID); 1714 if(frameID.length()==6) 1715 aff = Integer.parseInt(frameID.substring(2,3)); 1716 else //"octagon" 1717 return 1f; 1718 char fs = (frameID.charAt(3)); 1719 1720 if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 1721 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 1722 { 1723 switch (fs){ 1724 case SymbolID.FrameShape_LandUnit: 1725 case SymbolID.FrameShape_LandInstallation: 1726 case SymbolID.FrameShape_LandEquipment_SeaSurface: 1727 case SymbolID.FrameShape_Activity_Event: 1728 case SymbolID.FrameShape_Cyberspace: 1729 rw = 1.44f; 1730 break; 1731 default: 1732 rw=1.1f; 1733 } 1734 } 1735 else if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 1736 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 1737 { 1738 switch (fs){ 1739 case SymbolID.FrameShape_LandUnit: 1740 case SymbolID.FrameShape_LandInstallation: 1741 case SymbolID.FrameShape_Activity_Event: 1742 case SymbolID.FrameShape_Cyberspace: 1743 rw = 1.5f; 1744 break; 1745 case SymbolID.FrameShape_LandEquipment_SeaSurface: 1746 rw = 1.2f; 1747 break; 1748 default: 1749 rw=1.1f; 1750 } 1751 } 1752 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 1753 { 1754 rw = 1.1f; 1755 } 1756 else //UNKNOWN 1757 { 1758 switch (fs){ 1759 case SymbolID.FrameShape_LandUnit: 1760 case SymbolID.FrameShape_LandInstallation: 1761 case SymbolID.FrameShape_LandEquipment_SeaSurface: 1762 case SymbolID.FrameShape_Activity_Event: 1763 case SymbolID.FrameShape_Cyberspace: 1764 rw = 1.44f; 1765 break; 1766 default: 1767 rw=1.5f; 1768 } 1769 } 1770 } 1771 1772 return rw; 1773 } 1774 1775 /** 1776 * @param linetype the line type 1777 * @return true if the line is a basic shape 1778 */ 1779 public static boolean isBasicShape(int linetype) { 1780 switch (linetype) { 1781 case TacticalLines.BS_AREA: 1782 case TacticalLines.BS_LINE: 1783 case TacticalLines.BS_CROSS: 1784 case TacticalLines.BS_ELLIPSE: 1785 case TacticalLines.PBS_ELLIPSE: 1786 case TacticalLines.PBS_CIRCLE: 1787 case TacticalLines.PBS_SQUARE: 1788 case TacticalLines.PBS_RECTANGLE: 1789 case TacticalLines.BS_RECTANGLE: 1790 case TacticalLines.BBS_AREA: 1791 case TacticalLines.BBS_LINE: 1792 case TacticalLines.BBS_POINT: 1793 case TacticalLines.BBS_RECTANGLE: 1794 case TacticalLines.BS_BBOX: 1795 return true; 1796 default: 1797 return false; 1798 } 1799 } 1800}