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 ss != SymbolID.SymbolSet_CyberSpace_Equipment) 492 { 493 mainIconID = "98100000";//invalid symbol, inverted question mark 494 } 495 496 return mainIconID; 497 } 498 499 500 private static String getPostFixForIcon(String symbolID) 501 { 502 int aff = SymbolID.getAffiliation(symbolID); 503 String pf = ""; 504 if(aff == SymbolID.StandardIdentity_Affiliation_Friend || 505 aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend) 506 pf += "_1"; 507 else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral) 508 pf += "_2"; 509 else if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker || 510 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker) 511 pf += "_3"; 512 else if(aff == SymbolID.StandardIdentity_Affiliation_Unknown || 513 aff == SymbolID.StandardIdentity_Affiliation_Pending) 514 pf += "_0"; 515 516 return pf; 517 } 518 519 public static String getMod1ID(String symbolID) 520 { 521 String mod1ID = null; 522 523 524 if((SymbolID.getVersion(symbolID)>=SymbolID.Version_2525E) && symbolID.charAt(20) !='0') 525 {//2525E with Modifier 1 Indicator set 526 mod1ID = symbolID.substring(20,21) + symbolID.substring(16, 18) + "_1"; 527 if(mod1ID.equals("175_1")) 528 { 529 //TODO: as this is a common modifier, it can fit more than land units and will probably need its own function and more SVGs 530 mod1ID += getPostFixForIcon(symbolID); 531 } 532 } 533 else //2525D or no Modifier 1 Indicator set 534 { 535 //SIDC positions 5-6 + 17-18 + "1" 536 mod1ID = symbolID.substring(4, 6) + symbolID.substring(16, 18) + "1"; 537 538 if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_LandUnit) 539 { 540 switch(SymbolID.getModifier1(symbolID)) 541 { 542 case 98: 543 mod1ID += getPostFixForIcon(symbolID); 544 break; 545 default: 546 break; 547 } 548 } 549 } 550 return mod1ID; 551 } 552 553 public static String getMod2ID(String symbolID) 554 { 555 String mod2ID = null; 556 if((SymbolID.getVersion(symbolID)>=SymbolID.Version_2525E) && symbolID.charAt(21) != '0') 557 {//2525E with Modifier 1 Indicator set 558 mod2ID = symbolID.substring(21,22) + symbolID.substring(18, 20) + "_2"; 559 if(mod2ID.equals("131_2") || mod2ID.equals("134_2")) 560 { 561 //TODO: as this is a common modifier, it can fit more than land units and will probably need its own function and more SVGs 562 mod2ID += getPostFixForIcon(symbolID); 563 } 564 } 565 else //2525D or no Modifier 1 Indicator set 566 { 567 //SIDC positions 5-6 + 19-20 + "2" 568 mod2ID = symbolID.substring(4, 6) + symbolID.substring(18, 20) + "2"; 569 570 if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_LandUnit) 571 { 572 switch(SymbolID.getModifier2(symbolID)) 573 { 574 case 60: 575 case 62: 576 case 84: 577 case 89: 578 mod2ID += getPostFixForIcon(symbolID); 579 break; 580 default: 581 break; 582 } 583 } 584 } 585 return mod2ID; 586 } 587 588 public static String getEchelonAmplifier(String symbolID) 589 { 590 String amp = null; 591 int ver = SymbolID.getVersion(symbolID); 592 if (ver < SymbolID.Version_2525E) 593 { 594 amp = symbolID.charAt(3) + symbolID.substring(8,10); 595 } 596 else // >= 2525E 597 { 598 //This will eventually be different with the introduction of the frame shape modifier 599 amp = symbolID.charAt(3) + symbolID.substring(8,10); 600 } 601 return amp; 602 } 603 604 public static String getHQTFFD(String symbolID) { 605 String hqtffd = null; 606 int ver = SymbolID.getVersion(symbolID); 607 if (ver < SymbolID.Version_2525E) 608 { 609 hqtffd = symbolID.substring(3, 6) + symbolID.charAt(7); 610 } 611 else // >= 2525E 612 { 613 //This will eventually be different with the introduction of the frame shape modifier 614 hqtffd = symbolID.substring(3, 6) + symbolID.charAt(7); 615 } 616 return hqtffd; 617 } 618 619 public static String getOCA(String symbolID, boolean useSlash) 620 { 621 if(useSlash) 622 { 623 int status = SymbolID.getStatus(symbolID); 624 if(status == SymbolID.Status_Present_Damaged || status == SymbolID.Status_Present_Destroyed) 625 return String.valueOf(status); 626 else 627 return null; 628 } 629 else//get the bar 630 { 631 String oca = null; 632 int ver = SymbolID.getVersion(symbolID); 633 if(ver < SymbolID.Version_2525E) 634 { 635 oca = symbolID.substring(2,7) + "2"; 636 } 637 else // >= 2525E 638 { 639 //This will eventually be different with the introduction of the frame shape modifier 640 oca = symbolID.substring(2,7) + "2"; 641 } 642 return oca; 643 } 644 } 645 public static List<String> getAllKeys() 646 { 647 List<String> kl = new ArrayList(); 648 Set<String> keys = _SVGLookupD.keySet(); 649 for(String key: keys) { 650 //System.out.println(key); 651 kl.add(key); 652 } 653 return kl; 654 } 655 656 657 /* 658 * For use only by MilStdIconRenderer.addCustomSymbol() 659 * @param svgInfo with the basic symbol id, bounds of the SVG, SVG group 660 * @param version like SymbolID.Version_2525E 661 * @return 662 */ 663 public boolean addCustomSymbol(SVGInfo svgInfo, int version) 664 { 665 boolean success = false; 666 try 667 { 668 String basicID = svgInfo.getID(); 669 if (version < SymbolID.Version_2525E) 670 { 671 if(SVGLookup._SVGLookupD.containsKey(svgInfo.getID()) == false) 672 { 673 SVGLookup._SVGLookupD.put(svgInfo.getID(),svgInfo); 674 } 675 } 676 else if (version >= SymbolID.Version_2525E) 677 { 678 if(SVGLookup._SVGLookupE.containsKey(svgInfo.getID()) == false) 679 { 680 SVGLookup._SVGLookupE.put(svgInfo.getID(),svgInfo); 681 } 682 } 683 } 684 catch(Exception e) 685 { 686 ErrorLogger.LogException("SVGLookup","addCUstomSymbol",e); 687 } 688 return success; 689 } 690} 691 692