001package armyc2.c5isr.renderer; 002 003import android.content.Context; 004import android.os.Build; 005import android.util.DisplayMetrics; 006import android.util.Log; 007import android.view.WindowManager; 008 009import java.util.HashMap; 010import java.util.Map; 011import java.util.concurrent.atomic.AtomicBoolean; 012import java.util.logging.Level; 013 014import armyc2.c5isr.renderer.utilities.C2DLookup; 015import armyc2.c5isr.renderer.utilities.DrawRules; 016import armyc2.c5isr.renderer.utilities.ErrorLogger; 017import armyc2.c5isr.renderer.utilities.GENCLookup; 018import armyc2.c5isr.renderer.utilities.ImageInfo; 019import armyc2.c5isr.renderer.utilities.MSInfo; 020import armyc2.c5isr.renderer.utilities.MSLookup; 021import armyc2.c5isr.renderer.utilities.MilStdAttributes; 022import armyc2.c5isr.renderer.utilities.RendererSettings; 023import armyc2.c5isr.renderer.utilities.SVGInfo; 024import armyc2.c5isr.renderer.utilities.SVGLookup; 025import armyc2.c5isr.renderer.utilities.SVGSymbolInfo; 026import armyc2.c5isr.renderer.utilities.SectorModUtils; 027import armyc2.c5isr.renderer.utilities.SymbolID; 028import armyc2.c5isr.renderer.utilities.SymbolUtilities; 029 030/** 031 * This class is used for rendering icons that represent the single point graphics in the MilStd 2525. 032 * It can also be used for rendering icon previews for multipoint graphics. 033 */ 034public class MilStdIconRenderer 035/* implements IIconRenderer */ { 036 037 private String TAG = "MilStdIconRenderer"; 038 039 private static MilStdIconRenderer _instance = null; 040 private AtomicBoolean _initSuccess = new AtomicBoolean(false); 041 private SinglePointRenderer _SPR = null; 042 043 private SinglePointSVGRenderer _SPSVGR = null; 044 public static synchronized MilStdIconRenderer getInstance() 045 { 046 if (_instance == null) { 047 _instance = new MilStdIconRenderer(); 048 } 049 return _instance; 050 } 051 052 /** 053 * 054 * @param context 055 */ 056 public synchronized void init(Context context)// List<Typeface> fonts, List<String> xml 057 { 058 try { 059 if (!_initSuccess.get()) { 060 061 //test SVGLookup//////////////////////////////////////////////////////////////////// 062 SVGLookup.getInstance().init(context); 063 /*SVGInfo oct = SVGLookup.getInstance().getSVGLInfo("octagon"); 064 System.out.println(oct.toString());//*/ 065 066 //test MSLookup///////////////////////////////////////////////////////////////////// 067 MSLookup.getInstance().init(context); 068 069 /*MSInfo msi = MSLookup.getInstance().getMSLInfo("50110100",0);// 070 msi = MSLookup.getInstance().getMSLInfo("36190100",0);//"Non-Mine MineāLike Object, Bottom" 071 System.out.println(msi.getPath()); 072 System.out.println(msi.getName()); 073 msi = MSLookup.getInstance().getMSLInfo("01110300",0);//"Unmanned Aircraft (UA) / Unmanned Aerial Vehicle (UAV) / Unmanned Aircraft System (UAS) / Remotely Piloted Vehicle (RPV)" 074 System.out.println(msi.getPath()); 075 System.out.println(msi.getName());//*/ 076 077 //https://stackoverflow.com/questions/3166501/getting-the-screen-density-programmatically-in-android 078 DisplayMetrics dm = new DisplayMetrics(); 079 WindowManager manager; 080 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 081 manager = context.getSystemService(WindowManager.class);//.getDefaultDisplay().getRealMetrics(dm); 082 } 083 else 084 { 085 manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 086 } 087 manager.getDefaultDisplay().getRealMetrics(dm); 088 089 RendererSettings.getInstance().setDeviceDPI(dm.densityDpi); 090 RendererSettings.getInstance().setDeviceHeight(dm.heightPixels); 091 RendererSettings.getInstance().setDeviceWidth(dm.widthPixels); 092 093 //Country Codes 094 GENCLookup.getInstance().init(context); 095 096 //SectorMod lookups 097 SectorModUtils.getInstance().init(context); 098 099 //C2DLookup (2525C -> 2525Dch1 code conversion) 100 C2DLookup.getInstance().init(context); 101 102 // setup single point renderer 103 _SPR = SinglePointRenderer.getInstance(); 104 _SPSVGR = SinglePointSVGRenderer.getInstance(); 105 106 _initSuccess.set(true); 107 } 108 109 } catch (Exception exc) { 110 Log.e(TAG, exc.getMessage(), exc); 111 } 112 } 113 114 public synchronized boolean isReady() 115 { 116 return _initSuccess.get(); 117 } 118 119 // @Override 120 121 /** 122 * Checks symbol codes and returns whether they can be rendered. 123 * For multi-point graphics, modifiers are ignored because we don't need that 124 * information to show preview icons in the SymbolPicker. 125 * 126 * @param symbolID 20-30 digit 2525D Symbol ID Code 127 * @param attributes (currently unused) 128 * @return true if the basic form of the graphic can be rendered 129 */ 130 public Boolean CanRender(String symbolID, Map<String,String> attributes) 131 { 132 String message = ""; 133 try { 134 // Extract 8-digit ID to use with SVGLookup. 135 // MSLookup can handle long codes, but SVGLookup can't because it also takes other strings. 136 String lookupID = SymbolUtilities.getBasicSymbolID(symbolID); 137 String lookupSVGID = SVGLookup.getMainIconID(symbolID); 138 139 // Renderer only supports 2525D at the moment. 2525E will be in the future. 140 /* 141 int symStd = -1; 142 int version = SymbolID.getVersion(symbolID); 143 //SymbolID.Version_2525Dch1 144 //SymbolID.Version_2525E 145 */ 146 147 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 148 if (msi == null) 149 { 150 if(SymbolID.getEntityCode(symbolID)==0) 151 { 152 switch (SymbolID.getSymbolSet(symbolID)) 153 { 154 case SymbolID.SymbolSet_Air: 155 case SymbolID.SymbolSet_AirMissile: 156 case SymbolID.SymbolSet_Space: 157 case SymbolID.SymbolSet_SpaceMissile: 158 case SymbolID.SymbolSet_LandUnit: 159 case SymbolID.SymbolSet_LandCivilianUnit_Organization: 160 case SymbolID.SymbolSet_LandEquipment: 161 //case SymbolID.SymbolSet_ControlMeasure: 162 case SymbolID.SymbolSet_DismountedIndividuals: 163 case SymbolID.SymbolSet_SeaSurface: 164 case SymbolID.SymbolSet_SeaSubsurface: 165 case SymbolID.SymbolSet_MineWarfare: 166 case SymbolID.SymbolSet_Activities: 167 case SymbolID.SymbolSet_CyberSpace: 168 //case SymbolID.SymbolSet_SignalsIntelligence: 169 case SymbolID.SymbolSet_SignalsIntelligence_Air: 170 case SymbolID.SymbolSet_SignalsIntelligence_Land: 171 case SymbolID.SymbolSet_SignalsIntelligence_Space: 172 case SymbolID.SymbolSet_SignalsIntelligence_SeaSurface: 173 case SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface: 174 return true; 175 } 176 } 177 message = String.format("Cannot find %s in MSLookup", lookupID); 178 } else if (msi.getDrawRule() == DrawRules.DONOTDRAW) { 179 message = String.format("%s (%s) is DoNotDraw", lookupID, msi.getName()); 180 } else 181 { 182 int version = SymbolID.getVersion(symbolID); 183 SVGInfo si = SVGLookup.getInstance().getSVGLInfo(lookupSVGID,version); 184 if (si != null)// || (SymbolID.getEntityCode(symbolID)==000000 && SVGLookup.getInstance().getSVGLInfo(SVGLookup.getFrameID(symbolID)) != null)) 185 { 186 return true; 187 } 188 else 189 { 190 message = String.format("Cannot find %s (%s) in SVGLookup", lookupID, msi.getName()); 191 } 192 } 193 } catch (Exception exc) { 194 ErrorLogger.LogException("MilStdIconRenderer", "CanRender", exc); 195 } 196 // ErrorLogger.LogMessage(this.getClass().getName(), "CanRender()", message, Level.FINE); 197 Log.d("MilStdIconR.CanRender()", message); 198 return false; 199 } 200 201 202 203 // @Override 204 public ImageInfo RenderIcon(String symbolID, Map<String,String> modifiers, 205 Map<String,String> attributes) 206 { 207 208 209 int ss = SymbolID.getSymbolSet(symbolID); 210 211 ImageInfo temp = null; 212 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 213 /*if (msi == null) 214 { 215 //Attempt to fix the code or set if to invalid symbol if unfixable 216 symbolID = SymbolUtilities.reconcileSymbolID(symbolID); 217 msi = MSLookup.getInstance().getMSLInfo(symbolID); 218 if(msi == null) 219 { 220 if(SymbolID.getSymbolSet(symbolID)!=SymbolID.SymbolSet_LandUnit) 221 222 symbolID = "110098000010000000000000000000";//invalid symbol 223 } 224 } 225 if (msi != null && msi.getDrawRule() == DrawRules.DONOTDRAW) { 226 return null; 227 }//*/ 228 229 if (ss==SymbolID.SymbolSet_ControlMeasure) 230 { 231 if (msi != null) { 232 //Point12 is actually a multipoint and 17 & 18 are rectangular target and sector range fan 233 if (SymbolUtilities.isMultiPoint(symbolID)==false) { 234 temp = _SPR.RenderSP(symbolID, modifiers, attributes); 235 } else { 236 temp = _SPR.RenderSP(symbolID, null, attributes); 237 } 238 } 239 } 240 else if(ss==SymbolID.SymbolSet_Atmospheric || 241 ss==SymbolID.SymbolSet_Oceanographic || 242 ss==SymbolID.SymbolSet_MeteorologicalSpace) 243 { 244 temp = _SPR.RenderSP(symbolID, modifiers, attributes); 245 } 246 else 247 { 248 temp = _SPR.RenderUnit(symbolID, modifiers, attributes); 249 } 250 251 return temp; 252 } 253 254 public SVGSymbolInfo RenderSVG(String symbolID, Map<String,String> modifiers, 255 Map<String,String> attributes) 256 { 257 258 //Update to use _SPSVGR.RenderUnit 259 int ss = SymbolID.getSymbolSet(symbolID); 260 261 ImageInfo temp = null; 262 SVGSymbolInfo svgTemp = null; 263 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID); 264 if (msi == null) 265 { 266 //TODO: if null, try to fix the code so that something renders 267 /*symbolID = SymbolUtilities.reconcileSymbolID(symbolID); 268 basicSymbolID = SymbolUtilities.getBasicSymbolIDStrict(symbolID); 269 sd = SymbolDefTable.getInstance().getSymbolDef(basicSymbolID, symStd);//*/ 270 } 271 if (msi != null && msi.getDrawRule() == DrawRules.DONOTDRAW) 272 { 273 return null; 274 } 275 276 if (ss==SymbolID.SymbolSet_ControlMeasure) 277 { 278 if (msi != null) { 279 //Point12 is actually a multipoint and 17 & 18 are rectangular target and sector range fan 280 if (SymbolUtilities.isMultiPoint(symbolID)==false) { 281 svgTemp = _SPSVGR.RenderSP(symbolID, modifiers, attributes); 282 } else { 283 svgTemp = _SPSVGR.RenderSP(symbolID, null, attributes); 284 } 285 } 286 } 287 else if(ss==SymbolID.SymbolSet_Atmospheric || 288 ss==SymbolID.SymbolSet_Oceanographic || 289 ss==SymbolID.SymbolSet_MeteorologicalSpace) 290 { 291 svgTemp = _SPSVGR.RenderSP(symbolID, modifiers, attributes); 292 } 293 else 294 { 295 svgTemp = _SPSVGR.RenderUnit(symbolID, modifiers, attributes); 296 } 297 298 return svgTemp; 299 } 300 301 // @Override 302 public String getRendererID() 303 { 304 305 return "milstd2525"; 306 } 307 308 private Map<String,String> getDefaultAttributes(String symbolID) 309 { 310 Map<String,String> map = new HashMap<>(); 311 try { 312 if (symbolID == null || symbolID.length() != 15) { 313 if (symbolID == null) { 314 symbolID = "null"; 315 } 316 ErrorLogger.LogMessage("MilStdIconRenderer", "getDefaultAttributes", 317 "getDefaultAttributes passed bad symbolID: " + symbolID); 318 return null; 319 } 320 321 map.put(MilStdAttributes.Alpha, "1.0"); 322 if (SymbolUtilities.hasDefaultFill(symbolID)) { 323 map.put(MilStdAttributes.FillColor, 324 SymbolUtilities.getFillColorOfAffiliation(symbolID).toHexString()); 325 } 326 327 map.put(MilStdAttributes.LineColor, 328 SymbolUtilities.getLineColorOfAffiliation(symbolID).toHexString()); 329 330 map.put(MilStdAttributes.OutlineSymbol, "false"); 331 // attribute[MilStdAttributes.SymbolOutlineColor] = null; 332 // map.put(MilStdAttributes.OutlineWidth,"1"); 333 334 map.put(MilStdAttributes.DrawAsIcon, "false"); 335 336 RendererSettings rs = RendererSettings.getInstance(); 337 338 map.put(MilStdAttributes.KeepUnitRatio, "true"); 339 return map; 340 } catch (Exception exc) { 341 ErrorLogger.LogException("MilStdIconRenderer", "getDefaultAttributes", exc); 342 } 343 return map; 344 } 345 346 /** 347 * Add a custom framed symbol to the renderer's collection 348 * @param msInfo 349 * @param svgInfo 350 * @return 351 */ 352 public boolean AddCustomSymbol(MSInfo msInfo, SVGInfo svgInfo) 353 { 354 boolean success = false; 355 if(msInfo.getBasicSymbolID().equals(svgInfo.getID()))//Make sure IDs match 356 { 357 //Make sure entry isn't already there 358 if(MSLookup.getInstance().getMSLInfo(msInfo.getBasicSymbolID(),msInfo.getVersion())==null && 359 SVGLookup.getInstance().getSVGLInfo(svgInfo.getID(),msInfo.getVersion())==null) 360 { 361 if(MSLookup.getInstance().addCustomSymbol(msInfo)) 362 success = SVGLookup.getInstance().addCustomSymbol(svgInfo,msInfo.getVersion()); 363 } 364 } 365 else 366 { 367 ErrorLogger.LogMessage("Symbol Set and Entity Codes do not match", Level.INFO,false); 368 } 369 return success; 370 } 371}