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