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