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