package armyc2.c2sd.renderer; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Paint.Align; import android.graphics.Paint.FontMetrics; import android.graphics.Typeface; import android.os.Environment; import android.util.Log; import android.util.LruCache; import android.util.SparseArray; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import armyc2.c2sd.renderer.utilities.Color; import armyc2.c2sd.renderer.utilities.ErrorLogger; import armyc2.c2sd.renderer.utilities.FontManager; import armyc2.c2sd.renderer.utilities.ImageInfo; import armyc2.c2sd.renderer.utilities.MilStdAttributes; import armyc2.c2sd.renderer.utilities.ModifiersTG; import armyc2.c2sd.renderer.utilities.RectUtilities; import armyc2.c2sd.renderer.utilities.RendererSettings; import armyc2.c2sd.renderer.utilities.RendererUtilities; import armyc2.c2sd.renderer.utilities.SettingsChangedEvent; import armyc2.c2sd.renderer.utilities.SettingsChangedEventListener; import armyc2.c2sd.renderer.utilities.SinglePointLookup; import armyc2.c2sd.renderer.utilities.SinglePointLookupInfo; import armyc2.c2sd.renderer.utilities.SymbolDef; import armyc2.c2sd.renderer.utilities.SymbolDimensions; import armyc2.c2sd.renderer.utilities.SymbolUtilities; import armyc2.c2sd.renderer.utilities.UnitFontLookup; import armyc2.c2sd.renderer.utilities.UnitFontLookupInfo; public class SinglePointRenderer implements SettingsChangedEventListener { private final String TAG = "SinglePointRenderer"; private static SinglePointRenderer _instance = null; private Typeface _tfUnits = null; private Typeface _tfSP = null; private Typeface _tfTG = null; private final Object _SinglePointFontMutex = new Object(); private final Object _UnitFontMutex = new Object(); private final Object _ModifierFontMutex = new Object(); private final Object _SinglePointCacheMutex = new Object(); private final Object _UnitCacheMutex = new Object(); private Paint _modifierFont = new Paint(); private Paint _modifierOutlineFont = new Paint(); private float _modifierDescent = 2; private float _modifierFontHeight = 10; private int _deviceDPI = 72; //private LruCache<String, ImageInfo> _unitCache = new LruCache<String, ImageInfo>(15); //private LruCache<String, ImageInfo> _tgCache = new LruCache<String, ImageInfo>(7); private LruCache<String, ImageInfo> _unitCache = new LruCache<String, ImageInfo>(1024); private LruCache<String, ImageInfo> _tgCache = new LruCache<String, ImageInfo>(1024); private final int maxMemory = (int) (Runtime.getRuntime().maxMemory());// / 1024); private int cacheSize = 5;//RendererSettings.getInstance().getCacheSize() / 2; private int maxCachedEntrySize = cacheSize / 5; private SinglePointRenderer() { _tfUnits = FontManager.getInstance().getTypeface(FontManager.FONT_UNIT); _tfSP = FontManager.getInstance().getTypeface(FontManager.FONT_SPTG); _tfTG = FontManager.getInstance().getTypeface(FontManager.FONT_MPTG); TacticalGraphicIconRenderer.setTGTypeFace(_tfTG); RendererSettings.getInstance().addEventListener(this); //get modifier font values. onSettingsChanged(new SettingsChangedEvent(SettingsChangedEvent.EventType_FontChanged)); //set cache onSettingsChanged(new SettingsChangedEvent(SettingsChangedEvent.EventType_CacheSizeChanged)); } public static synchronized SinglePointRenderer getInstance() { if (_instance == null) { _instance = new SinglePointRenderer(); } return _instance; } /** * * @param symbolID * @param modifiers * @return */ public ImageInfo RenderUnit(String symbolID, SparseArray<String> modifiers, SparseArray<String> attributes) { ImageInfo temp = null; float fontSize = RendererSettings.getInstance().getUnitFontSize(); Color lineColor = SymbolUtilities.getLineColorOfAffiliation(symbolID); Color fillColor = SymbolUtilities.getFillColorOfAffiliation(symbolID); Color iconColor = null; int alpha = -1; int symStd = RendererSettings.getInstance().getSymbologyStandard(); //get fill character int charFillIndex = UnitFontLookup.getFillCode(symbolID, symStd); //get frame character int charFrameIndex = UnitFontLookup.getFrameCode(symbolID, charFillIndex); int charSymbol1Index = -1; int charSymbol2Index = -1; int charFrameAssumeIndex = -1; char frameAssume; Paint fillPaint = null; Paint framePaint = null; Paint symbol1Paint = null; Paint symbol2Paint = null; Paint frameAssumePaint = null; UnitFontLookupInfo lookup = null; Rect symbolBounds = null; Rect fullBounds = null; Bitmap fullBMP = null; boolean hasDisplayModifiers = false; boolean hasTextModifiers = false; int pixelSize = -1; boolean keepUnitRatio = true; boolean icon = false; float[] dimensions = { 0f, 0f, 0f, 0f }; try { //get MilStdAttributes if (attributes.indexOfKey(MilStdAttributes.SymbologyStandard) >= 0) { symStd = Integer.parseInt(attributes.get(MilStdAttributes.SymbologyStandard)); } if (symStd > RendererSettings.Symbology_2525Bch2_USAS_13_14) { char affiliation = symbolID.charAt(1); switch (affiliation) { case 'P': case 'A': case 'S': case 'G': case 'M': if(symbolID.charAt(2) == 'U' && (symbolID.substring(4, 6).equals("WM") || symbolID.substring(4, 7).equals("WDM"))) { if(symbolID.charAt(3) != 'A') { charFillIndex++; } charFrameAssumeIndex = charFillIndex - 1; charFrameIndex = -1; } else { charFrameIndex = charFillIndex + 2; charFrameAssumeIndex = charFillIndex + 1; } break; } if (charFrameAssumeIndex > 0) { frameAssume = (char) (charFrameAssumeIndex); } } if (attributes.indexOfKey(MilStdAttributes.PixelSize) >= 0) { pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize)); } else { pixelSize = RendererSettings.getInstance().getDefaultPixelSize(); } if (attributes.indexOfKey(MilStdAttributes.KeepUnitRatio) >= 0) { keepUnitRatio = Boolean.parseBoolean(attributes.get(MilStdAttributes.KeepUnitRatio)); } if (attributes.indexOfKey(MilStdAttributes.DrawAsIcon) >= 0) { icon = Boolean.parseBoolean(attributes.get(MilStdAttributes.DrawAsIcon)); } if (icon)//icon won't show modifiers or display icons { keepUnitRatio = false; hasDisplayModifiers = false; hasTextModifiers = false; symbolID = symbolID.substring(0, 10) + "-----"; } else { hasDisplayModifiers = ModifierRenderer.hasDisplayModifiers(symbolID, modifiers); hasTextModifiers = ModifierRenderer.hasTextModifiers(symbolID, modifiers, attributes); } if (attributes.indexOfKey(MilStdAttributes.LineColor) >= 0) { lineColor = new Color(attributes.get(MilStdAttributes.LineColor)); } if (attributes.indexOfKey(MilStdAttributes.FillColor) >= 0) { fillColor = new Color(attributes.get(MilStdAttributes.FillColor)); } if (attributes.indexOfKey(MilStdAttributes.IconColor) >= 0) { iconColor = new Color(attributes.get(MilStdAttributes.IconColor)); } //get symbol info lookup = UnitFontLookup.getInstance().getLookupInfo(symbolID, symStd); if (lookup == null)//if lookup fails, fix code/use unknown symbol code. { //if symbolID bad, do best to find a workable code lookup = ResolveUnitFontLookupInfo(symbolID, symStd); } //////////////////////////////////////////////////////////////////// dimensions = SymbolDimensions.getUnitBounds(charFillIndex, 50); symbolBounds = RectUtilities.makeRect(0f, 0f, dimensions[2], dimensions[3]); Rect rect = new Rect(symbolBounds); float ratio = -1; if (pixelSize > 0 && keepUnitRatio == true) { float heightRatio = UnitFontLookup.getUnitRatioHeight(charFillIndex); float widthRatio = UnitFontLookup.getUnitRatioWidth(charFillIndex); if (heightRatio > widthRatio) { pixelSize = (int) ((pixelSize / 1.5f) * heightRatio); } else { pixelSize = (int) ((pixelSize / 1.5f) * widthRatio); } } if (pixelSize > 0) { float p = pixelSize; float h = rect.height(); float w = rect.width(); ratio = Math.min((p / h), (p / w)); float fontsize = 50; //ratio = ratio / 72 * 96; fontSize = (((fontsize * ratio))); //fontSize = (((fontsize * ratio) / 96) * 72); //fontSize = (((fontsize * ratio) / 96) * _deviceDPI); //ctx.font= "75pt UnitFontsC"; //symbolBounds = SymbolDimensions.getUnitBounds(charFillIndex, (50 * ratio)); dimensions = SymbolDimensions.getUnitBounds(charFillIndex, 50 * ratio); symbolBounds = RectUtilities.makeRect(0f, 0f, dimensions[2], dimensions[3]); }//*/ //////////////////////////////////////////////////////////////////// fillPaint = new Paint(); fillPaint.setStyle(Paint.Style.FILL); fillPaint.setColor(fillColor.toARGB()); fillPaint.setTextSize(fontSize); fillPaint.setAntiAlias(true); fillPaint.setTextAlign(Align.CENTER); fillPaint.setTypeface(_tfUnits); framePaint = new Paint(); framePaint.setStyle(Paint.Style.FILL); framePaint.setColor(lineColor.toARGB()); framePaint.setTextSize(fontSize); framePaint.setAntiAlias(true); framePaint.setTextAlign(Align.CENTER); framePaint.setTypeface(_tfUnits); symbol1Paint = new Paint(); symbol1Paint.setStyle(Paint.Style.FILL); if(iconColor != null) { symbol1Paint.setColor(iconColor.toARGB()); } else { symbol1Paint.setColor(lookup.getColor1().toARGB()); } symbol1Paint.setTextSize(fontSize); symbol1Paint.setAntiAlias(true); symbol1Paint.setTextAlign(Align.CENTER); symbol1Paint.setTypeface(_tfUnits); symbol2Paint = new Paint(); symbol2Paint.setStyle(Paint.Style.FILL); symbol2Paint.setColor(lookup.getColor2().toARGB()); symbol2Paint.setTextSize(fontSize); symbol2Paint.setAntiAlias(true); symbol2Paint.setTextAlign(Align.CENTER); symbol2Paint.setTypeface(_tfUnits); frameAssumePaint = new Paint(); frameAssumePaint.setStyle(Paint.Style.FILL); frameAssumePaint.setColor(Color.WHITE.toARGB()); frameAssumePaint.setTextSize(fontSize); frameAssumePaint.setAntiAlias(true); frameAssumePaint.setTextAlign(Align.CENTER); frameAssumePaint.setTypeface(_tfUnits); //Just for sea mines if(symbolID.charAt(2) == 'U' && symbolID.substring(4, 6).equals("WM")) { if(symStd == RendererSettings.Symbology_2525B) { fillPaint.setColor(fillColor.toARGB()); symbol1Paint.setColor(lineColor.toARGB()); } else if(symStd == RendererSettings.Symbology_2525C) { fillPaint.setColor(lineColor.toARGB()); } } else if(symbolID.charAt(2) == 'S' && symbolID.charAt(4) == 'O')//own track, //SUSPO { fillPaint.setColor(lineColor.toARGB()); } } catch (Exception excModifiers) { ErrorLogger.LogException("MilStdIconRenderer", "RenderUnit", excModifiers); } try { ImageInfo ii = null; String key = makeCacheKey(symbolID, lineColor.toInt(), fillColor.toInt(), symbol1Paint.getColor(), pixelSize, keepUnitRatio, symStd); //see if it's in the cache ii = _unitCache.get(key); //if not, generate symbol if (ii == null)//*/ { if (lookup != null) { //get Symbol1 character mapping charSymbol1Index = lookup.getMapping1(symbolID); //get Symbol2 character mapping charSymbol2Index = lookup.getMapping2(); } //dimensions of the unit at specified font size //dimensions = SymbolDimensions.getUnitBounds(charFillIndex, fontSize); //symbolBounds = RectUtilities.makeRect(0, 0, dimensions[2], dimensions[3]); //get centerpoint of the image Point centerPoint = new Point(Math.round(symbolBounds.width() / 2), Math.round(symbolBounds.height() / 2)); Point centerCache = new Point(centerPoint); //y offset to get centerpoint so we set back to zero when done. symbolBounds.top = 0; //Draw glyphs to bitmap Bitmap bmp = Bitmap.createBitmap((int) (symbolBounds.width()), (int) (symbolBounds.height()), Config.ARGB_8888); Canvas canvas = new Canvas(bmp); //Log.i("HWA?","HWA: " + String.valueOf(canvas.isHardwareAccelerated())); String strFill = null; String strFrame = null; String strSymbol1 = null; String strSymbol2 = null; String strFrameAssume = null; if (charFillIndex > 0) { strFill = String.valueOf((char) charFillIndex); } if (charFrameIndex > 0) { strFrame = String.valueOf((char) charFrameIndex); } if (charSymbol1Index > 0) { strSymbol1 = String.valueOf((char) charSymbol1Index); } if (charSymbol2Index > 0) { strSymbol2 = String.valueOf((char) charSymbol2Index); } if (charFrameAssumeIndex > 0) { strFrameAssume = String.valueOf((char) charFrameAssumeIndex); } //test /*Paint ptTest = new Paint(); ptTest.setColor(Color.GREEN); Rect rTest = new Rect(0,0,bmp.getWidth(),bmp.getHeight()); canvas.drawRect(rTest, ptTest);//*/ //end test synchronized(_UnitFontMutex) { if (strFrameAssume != null && charFillIndex == -1) { canvas.drawText(strFrameAssume, centerPoint.x, centerPoint.y + (int) dimensions[1], symbol2Paint); strFrameAssume = null; } if (strFill != null) { canvas.drawText(strFill, centerPoint.x, centerPoint.y + (int) dimensions[1], fillPaint); } if (strFrameAssume != null) { canvas.drawText(strFrameAssume, centerPoint.x, centerPoint.y + (int) dimensions[1], frameAssumePaint); } if (strFrame != null) { canvas.drawText(strFrame, centerPoint.x, centerPoint.y + (int) dimensions[1], framePaint); } if (strSymbol2 != null) { canvas.drawText(strSymbol2, centerPoint.x, centerPoint.y + (int) dimensions[1], symbol2Paint); } if (strSymbol1 != null) { canvas.drawText(strSymbol1, centerPoint.x, centerPoint.y + (int) dimensions[1], symbol1Paint); } } //adjust centerpoint for HQStaff if present if (SymbolUtilities.isHQ(symbolID)) { PointF point1 = new PointF(); PointF point2 = new PointF(); char affiliation = symbolID.charAt(1); if (affiliation == ('F') || affiliation == ('A') || affiliation == ('D') || affiliation == ('M') || affiliation == ('J') || affiliation == ('K') || affiliation == ('N') || affiliation == ('L')) { point1.x = (symbolBounds.left); point1.y = symbolBounds.top + (symbolBounds.height()); point2.x = point1.x; point2.y = point1.y + symbolBounds.height(); } else { point1.x = (symbolBounds.left + 1); point1.y = symbolBounds.top + (symbolBounds.height() / 2); point2.x = point1.x; point2.y = point1.y + symbolBounds.height(); } centerPoint = new Point((int) point2.x, (int) point2.y); } ii = new ImageInfo(bmp, centerPoint, symbolBounds); if(icon == false && bmp.getByteCount() <= maxCachedEntrySize) { synchronized (_UnitCacheMutex) { if(_unitCache.get(key) == null) _unitCache.put(key, new ImageInfo(bmp, new Point(centerCache), new Rect(symbolBounds))); } } /*if(icon == false && pixelSize <= 100) { _unitCache.put(key, new ImageInfo(bmp, new Point(centerCache), new Rect(symbolBounds))); }//*/ } ImageInfo iinew = null; //////////////////////////////////////////////////////////////////// //process display modifiers if (hasDisplayModifiers) { iinew = ModifierRenderer.processUnitDisplayModifiers(ii, symbolID, modifiers, hasTextModifiers, attributes); } if (iinew != null) { ii = iinew; } iinew = null; //process test modifiers if (hasTextModifiers) { iinew = ModifierRenderer.processUnitTextModifiers(ii, symbolID, modifiers, attributes); } if (iinew != null) { ii = iinew; } iinew = null; //cleanup/////////////////////////////////////////////////////////// //bmp.recycle(); symbolBounds = null; fullBMP = null; fullBounds = null; //fullCanvas = null; fillPaint = null; framePaint = null; symbol1Paint = null; symbol2Paint = null; lookup = null; //////////////////////////////////////////////////////////////////// if (icon == true) { return ii.getSquareImageInfo(); } else { return ii; } } catch (Exception exc) { ErrorLogger.LogException("MilStdIconRenderer", "RenderUnit", exc); } return temp; } /** * * @param symbolID * @param modifiers * @return */ @SuppressWarnings("unused") public ImageInfo RenderSP(String symbolID, SparseArray<String> modifiers, SparseArray<String> attributes) { ImageInfo temp = null; String basicSymbolID = null; float fontSize = RendererSettings.getInstance().getSPFontSize(); Color lineColor = SymbolUtilities.getLineColorOfAffiliation(symbolID); Color fillColor = null;//SymbolUtilities.getFillColorOfAffiliation(symbolID); int alpha = -1; int symStd = RendererSettings.getInstance().getSymbologyStandard(); //fill character int charFillIndex = -1; //frame character int charFrameIndex = -1; //made up symbol ID for fill characters String fillID = null; SymbolDef sd = null; Paint fillPaint = null; Paint framePaint = null; SinglePointLookupInfo lookup = null; Rect symbolBounds = null; RectF fullBounds = null; Bitmap fullBMP = null; boolean drawAsIcon = false; int pixelSize = -1; boolean keepUnitRatio = true; boolean hasDisplayModifiers = false; boolean hasTextModifiers = false; int symbolOutlineWidth = RendererSettings.getInstance().getSinglePointSymbolOutlineWidth(); float scale = -999; try { if (modifiers == null) { modifiers = new SparseArray<String>(); } //get MilStdAttributes if (attributes != null && attributes.indexOfKey(MilStdAttributes.SymbologyStandard) >= 0) { symStd = Integer.parseInt(attributes.get(MilStdAttributes.SymbologyStandard)); } //get symbol info basicSymbolID = SymbolUtilities.getBasicSymbolIDStrict(symbolID); lookup = SinglePointLookup.getInstance().getSPLookupInfo(basicSymbolID, symStd); if (lookup == null)//if lookup fails, fix code/use unknown symbol code. { //if symbolID bad, do best to find a workable code if (modifiers.get(ModifiersTG.H_ADDITIONAL_INFO_1) != null) { modifiers.put(ModifiersTG.H1_ADDITIONAL_INFO_2, modifiers.get(ModifiersTG.H_ADDITIONAL_INFO_1)); } modifiers.put(ModifiersTG.H_ADDITIONAL_INFO_1, symbolID.substring(0, 10)); symbolID = "G" + SymbolUtilities.getAffiliation(symbolID) + "G" + SymbolUtilities.getStatus(symbolID) + "GPP---****X"; basicSymbolID = SymbolUtilities.getBasicSymbolIDStrict(symbolID); lookup = SinglePointLookup.getInstance().getSPLookupInfo(basicSymbolID, symStd); lineColor = SymbolUtilities.getLineColorOfAffiliation(symbolID); fillColor = null;//SymbolUtilities.getFillColorOfAffiliation(symbolID); } if (SymbolUtilities.hasDefaultFill(symbolID)) { fillColor = SymbolUtilities.getFillColorOfAffiliation(symbolID); } if (SymbolUtilities.isTGSPWithFill(symbolID)) { fillID = SymbolUtilities.getTGFillSymbolCode(symbolID); if (fillID != null) { charFillIndex = SinglePointLookup.getInstance().getCharCodeFromSymbol(fillID, symStd); } } else if (SymbolUtilities.isWeatherSPWithFill(symbolID)) { charFillIndex = charFrameIndex + 1; fillColor = SymbolUtilities.getFillColorOfWeather(symbolID); } if (attributes != null) { if (attributes.indexOfKey(MilStdAttributes.KeepUnitRatio) >= 0) { keepUnitRatio = Boolean.parseBoolean(attributes.get(MilStdAttributes.KeepUnitRatio)); } if (attributes.indexOfKey(MilStdAttributes.LineColor) >= 0) { lineColor = SymbolUtilities.getColorFromHexString(attributes.get(MilStdAttributes.LineColor)); } if (attributes.indexOfKey(MilStdAttributes.FillColor) >= 0) { fillColor = SymbolUtilities.getColorFromHexString(attributes.get(MilStdAttributes.FillColor)); } if (attributes.indexOfKey(MilStdAttributes.Alpha) >= 0) { alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha)); } if (attributes.indexOfKey(MilStdAttributes.DrawAsIcon) >= 0) { drawAsIcon = Boolean.parseBoolean(attributes.get(MilStdAttributes.DrawAsIcon)); } if (attributes.indexOfKey(MilStdAttributes.PixelSize) >= 0) { pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize)); } else { if(keepUnitRatio == true) pixelSize = 35; else { try { Rect sb = SymbolDimensions.getSymbolBounds(SymbolUtilities.getBasicSymbolIDStrict(symbolID),symStd,60.0f); pixelSize = Math.max(sb.width(), sb.height()); } catch(Exception exc){ Log.e(TAG,exc.getMessage()); exc.printStackTrace(); } } } /*if (attributes.indexOfKey(MilStdAttributes.OutlineWidth)>=0) symbolOutlineWidth = Integer.parseInt(attributes.get(MilStdAttributes.OutlineWidth));//*/ } if (drawAsIcon)//icon won't show modifiers or display icons { keepUnitRatio = false; hasDisplayModifiers = false; hasTextModifiers = false; symbolOutlineWidth = 0; } else { hasDisplayModifiers = ModifierRenderer.hasDisplayModifiers(symbolID, modifiers); hasTextModifiers = ModifierRenderer.hasTextModifiers(symbolID, modifiers, attributes); } int outlineOffset = symbolOutlineWidth; if (outlineOffset > 2) { outlineOffset = (outlineOffset - 1) / 2; } else { outlineOffset = 0; } //check symbol font size//////////////////////////////////////////// Rect rect = null; float ratio = 0; if (pixelSize > 0) { symbolBounds = SymbolDimensions.getSymbolBounds(basicSymbolID, symStd, fontSize); rect = new Rect(symbolBounds); if (keepUnitRatio == true) { //scale it somehow for consistency with units. //when SymbolSizeMedium = 80; //a pixel size of 35 = scale value of 1.0 scale = pixelSize / 35.0f; } //adjust size float fPixelSize = (float)pixelSize; ratio = Math.min((fPixelSize / rect.height()), (fPixelSize / rect.width())); } //scale overrides pixel size. if (scale != -999) { ratio = scale; } if (ratio > 0) { fontSize = fontSize * ratio; } //symbolBounds = SymbolDimensions.getSymbolBounds(basicSymbolID, symStd, fontSize); //////////////////////////////////////////////////////////////////// if (SymbolUtilities.isTGSPWithFill(symbolID) && fillColor != null) { fillPaint = new Paint(); fillPaint.setStyle(Paint.Style.FILL); fillPaint.setColor(fillColor.toARGB()); fillPaint.setTextSize(fontSize); fillPaint.setAntiAlias(true); fillPaint.setTextAlign(Align.CENTER); fillPaint.setTypeface(_tfSP); } framePaint = new Paint(); framePaint.setStyle(Paint.Style.FILL); framePaint.setColor(lineColor.toARGB()); framePaint.setTextSize(fontSize); framePaint.setAntiAlias(true); framePaint.setTextAlign(Align.CENTER); framePaint.setTypeface(_tfSP); //Check if we need to set 'N' to "ENY" if (symbolID.charAt(1) == 'H' && modifiers.indexOfKey(MilStdAttributes.DrawAsIcon) >= 0 && (Boolean.parseBoolean(modifiers.get(MilStdAttributes.DrawAsIcon)) == false)) { modifiers.put(ModifiersTG.N_HOSTILE, "ENY"); } } catch (Exception excModifiers) { ErrorLogger.LogException("MilStdIconRenderer", "RenderUnit", excModifiers); } try { ImageInfo ii = null; int intFill = -1; if (fillColor != null) { intFill = fillColor.toInt(); } String key = makeCacheKey(symbolID, lineColor.toInt(), intFill, pixelSize, keepUnitRatio, symStd); //see if it's in the cache ii = _tgCache.get(key); //if not, generate symbol if (ii == null)//*/ { //get fill character //get frame character //get symbol info charFrameIndex = -1;//SinglePointLookup.instance.getCharCodeFromSymbol(symbolID); charFillIndex = -1; if (SymbolUtilities.getStatus(symbolID).equals("A")) { charFrameIndex = lookup.getMappingA(); } else { charFrameIndex = lookup.getMappingP(); } if (SymbolUtilities.isTGSPWithFill(symbolID) && fillColor != null) { fillID = SymbolUtilities.getTGFillSymbolCode(symbolID); if (fillID != null) { charFillIndex = SinglePointLookup.getInstance().getCharCodeFromSymbol(fillID, symStd); } } //dimensions of the unit at specified font size RectF rect = new RectF(0, 0, lookup.getWidth(), lookup.getHeight()); if (fontSize != 60.0)//adjust boundaries ratio if font size is not at the default setting. { double ratio = fontSize / 60; rect = new RectF(0, 0, Math.round(rect.width() * ratio), Math.round(rect.height() * ratio)); } //matrix to place the symbol centered in the MilStdBmp Matrix matrix = new Matrix(); Point centerPoint = null; centerPoint = SymbolDimensions.getSymbolCenter(lookup.getBasicSymbolID(), rect); if (symbolOutlineWidth > 0) { //adjust matrix and centerpoint to account for outline if present matrix.postTranslate(centerPoint.x + symbolOutlineWidth, centerPoint.y + symbolOutlineWidth); centerPoint.offset(symbolOutlineWidth, symbolOutlineWidth); rect = new RectF(0, 0, (rect.width() + (symbolOutlineWidth * 2)), (rect.height() + (symbolOutlineWidth * 2))); } else { matrix.postTranslate(centerPoint.x, centerPoint.y); } //Draw glyphs to bitmap Bitmap bmp = Bitmap.createBitmap((int) (rect.width() + 0.5), (int) (rect.height() + 0.5), Config.ARGB_8888); Canvas canvas = new Canvas(bmp); symbolBounds = new Rect(0, 0, bmp.getWidth(), bmp.getHeight()); String strFill = null; String strFrame = null; if (charFillIndex > 0) { strFill = String.valueOf((char) charFillIndex); } if (charFrameIndex > 0) { strFrame = String.valueOf((char) charFrameIndex); } canvas.setMatrix(matrix); synchronized (_SinglePointFontMutex) { if (strFill != null) { canvas.drawText(strFill, 0, 0, fillPaint); } if (strFrame != null) { //try //{ RendererUtilities.renderSymbolCharacter(canvas, strFrame, 0, 0, framePaint, lineColor, symbolOutlineWidth); //} //catch( Exception e){ // logError(TAG,e); //} } } ii = new ImageInfo(bmp, centerPoint, symbolBounds); if(drawAsIcon == false && bmp.getByteCount() <= maxCachedEntrySize) { synchronized (_SinglePointCacheMutex) { if(_tgCache.get(key) == null) _tgCache.put(key, ii); } } /*if (drawAsIcon == false && pixelSize <= 100) { _tgCache.put(key, ii); }//*/ } //Process Modifiers ImageInfo iiNew = null; if (drawAsIcon == false && (hasTextModifiers || hasDisplayModifiers || SymbolUtilities.isTGSPWithIntegralText(symbolID))) { if (SymbolUtilities.isTGSPWithSpecialModifierLayout(symbolID) || SymbolUtilities.isTGSPWithIntegralText(symbolID)) { iiNew = ModifierRenderer.ProcessTGSPWithSpecialModifierLayout(ii, symbolID, modifiers, attributes, lineColor); } else { iiNew = ModifierRenderer.ProcessTGSPModifiers(ii, symbolID, modifiers, attributes, lineColor); } } if (iiNew != null) { ii = iiNew; } //cleanup //bmp.recycle(); symbolBounds = null; fullBMP = null; fullBounds = null; fillPaint = null; framePaint = null; lookup = null; if (drawAsIcon) { return ii.getSquareImageInfo(); } else { return ii; } } catch (Exception exc) { ErrorLogger.LogException("MilStdIconRenderer", "RenderSP", exc); } return null; } /** * Tries to get a valid UnitFontLookupInfo object when the symbolID is * poorly formed or there's no match in the lookup. Use this if you get a * null return value from: * "UnitFontLookupC.getInstance().getLookupInfo(symbolID)" or "CanRender" * returns false. * * @param symbolID * @return */ private UnitFontLookupInfo ResolveUnitFontLookupInfo(String symbolID, int symStd) { String id = symbolID; UnitFontLookupInfo lookup = null; String affiliation = ""; String status = ""; if (id != null && id.length() >= 10)//if lookup fails, fix code/use unknown symbol code. { StringBuilder sb = new StringBuilder(""); sb.append(id.charAt(0)); if (SymbolUtilities.hasValidAffiliation(id) == false) { sb.append('U'); affiliation = "U"; } else { sb.append(id.charAt(1)); affiliation = id.substring(1, 2); } if (SymbolUtilities.hasValidBattleDimension(id) == false) { sb.append('Z'); sb.replace(0, 1, "S"); } else { sb.append(id.charAt(2)); } if (SymbolUtilities.hasValidStatus(id) == false) { sb.append('P'); status = "P"; } else { sb.append(id.charAt(3)); status = id.substring(3, 4); } sb.append("------"); if (id.length() >= 15) { sb.append(id.substring(10, 15)); } else { sb.append("*****"); } id = sb.toString(); lookup = UnitFontLookup.getInstance().getLookupInfo(id, symStd); } else if (symbolID == null || symbolID.equals("")) { lookup = UnitFontLookup.getInstance().getLookupInfo("SUZP------*****", symStd); } return lookup; } public Bitmap getTestSymbol() { Bitmap temp = null; try { temp = Bitmap.createBitmap(70, 70, Config.ARGB_8888); Canvas canvas = new Canvas(temp); if (canvas.isHardwareAccelerated()) { System.out.println("HW acceleration supported"); } //canvas.drawColor(Color.WHITE); //Typeface tf = Typeface.createFromAsset(_am, "fonts/unitfonts.ttf"); Typeface tf = _tfUnits; Paint fillPaint = new Paint(); fillPaint.setStyle(Paint.Style.FILL); fillPaint.setColor(Color.CYAN.toInt()); fillPaint.setTextSize(50); fillPaint.setAntiAlias(true); fillPaint.setTextAlign(Align.CENTER); fillPaint.setTypeface(tf); Paint framePaint = new Paint(); framePaint.setStyle(Paint.Style.FILL); framePaint.setColor(Color.BLACK.toInt()); framePaint.setTextSize(50); framePaint.setAntiAlias(true); framePaint.setTextAlign(Align.CENTER); framePaint.setTypeface(tf); Paint symbolPaint = new Paint(); symbolPaint.setStyle(Paint.Style.FILL); symbolPaint.setColor(Color.BLACK.toInt()); symbolPaint.setTextSize(50); symbolPaint.setAntiAlias(true); symbolPaint.setTextAlign(Align.CENTER); symbolPaint.setTypeface(tf); String strFill = String.valueOf((char) 800); String strFrame = String.valueOf((char) 801); String strSymbol = String.valueOf((char) 1121); canvas.drawText(strFill, 35, 35, fillPaint); canvas.drawText(strFrame, 35, 35, framePaint); canvas.drawText(strSymbol, 35, 35, symbolPaint); FontMetrics mf = framePaint.getFontMetrics(); float height = mf.bottom - mf.top; float width = fillPaint.measureText(strFrame); Log.i(TAG, "top: " + String.valueOf(mf.top)); Log.i(TAG, "bottom: " + String.valueOf(mf.bottom)); Log.i(TAG, "ascent: " + String.valueOf(mf.ascent)); Log.i(TAG, "descent: " + String.valueOf(mf.descent)); Log.i(TAG, "leading: " + String.valueOf(mf.leading)); Log.i(TAG, "width: " + String.valueOf(width)); Log.i(TAG, "height: " + String.valueOf(height)); } catch (Exception exc) { Log.e(TAG, exc.getMessage()); Log.e(TAG, getStackTrace(exc)); } return temp; }//*/ public static String makeCacheKey(String symbolID, int lineColor, int fillColor, int iconColor, int size, boolean keepUnitRatio, int symStd) { String key = symbolID.substring(0, 10) + String.valueOf(lineColor) + String.valueOf(fillColor) + String.valueOf(iconColor) + String.valueOf(size) + String.valueOf(keepUnitRatio) + String.valueOf(symStd); return key; } public static String makeCacheKey(String symbolID, int lineColor, int fillColor, int size, boolean keepUnitRatio, int symStd) { String key = symbolID.substring(0, 10) + String.valueOf(lineColor) + String.valueOf(fillColor) + String.valueOf(size) + String.valueOf(keepUnitRatio) + String.valueOf(symStd); return key; } public void logError(String tag, Throwable thrown) { if (tag == null || tag.equals("")) { tag = "singlePointRenderer"; } String message = thrown.getMessage(); String stack = getStackTrace(thrown); if (message != null) { Log.e(tag, message); } if (stack != null) { Log.e(tag, stack); } } public String getStackTrace(Throwable thrown) { try { if (thrown != null) { if (thrown.getStackTrace() != null) { String eol = System.getProperty("line.separator"); StringBuilder sb = new StringBuilder(); sb.append(thrown.toString()); sb.append(eol); for (StackTraceElement element : thrown.getStackTrace()) { sb.append(" at "); sb.append(element); sb.append(eol); } return sb.toString(); } else { return thrown.getMessage() + "- no stack trace"; } } else { return "no stack trace"; } } catch (Exception exc) { Log.e("getStackTrace", exc.getMessage()); } return thrown.getMessage(); }//*/ /* private static String PrintList(ArrayList list) { String message = ""; for(Object item : list) { message += item.toString() + "\n"; } return message; }//*/ /* private static String PrintObjectMap(Map<String, Object> map) { Iterator<Object> itr = map.values().iterator(); String message = ""; String temp = null; while(itr.hasNext()) { temp = String.valueOf(itr.next()); if(temp != null) message += temp + "\n"; } //ErrorLogger.LogMessage(message); return message; }//*/ @Override public void onSettingsChanged(SettingsChangedEvent sce) { if(sce != null && sce.getEventType().equals(SettingsChangedEvent.EventType_FontChanged)) { synchronized (_modifierFont) { _modifierFont = RendererSettings.getInstance().getModiferFont(); _modifierOutlineFont = RendererSettings.getInstance().getModiferFont(); FontMetrics fm = new FontMetrics(); fm = _modifierFont.getFontMetrics(); _modifierDescent = fm.descent; //_modifierFontHeight = fm.top + fm.bottom; _modifierFontHeight = fm.bottom - fm.top; _modifierFont.setStrokeWidth(RendererSettings.getInstance().getTextOutlineWidth()); _modifierOutlineFont.setColor(Color.white.toInt()); _deviceDPI = RendererSettings.getInstance().getDeviceDPI(); ModifierRenderer.setModifierFont(_modifierFont, _modifierFontHeight, _modifierDescent); } } if(sce != null && sce.getEventType().equals(SettingsChangedEvent.EventType_CacheSizeChanged)) { int cSize = RendererSettings.getInstance().getCacheSize()/2; //adjust unit cache if(cSize != cacheSize) { synchronized(_unitCache) { _unitCache.evictAll(); _unitCache = new LruCache<String, ImageInfo>(cSize) { @Override protected int sizeOf(String key, ImageInfo ii) { return ii.getImage().getByteCount();// / 1024; } }; } //adjust tg cache synchronized(_tgCache) { _tgCache.evictAll(); _tgCache = new LruCache<String, ImageInfo>(cSize) { @Override protected int sizeOf(String key, ImageInfo ii) { return ii.getImage().getByteCount();// / 1024; } }; } cacheSize = cSize; if(cacheSize >= 5) maxCachedEntrySize = cacheSize / 5; else maxCachedEntrySize = 1; } } } }