001package armyc2.c5isr.renderer.utilities; 002 003import android.content.Context; 004import android.graphics.RectF; 005 006import java.io.BufferedReader; 007import java.io.IOException; 008import java.io.InputStream; 009import java.io.InputStreamReader; 010import java.util.ArrayList; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014import java.util.Set; 015 016 017import armyc2.c5isr.renderer.R; 018 019public class SVGLookup { 020 private static SVGLookup _instance = null; 021 private static Boolean _initCalled = false; 022 private static Map<String, SVGInfo> _SVGLookupD = null; 023 private static Map<String, SVGInfo> _SVGLookupE = null; 024 private static Map<String, SVGInfo> _SVGLookup6D = null; 025 private static Map<String, SVGInfo> _SVGLookup6E = null; 026 private String TAG = "SVGLookup"; 027 028 029 /* 030 * Holds SymbolDefs for all symbols. (basicSymbolID, Description, MinPoint, MaxPoints, etc...) Call 031 * getInstance(). 032 * 033 */ 034 private SVGLookup() { 035 // init(null); 036 // _initCalled=true; 037 } 038 039 public static synchronized SVGLookup getInstance() { 040 if (_instance == null) { 041 _instance = new SVGLookup(); 042 } 043 044 return _instance; 045 } 046 047 public final synchronized void init(Context context) 048 { 049 if (_initCalled == false) 050 { 051 _SVGLookupD = new HashMap<>(); 052 _SVGLookupE = new HashMap<>(); 053 _SVGLookup6D = new HashMap<>(); 054 _SVGLookup6E = new HashMap<>(); 055 056 try 057 { 058 InputStream isD = context.getResources().openRawResource(R.raw.svgd); 059 loadData(isD, SymbolID.Version_2525Dch1); 060 isD.close(); 061 062 InputStream is6D = context.getResources().openRawResource(R.raw.svg6d); 063 loadData(is6D, SymbolID.Version_2525Dch1); 064 is6D.close(); 065 066 InputStream isE = context.getResources().openRawResource(R.raw.svge); 067 loadData(isE, SymbolID.Version_2525Ech1); 068 isE.close(); 069 070 InputStream is6E = context.getResources().openRawResource(R.raw.svg6e); 071 loadData(is6E, SymbolID.Version_2525E); 072 is6E.close(); 073 074 _initCalled = true; 075 } 076 catch(Exception e) 077 { 078 System.out.println(e.getMessage()); 079 } 080 } 081 082 } 083 084 private void loadData(InputStream is, int version) 085 { 086 String[] temp = null; 087 String id = null; 088 RectF bbox = null; 089 String svg = null; 090 String delimiter = "~"; 091 092 try 093 { 094 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 095 String line = br.readLine(); 096 097 Map<String, SVGInfo> lookup = null; 098 if(version == SymbolID.Version_2525E || version == SymbolID.Version_2525Ech1) 099 lookup = _SVGLookupE; 100 else if(version == SymbolID.Version_2525Dch1) 101 lookup = _SVGLookupD; 102 else if(version == SymbolID.Version_APP6D)// || version == SymbolID.Version_APP6Dch2) 103 lookup = _SVGLookup6D; 104 else if(version == SymbolID.Version_APP6Ech1 || version == SymbolID.Version_APP6Ech2) 105 lookup = _SVGLookup6E; 106 107 while (line != null) 108 { 109 //parse first line 110 temp = line.split(delimiter); 111 id = temp[0]; 112 float left, top, width, height; 113 left = Float.parseFloat(temp[1]); 114 top = Float.parseFloat(temp[2]); 115 width = Float.parseFloat(temp[3]); 116 height = Float.parseFloat(temp[4]); 117 bbox = RectUtilities.makeRectF(left, top, width, height); 118 119 if(id.startsWith("461206"))//Hydrography Bottom Features 120 { 121 //grow bbox as android uses a different serif italic font than browsers and windows 122 bbox = RectUtilities.makeRectF((int)(left + (left * -0.04)), (int)(top + (top * -0.1)), (int)(width * 1.2), (int)(height * 1.1)); 123 } 124 /*if(id.equals("25130100")) 125 Log.e("action point",id);//*/ 126 127 //read 2nd line to get SVG 128 svg = br.readLine(); 129 130 //increase icon stroke width for high dpi screens 131 //ldpi <=120, mdpi >= 160, hdpi >= 240, xhdpi >= 320, xxhdpi >= 480, xxxhdpi >= 640 132 /*if(svg != null && id.length() == 8 && !id.startsWith("25") && !id.startsWith("4")) { 133 //int dpi = RendererSettings.getInstance().getDeviceDPI(); 134 svg = RendererUtilities.increaseStrokeWidth(svg, 2); 135 }//*/ 136 137 if(lookup != null) 138 lookup.put(id, new SVGInfo(id, bbox, svg)); 139 140 //read next line for next loop 141 line = br.readLine(); 142 } 143 _initCalled = true; 144 } 145 catch(IOException ioe) 146 { 147 System.out.println(ioe.getMessage()); 148 } 149 catch(Exception e) 150 { 151 System.out.println(e.getMessage()); 152 } 153 } 154 155 /** 156 * 157 * @param id 158 * @param version 159 * @return 160 */ 161 public SVGInfo getSVGLInfo(String id, int version) 162 { 163 if(version == SymbolID.Version_2525E || version == SymbolID.Version_2525Ech1) 164 { 165 if (_SVGLookupE.containsKey(id)) 166 return _SVGLookupE.get(id); 167 } 168 else if(version == SymbolID.Version_2525Dch1) 169 { 170 if (_SVGLookupD.containsKey(id)) 171 return _SVGLookupD.get(id); 172 } 173 else if(version == SymbolID.Version_APP6Ech2 || version == SymbolID.Version_APP6Ech1) 174 { 175 if (_SVGLookup6E.containsKey(id)) 176 return _SVGLookup6E.get(id); 177 else if (_SVGLookupE.containsKey(id)) 178 return _SVGLookupE.get(id); 179 } 180 else if(version == SymbolID.Version_APP6D) 181 { 182 if (_SVGLookup6D.containsKey(id)) 183 return _SVGLookup6D.get(id); 184 else if (_SVGLookupD.containsKey(id)) 185 return _SVGLookupD.get(id); 186 else if (_SVGLookupE.containsKey(id))//Dismounted Individual 187 return _SVGLookupE.get(id); 188 } 189 190 return null; 191 } 192 193 194 public static String getFrameID(String symbolID) 195 { 196 //SIDC positions 3_456_7 197 // String frameID = symbolID.charAt(2) + "_" + symbolID.substring(3, 6) + "_" + symbolID.charAt(6); 198 199 String frameID = null; 200 String ss; 201 202 int affiliation = SymbolID.getAffiliation(symbolID); 203 if(affiliation > SymbolID.StandardIdentity_Affiliation_Hostile_Faker) 204 affiliation = SymbolID.StandardIdentity_Affiliation_Unknown; 205 206 int status = SymbolID.getStatus(symbolID); 207 //Some affiliations are always dashed and only have one SVG for status with a value of 0 208 if(affiliation == SymbolID.StandardIdentity_Affiliation_Pending || 209 affiliation == SymbolID.StandardIdentity_Affiliation_AssumedFriend || 210 affiliation == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 211 { 212 // "When the frame is assumed friend, suspect, or pending, the status shall not be displayed." 213 status = 0; 214 } 215 if(status > 1) // Anything above 1 for status means present for the frame 216 status = 0; 217 218 int context = SymbolID.getContext(symbolID); 219 //they didn't make duplicate frame so I have to change the number for 220 //the lookup to work. 221 222 if(SymbolID.getVersion(symbolID) < SymbolID.Version_2525E)//2525Dch1 or less 223 { 224 switch(SymbolID.getSymbolSet(symbolID)) 225 { 226 case 01: //Air 227 case 02: //Air Missile 228 case 51: //Air SIGINT 229 ss = "01"; 230 break; 231 case 05: //Space 232 case 06: //Space Missile 233 case 50: //Space SIGINT 234 ss = "05"; 235 break; 236 case 10: //Land Unit 237 case 11://Land Civilian Unit/Org 238 ss = "10"; 239 break; 240 case 15://Land Equipment 241 case 52://Land SigInt 242 case 53://Sea Surface SIGINT 243 ss = "30"; 244 break; 245 case 30://Sea Surface 246 ss = "30"; 247 if(SymbolID.getEntityCode(symbolID)==150000) 248 return "octagon";//this symbol has no frame and a size of 1L x 1L. 249 break; 250 case 20: //Land Installation 251 ss = "20"; 252 break; 253 case SymbolID.SymbolSet_DismountedIndividuals: //Dismounted Individuals 254 ss = "27"; 255 break; 256 case 35: //Sea Subsurface 257 case 36: //Mine Warfare 258 case 54: //Sea Subsurface SigInt 259 ss = "35"; 260 break; 261 case 40: //Activities/Events 262 ss = "40"; 263 break; 264 case 60: //Cyberspace 265 ss = "60"; //No cyberspace SVG frame at the moment so setting to activities 266 break; 267 default: 268 ss = "00"; 269 270 if(context == SymbolID.StandardIdentity_Context_Exercise && affiliation > SymbolID.StandardIdentity_Affiliation_Unknown) 271 { 272 //really there are no unknown exercise symbols outside of pending and unknown 273 //default to unknown 274 affiliation = SymbolID.StandardIdentity_Affiliation_Unknown; 275 } 276 } 277 if(context == SymbolID.StandardIdentity_Context_Restricted_Target_Reality || context == SymbolID.StandardIdentity_Context_No_Strike_Entity_Reality) 278 context = SymbolID.StandardIdentity_Context_Reality; 279 frameID = context + "_" + affiliation + ss + "_" + status; 280 } 281 else//2525E or above 282 { 283 char frameShape = SymbolID.getFrameShape(symbolID); 284 if(frameShape==SymbolID.FrameShape_Unknown) 285 { 286 287 /*if(SymbolID.getSymbolSet(symbolID) != SymbolID.SymbolSet_SignalsIntelligence) 288 {//get frame shape associated with symbol set 289 frameShape=SymbolID.getDefaultFrameShape(symbolID); 290 }//*/ 291 frameShape=SymbolID.getDefaultFrameShape(symbolID); 292 if(context == SymbolID.StandardIdentity_Context_Exercise && 293 SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_Unknown && 294 affiliation > SymbolID.StandardIdentity_Affiliation_Unknown) 295 { 296 //really there are no unknown exercise symbols outside pending and unknown affiliations 297 //default to unknown 298 affiliation = SymbolID.StandardIdentity_Affiliation_Unknown; 299 } 300 } 301 if(SymbolID.getSymbolSet(symbolID)==SymbolID.SymbolSet_SeaSurface && 302 SymbolID.getEntityCode(symbolID)==150000 && //Own Ship 303 (frameShape == SymbolID.FrameShape_SeaSurface || frameShape == SymbolID.FrameShape_Unknown)) 304 { 305 return "octagon"; 306 } 307 if(context == SymbolID.StandardIdentity_Context_Restricted_Target_Reality || context == SymbolID.StandardIdentity_Context_No_Strike_Entity_Reality) 308 context = SymbolID.StandardIdentity_Context_Reality; 309 frameID = context + "_" + affiliation + frameShape + "_" + status; 310 } 311 return frameID; 312 } 313 314 public static String getMainIconID(String symbolID) 315 { 316 //SIDC positions 5-6 + 11-16 317 String mainIconID = symbolID.substring(4, 6) + symbolID.substring(10, 16); 318 int ss = SymbolID.getSymbolSet(symbolID); 319 320 if(ss == SymbolID.SymbolSet_MineWarfare) 321 { 322 if(RendererSettings.getInstance().getSeaMineRenderMethod() == RendererSettings.SeaMineRenderMethod_ALT || 323 mainIconID.equals("36110600") || mainIconID.equals("36110700")) 324 { 325 mainIconID += "_a"; 326 } 327 } 328 else if(ss == SymbolID.SymbolSet_LandUnit) 329 { 330 switch(SymbolID.getEntityCode(symbolID)) 331 { 332 case 110501: 333 case 111000: 334 case 111001: 335 case 111002: 336 case 111003: 337 case 111004: 338 case 111005: 339 case 111500: 340 case 120100: 341 case 120300: 342 case 120400: 343 case 120401: 344 case 120402: 345 case 120501: 346 case 120502: 347 case 120601: 348 case 120801: 349 case 121100: 350 case 121101: 351 case 121102: 352 case 121103: 353 case 121104: 354 case 121105: 355 case 121106: 356 case 121107: 357 case 121300: 358 case 121301: 359 case 121302: 360 case 121303: 361 case 121304: 362 case 121802: 363 case 122100: 364 case 130100: 365 case 130101: 366 case 130102: 367 case 130103: 368 case 130200: 369 case 130302: 370 case 130303: 371 case 140102: 372 case 140103: 373 case 140104: 374 case 140105: 375 case 140702: 376 case 140703: 377 case 141702: 378 case 150504: 379 case 150800: 380 case 160200: 381 case 161200: 382 case 161300: 383 case 161400: 384 case 161700: 385 case 161800: 386 case 161900: 387 case 162000: 388 case 162100: 389 case 162200: 390 case 163400: 391 case 163700: 392 case 163800: 393 case 163900: 394 case 164000: 395 case 164100: 396 case 164200: 397 case 164300: 398 case 164400: 399 case 164500: 400 case 164600: 401 case 165000://NATO Only 402 //do thing to append correct number 403 mainIconID += getPostFixForIcon(symbolID); 404 break; 405 default: 406 break; 407 } 408 409 } 410 else if(ss == SymbolID.SymbolSet_LandEquipment) 411 { 412 switch (SymbolID.getEntityCode(symbolID)) 413 { 414 case 120111: 415 //do thing to append correct number 416 mainIconID += getPostFixForIcon(symbolID); 417 break; 418 default: 419 break; 420 } 421 } 422 else if(ss == SymbolID.SymbolSet_LandInstallation) 423 { 424 switch (SymbolID.getEntityCode(symbolID)) 425 { 426 case 110300: 427 case 111200: 428 case 120103: 429 case 120105: 430 case 120106: 431 case 120107: 432 case 120701: 433 case 120702: 434 //do thing to append correct number 435 mainIconID += getPostFixForIcon(symbolID); 436 break; 437 default: 438 break; 439 } 440 } 441 else if(ss == SymbolID.SymbolSet_DismountedIndividuals) 442 { 443 switch (SymbolID.getEntityCode(symbolID)) 444 { 445 case 110101: 446 case 110102: 447 case 110103: 448 case 110104: 449 //do thing to append correct number 450 mainIconID += getPostFixForIcon(symbolID); 451 break; 452 default: 453 break; 454 } 455 } 456 else if(ss == SymbolID.SymbolSet_Activities) 457 { 458 switch (SymbolID.getEntityCode(symbolID)) 459 { 460 case 110303: 461 case 130201: 462 case 131202: 463 case 131208: 464 //do thing to append correct number 465 mainIconID += getPostFixForIcon(symbolID); 466 break; 467 default: 468 break; 469 } 470 } 471 else if(ss == SymbolID.SymbolSet_Unknown) 472 mainIconID = "00000000";//unknown with question mark 473 else if (ss != SymbolID.SymbolSet_Air && 474 ss != SymbolID.SymbolSet_AirMissile && 475 ss != SymbolID.SymbolSet_Space && 476 ss != SymbolID.SymbolSet_SpaceMissile && 477 ss != SymbolID.SymbolSet_LandCivilianUnit_Organization && 478 ss != SymbolID.SymbolSet_DismountedIndividuals && 479 ss != SymbolID.SymbolSet_ControlMeasure && 480 ss != SymbolID.SymbolSet_SeaSurface && 481 ss != SymbolID.SymbolSet_SeaSubsurface && 482 ss != SymbolID.SymbolSet_Atmospheric && 483 ss != SymbolID.SymbolSet_Oceanographic && 484 ss != SymbolID.SymbolSet_MeteorologicalSpace && 485 ss != SymbolID.SymbolSet_SignalsIntelligence_Space && 486 ss != SymbolID.SymbolSet_SignalsIntelligence_Air && 487 ss != SymbolID.SymbolSet_SignalsIntelligence_Land && 488 ss != SymbolID.SymbolSet_SignalsIntelligence_SeaSurface && 489 ss != SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface && 490 ss != SymbolID.SymbolSet_CyberSpace) 491 { 492 mainIconID = "98100000";//invalid symbol, inverted question mark 493 } 494 495 return mainIconID; 496 } 497 498 499 private static String getPostFixForIcon(String symbolID) 500 { 501 int aff = SymbolID.getAffiliation(symbolID); 502 String pf = ""; 503 if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 504 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 505 pf += "_1"; 506 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 507 pf += "_2"; 508 else if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 509 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 510 pf += "_3"; 511 else if(aff == SymbolID.StandardIdentity_Affiliation_Unknown || 512 aff == SymbolID.StandardIdentity_Affiliation_Pending) 513 pf += "_0"; 514 515 return pf; 516 } 517 518 public static String getMod1ID(String symbolID) 519 { 520 String mod1ID = null; 521 522 523 if((SymbolID.getVersion(symbolID)>=SymbolID.Version_2525E) && symbolID.charAt(20) !='0') 524 {//2525E with Modifier 1 Indicator set 525 mod1ID = symbolID.substring(20,21) + symbolID.substring(16, 18) + "_1"; 526 if(mod1ID.equals("175_1")) 527 { 528 //TODO: as this is a common modifier, it can fit more than land units and will probably need its own function and more SVGs 529 mod1ID += getPostFixForIcon(symbolID); 530 } 531 } 532 else //2525D or no Modifier 1 Indicator set 533 { 534 //SIDC positions 5-6 + 17-18 + "1" 535 mod1ID = symbolID.substring(4, 6) + symbolID.substring(16, 18) + "1"; 536 537 if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_LandUnit) 538 { 539 switch(SymbolID.getModifier1(symbolID)) 540 { 541 case 98: 542 mod1ID += getPostFixForIcon(symbolID); 543 break; 544 default: 545 break; 546 } 547 } 548 } 549 return mod1ID; 550 } 551 552 public static String getMod2ID(String symbolID) 553 { 554 String mod2ID = null; 555 if((SymbolID.getVersion(symbolID)>=SymbolID.Version_2525E) && symbolID.charAt(21) != '0') 556 {//2525E with Modifier 1 Indicator set 557 mod2ID = symbolID.substring(21,22) + symbolID.substring(18, 20) + "_2"; 558 if(mod2ID.equals("131_2") || mod2ID.equals("134_2")) 559 { 560 //TODO: as this is a common modifier, it can fit more than land units and will probably need its own function and more SVGs 561 mod2ID += getPostFixForIcon(symbolID); 562 } 563 } 564 else //2525D or no Modifier 1 Indicator set 565 { 566 //SIDC positions 5-6 + 19-20 + "2" 567 mod2ID = symbolID.substring(4, 6) + symbolID.substring(18, 20) + "2"; 568 569 if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_LandUnit) 570 { 571 switch(SymbolID.getModifier2(symbolID)) 572 { 573 case 60: 574 case 62: 575 case 84: 576 case 89: 577 mod2ID += getPostFixForIcon(symbolID); 578 break; 579 default: 580 break; 581 } 582 } 583 } 584 return mod2ID; 585 } 586 587 public static String getEchelonAmplifier(String symbolID) 588 { 589 String amp = null; 590 int ver = SymbolID.getVersion(symbolID); 591 if (ver < SymbolID.Version_2525E) 592 { 593 amp = symbolID.charAt(3) + symbolID.substring(8,10); 594 } 595 else // >= 2525E 596 { 597 //This will eventually be different with the introduction of the frame shape modifier 598 amp = symbolID.charAt(3) + symbolID.substring(8,10); 599 } 600 return amp; 601 } 602 603 public static String getHQTFFD(String symbolID) { 604 String hqtffd = null; 605 int ver = SymbolID.getVersion(symbolID); 606 if (ver < SymbolID.Version_2525E) 607 { 608 hqtffd = symbolID.substring(3, 6) + symbolID.charAt(7); 609 } 610 else // >= 2525E 611 { 612 //This will eventually be different with the introduction of the frame shape modifier 613 hqtffd = symbolID.substring(3, 6) + symbolID.charAt(7); 614 } 615 return hqtffd; 616 } 617 618 public static String getOCA(String symbolID, boolean useSlash) 619 { 620 if(useSlash) 621 { 622 int status = SymbolID.getStatus(symbolID); 623 if(status == SymbolID.Status_Present_Damaged || status == SymbolID.Status_Present_Destroyed) 624 return String.valueOf(status); 625 else 626 return null; 627 } 628 else//get the bar 629 { 630 String oca = null; 631 int ver = SymbolID.getVersion(symbolID); 632 if(ver < SymbolID.Version_2525E) 633 { 634 oca = symbolID.substring(2,7) + "2"; 635 } 636 else // >= 2525E 637 { 638 //This will eventually be different with the introduction of the frame shape modifier 639 oca = symbolID.substring(2,7) + "2"; 640 } 641 return oca; 642 } 643 } 644 public static List<String> getAllKeys() 645 { 646 List<String> kl = new ArrayList(); 647 Set<String> keys = _SVGLookupD.keySet(); 648 for(String key: keys) { 649 //System.out.println(key); 650 kl.add(key); 651 } 652 return kl; 653 } 654 655 656 /* 657 * For use only by MilStdIconRenderer.addCustomSymbol() 658 * @param svgInfo with the basic symbol id, bounds of the SVG, SVG group 659 * @param version like SymbolID.Version_2525E 660 * @return 661 */ 662 public boolean addCustomSymbol(SVGInfo svgInfo, int version) 663 { 664 boolean success = false; 665 try 666 { 667 String basicID = svgInfo.getID(); 668 if (version < SymbolID.Version_2525E) 669 { 670 if(SVGLookup._SVGLookupD.containsKey(svgInfo.getID()) == false) 671 { 672 SVGLookup._SVGLookupD.put(svgInfo.getID(),svgInfo); 673 } 674 } 675 else if (version >= SymbolID.Version_2525E) 676 { 677 if(SVGLookup._SVGLookupE.containsKey(svgInfo.getID()) == false) 678 { 679 SVGLookup._SVGLookupE.put(svgInfo.getID(),svgInfo); 680 } 681 } 682 } 683 catch(Exception e) 684 { 685 ErrorLogger.LogException("SVGLookup","addCUstomSymbol",e); 686 } 687 return success; 688 } 689} 690 691