001package armyc2.c5isr.renderer;
002
003import android.graphics.Bitmap;
004import android.graphics.Bitmap.Config;
005import android.graphics.Canvas;
006import android.graphics.Paint;
007import android.graphics.Paint.FontMetrics;
008import android.graphics.Point;
009import android.graphics.PointF;
010import android.graphics.Rect;
011import android.graphics.RectF;
012import android.util.Log;
013import android.util.LruCache;
014
015import com.caverock.androidsvg.SVG;
016
017import java.util.HashMap;
018import java.util.Map;
019
020import armyc2.c5isr.renderer.utilities.Color;
021import armyc2.c5isr.renderer.utilities.DrawRules;
022import armyc2.c5isr.renderer.utilities.ErrorLogger;
023import armyc2.c5isr.renderer.utilities.ImageInfo;
024import armyc2.c5isr.renderer.utilities.MSInfo;
025import armyc2.c5isr.renderer.utilities.MSLookup;
026import armyc2.c5isr.renderer.utilities.MilStdAttributes;
027import armyc2.c5isr.renderer.utilities.Modifiers;
028import armyc2.c5isr.renderer.utilities.RectUtilities;
029import armyc2.c5isr.renderer.utilities.RendererSettings;
030import armyc2.c5isr.renderer.utilities.RendererUtilities;
031import armyc2.c5isr.renderer.utilities.SVGInfo;
032import armyc2.c5isr.renderer.utilities.SVGLookup;
033import armyc2.c5isr.renderer.utilities.SettingsChangedEvent;
034import armyc2.c5isr.renderer.utilities.SettingsChangedEventListener;
035import armyc2.c5isr.renderer.utilities.SymbolDimensionInfo;
036import armyc2.c5isr.renderer.utilities.SymbolID;
037import armyc2.c5isr.renderer.utilities.SymbolUtilities;
038
039public class SinglePointRenderer implements SettingsChangedEventListener
040{
041
042    private final String TAG = "SinglePointRenderer";
043    private static SinglePointRenderer _instance = null;
044
045    private final Object _SinglePointCacheMutex = new Object();
046    private final Object _UnitCacheMutex = new Object();
047
048    private final Object _modifierFontMutex = new Object();
049    private Paint _modifierFont = new Paint();
050    private Paint _modifierOutlineFont = new Paint();
051    private float _modifierDescent = 2;
052    private float _modifierFontHeight = 10;
053    private int _deviceDPI = 72;
054
055    //private LruCache<String, ImageInfo> _unitCache = new LruCache<String, ImageInfo>(15);
056    //private LruCache<String, ImageInfo> _tgCache = new LruCache<String, ImageInfo>(7);
057    private LruCache<String, ImageInfo> _unitCache = new LruCache<String, ImageInfo>(1024);
058    private LruCache<String, ImageInfo> _tgCache = new LruCache<String, ImageInfo>(1024);
059    private final int maxMemory = (int) (Runtime.getRuntime().maxMemory());// / 1024);
060    private int cacheSize = 5;//RendererSettings.getInstance().getCacheSize() / 2;
061    private int maxCachedEntrySize = cacheSize / 5;
062    private boolean cacheEnabled = RendererSettings.getInstance().getCacheEnabled();
063
064    private SinglePointRenderer()
065    {
066        RendererSettings.getInstance().addEventListener(this);
067        
068        //get modifier font values.
069        onSettingsChanged(new SettingsChangedEvent(SettingsChangedEvent.EventType_FontChanged));
070        //set cache
071        onSettingsChanged(new SettingsChangedEvent(SettingsChangedEvent.EventType_CacheSizeChanged));
072
073    }
074
075    public static synchronized SinglePointRenderer getInstance()
076    {
077        if (_instance == null)
078        {
079            _instance = new SinglePointRenderer();
080        }
081
082        return _instance;
083    }
084
085    /**
086     *
087     * @param symbolID
088     * @param modifiers
089     * @return
090     */
091    public ImageInfo RenderUnit(String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
092    {
093        Color lineColor = SymbolUtilities.getLineColorOfAffiliation(symbolID);
094        Color fillColor = SymbolUtilities.getFillColorOfAffiliation(symbolID);
095        Color iconColor = null;
096
097        int alpha = -1;
098
099
100        //SVG values
101        String frameID = null;
102        String iconID = null;
103        String mod1ID = null;
104        String mod2ID = null;
105        SVGInfo siFrame = null;
106        SVGInfo siIcon = null;
107        SVGInfo siMod1 = null;
108        SVGInfo siMod2 = null;
109        SVG mySVG = null;
110        int top = 0;
111        int left = 0;
112        int width = 0;
113        int height = 0;
114        String svgStart = null;
115        String strSVG = null;
116        String strSVGFrame = null;
117
118
119        Rect symbolBounds = null;
120        Rect fullBounds = null;
121        Bitmap fullBMP = null;
122
123        boolean hasDisplayModifiers = false;
124        boolean hasTextModifiers = false;
125
126        int pixelSize = -1;
127        boolean keepUnitRatio = true;
128        boolean icon = false;
129        boolean noFrame = false;
130
131        int ver = SymbolID.getVersion(symbolID);
132
133        // <editor-fold defaultstate="collapsed" desc="Parse Attributes">
134        try
135        {
136
137            if (attributes.containsKey(MilStdAttributes.PixelSize))
138            {
139                pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize));
140            }
141            else
142            {
143                pixelSize = RendererSettings.getInstance().getDefaultPixelSize();
144            }
145
146            if (attributes.containsKey(MilStdAttributes.KeepUnitRatio))
147            {
148                keepUnitRatio = Boolean.parseBoolean(attributes.get(MilStdAttributes.KeepUnitRatio));
149            }
150
151            if (attributes.containsKey(MilStdAttributes.DrawAsIcon))
152            {
153                icon = Boolean.parseBoolean(attributes.get(MilStdAttributes.DrawAsIcon));
154            }
155
156            if (icon)//icon won't show modifiers or display icons
157            {
158                //TODO: symbolID modifications as necessary
159                keepUnitRatio = false;
160                hasDisplayModifiers = false;
161                hasTextModifiers = false;
162                //symbolID = symbolID.substring(0, 10) + "-----";
163            }
164            else
165            {
166                hasDisplayModifiers = ModifierRenderer.hasDisplayModifiers(symbolID, modifiers);
167                hasTextModifiers = ModifierRenderer.hasTextModifiers(symbolID, modifiers);
168            }
169
170            if (attributes.containsKey(MilStdAttributes.LineColor))
171            {
172                lineColor = new Color(attributes.get(MilStdAttributes.LineColor));
173            }
174            if (attributes.containsKey(MilStdAttributes.FillColor))
175            {
176                fillColor = new Color(attributes.get(MilStdAttributes.FillColor));
177            }
178            if (attributes.containsKey(MilStdAttributes.IconColor))
179            {
180                iconColor = new Color(attributes.get(MilStdAttributes.IconColor));
181            }//*/
182            if (attributes.containsKey(MilStdAttributes.Alpha))
183            {
184                alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
185            }
186
187        }
188        catch (Exception excModifiers)
189        {
190            ErrorLogger.LogException("SinglePointRenderer", "RenderUnit", excModifiers);
191        }
192        // </editor-fold>
193
194        try
195        {
196
197            ImageInfo ii = null;
198            String key = makeCacheKey(symbolID, lineColor.toInt(), fillColor.toInt(), String.valueOf(iconColor),pixelSize, keepUnitRatio, false);
199
200            //see if it's in the cache
201            if(_unitCache != null) {
202                ii = _unitCache.get(key);
203                //safety check in case bitmaps are getting recycled while still in the LRU cache
204                if (ii != null && ii.getImage() != null && ii.getImage().isRecycled()) {
205                    synchronized (_UnitCacheMutex) {
206                        _unitCache.remove(key);
207                        ii = null;
208                    }
209                }
210            }
211            //if not, generate symbol
212            if (ii == null)//*/
213            {
214                int version = SymbolID.getVersion(symbolID);
215                //Get SVG pieces of symbol
216                frameID = SVGLookup.getFrameID(symbolID);
217                iconID = SVGLookup.getMainIconID(symbolID);
218                mod1ID = SVGLookup.getMod1ID(symbolID);
219                mod2ID = SVGLookup.getMod2ID(symbolID);
220                siFrame = SVGLookup.getInstance().getSVGLInfo(frameID, version);
221                siIcon = SVGLookup.getInstance().getSVGLInfo(iconID, version);
222
223                if(siFrame == null)
224                {
225                    frameID = SVGLookup.getFrameID(SymbolUtilities.reconcileSymbolID(symbolID));
226                    siFrame = SVGLookup.getInstance().getSVGLInfo(frameID, version);
227                    if(siFrame == null)//still no match, get unknown frame
228                    {
229                        frameID = SVGLookup.getFrameID(SymbolID.setSymbolSet(symbolID,SymbolID.SymbolSet_Unknown));
230                        siFrame = SVGLookup.getInstance().getSVGLInfo(frameID, version);
231                    }
232                }
233
234                if(siIcon == null)
235                {
236                        if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_Unknown)
237                            siIcon = SVGLookup.getInstance().getSVGLInfo("00000000", version);//question mark
238                        /*else if(iconID.substring(2,8).equals("000000")==false && MSLookup.getInstance().getMSLInfo(symbolID) == null)
239                            siIcon = SVGLookup.getInstance().getSVGLInfo("98100000", version);//inverted question mark//*/
240                }
241
242                if(RendererSettings.getInstance().getScaleMainIcon())
243                    siIcon = RendererUtilities.scaleIcon(symbolID,siIcon);
244
245                siMod1 = SVGLookup.getInstance().getSVGLInfo(mod1ID, version);
246                siMod2 = SVGLookup.getInstance().getSVGLInfo(mod2ID, version);
247                top = Math.round(siFrame.getBbox().top);
248                left = Math.round(siFrame.getBbox().left);
249                width = Math.round(siFrame.getBbox().width());
250                height = Math.round(siFrame.getBbox().height());
251                if(siFrame.getBbox().bottom > 400)
252                    svgStart = "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 612 792\">";
253                else
254                    svgStart = "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 400 400\">";
255
256                //update line and fill color of frame SVG
257                if(lineColor != null || fillColor != null)
258                    strSVGFrame = RendererUtilities.setSVGFrameColors(symbolID,siFrame.getSVG(),lineColor,fillColor);
259                else
260                    strSVGFrame = siFrame.getSVG();
261
262                if(frameID.equals("octagon"))//for the 1 unit symbol that doesn't have a frame: 30 + 15000
263                {
264                    noFrame = true;
265                    strSVGFrame = strSVGFrame.replaceFirst("<g id=\"octagon\">", "<g id=\"octagon\" display=\"none\">");
266                }
267
268
269                //get SVG dimensions and target dimensions
270                symbolBounds = RectUtilities.makeRect(left,top,width,height);
271                Rect rect = new Rect(symbolBounds);
272                float ratio = -1;
273
274                if (pixelSize > 0 && keepUnitRatio == true)
275                {
276                    float heightRatio = SymbolUtilities.getUnitRatioHeight(symbolID);
277                    float widthRatio = SymbolUtilities.getUnitRatioWidth(symbolID);
278
279                    if(noFrame == true)//using octagon with display="none" as frame for a 1x1 shape
280                    {
281                        heightRatio = 1.0f;
282                        widthRatio = 1.0f;
283                    }
284
285                    if (heightRatio > widthRatio)
286                    {
287                        pixelSize = (int) ((pixelSize / 1.5f) * heightRatio);
288                    }
289                    else
290                    {
291                        pixelSize = (int) ((pixelSize / 1.5f) * widthRatio);
292                    }
293                }
294                if (pixelSize > 0)
295                {
296                    float p = pixelSize;
297                    float h = rect.height();
298                    float w = rect.width();
299
300                    ratio = Math.min((p / h), (p / w));
301
302                    symbolBounds = RectUtilities.makeRect(0f, 0f, w * ratio, h * ratio);
303                }
304
305                //center of octagon is the center of all unit symbols
306                Point centerOctagon = new Point(306, 396);
307                centerOctagon.offset(-left,-top);//offset for the symbol bounds x,y
308                //scale center point by same ratio as the symbol
309                centerOctagon = new Point((int)(centerOctagon.x * ratio), (int)(centerOctagon.y * ratio));
310
311                //set centerpoint of the image
312                Point centerPoint = centerOctagon;
313                Point centerCache = new Point(centerOctagon.x, centerOctagon.y);
314
315                //y offset to get centerpoint so we set back to zero when done.
316                symbolBounds.top = 0;
317
318                //Create destination BMP
319                Bitmap bmp = Bitmap.createBitmap(symbolBounds.width(), symbolBounds.height(), Config.ARGB_8888);
320                Canvas canvas = new Canvas(bmp);
321
322                //draw unit from SVG
323                StringBuilder sb = new StringBuilder();
324                sb.append(svgStart);
325
326                if(strSVGFrame != null)
327                    sb.append(strSVGFrame);
328
329                String color = "";
330                String strokeFill = "";
331                if(iconColor != null)
332                {
333                    //make sure string is properly formatted.
334                    color = RendererUtilities.colorToHexString(iconColor,false);
335                    if(color != null && color != "#000000" && color != "")
336                        strokeFill = " fill=\"" + color + "\" ";
337                    else
338                        color = null;
339                }
340                String unit = "<g" + strokeFill + ">";
341                if (siIcon != null)
342                    unit += (siIcon.getSVG());
343                if (siMod1 != null)
344                    unit += (siMod1.getSVG());
345                if (siMod2 != null)
346                    unit += (siMod2.getSVG());
347                if(iconColor != null && color != null && color != "")
348                    unit = unit.replaceAll("#000000",color);
349                sb.append(unit + "</g>");
350
351                sb.append("</svg>");
352
353                strSVG = sb.toString();
354
355                mySVG = SVG.getFromString(strSVG);
356                mySVG.setDocumentViewBox(left,top,width,height);
357                mySVG.renderToCanvas(canvas);
358
359
360                //adjust centerpoint for HQStaff if present
361                if (SymbolUtilities.isHQ(symbolID))
362                {
363                    PointF point1 = new PointF();
364                    PointF point2 = new PointF();
365                    int affiliation = SymbolID.getAffiliation(symbolID);
366                    int ss = SymbolID.getStandardIdentity(symbolID);
367                    if (affiliation == SymbolID.StandardIdentity_Affiliation_Friend
368                            || affiliation == SymbolID.StandardIdentity_Affiliation_AssumedFriend
369                            || affiliation == SymbolID.StandardIdentity_Affiliation_Neutral
370                            || ss == 15 || ss == 16)//exercise joker or faker
371                    {
372                        point1.x = (symbolBounds.left);
373                        point1.y = symbolBounds.top + (symbolBounds.height());
374                        point2.x = point1.x;
375                        point2.y = point1.y + symbolBounds.height();
376                    }
377                    else
378                    {
379                        point1.x = (symbolBounds.left + 1);
380                        point1.y = symbolBounds.top + (symbolBounds.height() / 2);
381                        point2.x = point1.x;
382                        point2.y = point1.y + symbolBounds.height();
383                    }
384                    centerPoint = new Point((int) point2.x, (int) point2.y);
385                }
386
387                ii = new ImageInfo(bmp, centerPoint, symbolBounds);
388
389                if(cacheEnabled && icon == false && bmp.getAllocationByteCount() <= maxCachedEntrySize)
390                {
391                    synchronized (_UnitCacheMutex)
392                    {
393                        if(_unitCache != null && _unitCache.get(key) == null)
394                            _unitCache.put(key, new ImageInfo(bmp, new Point(centerCache), new Rect(symbolBounds)));
395                    }
396                }
397
398                /*if(icon == false && pixelSize <= 100)
399                {
400                    _unitCache.put(key, new ImageInfo(bmp, new Point(centerCache), new Rect(symbolBounds)));
401                }//*/
402            }
403
404            ImageInfo iiNew = null;
405            SymbolDimensionInfo sdiTemp = null;
406            ////////////////////////////////////////////////////////////////////
407            //process display modifiers
408            if (hasDisplayModifiers)
409            {
410                sdiTemp = ModifierRenderer.processUnitDisplayModifiers( ii, symbolID, modifiers, hasTextModifiers, attributes);
411                iiNew = (sdiTemp instanceof ImageInfo ? (ImageInfo)sdiTemp : null);
412                sdiTemp = null;
413            }
414
415            if (iiNew != null)
416            {
417                ii = iiNew;
418            }
419            iiNew = null;
420
421            //process text modifiers
422            if (hasTextModifiers)
423            {
424                sdiTemp = ModifierRenderer.processSPTextModifiers(ii, symbolID, modifiers, attributes);
425            }
426
427            iiNew = (sdiTemp instanceof ImageInfo ? (ImageInfo)sdiTemp : null);
428            if (iiNew != null)
429            {
430                ii = iiNew;
431            }
432            iiNew = null;
433
434            if(modifiers != null)
435                ii = (ImageInfo) ModifierRenderer.processSpeedLeader(ii,symbolID,modifiers,attributes);
436
437            //cleanup///////////////////////////////////////////////////////////
438            //bmp.recycle();
439            symbolBounds = null;
440            fullBMP = null;
441            fullBounds = null;
442            mySVG = null;
443            ////////////////////////////////////////////////////////////////////
444
445            if (icon == true)
446            {
447                return ii.getSquareImageInfo();
448            }
449            else
450            {
451                return ii;
452            }
453
454        }
455        catch (Exception exc)
456        {
457            ErrorLogger.LogException("SinglePointRenderer", "RenderUnit", exc);
458        }
459        return null;
460    }
461
462    /**
463     *
464     * @param symbolID
465     * @param modifiers
466     * @return
467     */
468    @SuppressWarnings("unused")
469    public ImageInfo RenderSP(String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
470    {
471        ImageInfo temp = null;
472        String basicSymbolID = null;
473
474        Color lineColor = SymbolUtilities.getDefaultLineColor(symbolID);
475        Color fillColor = null;//SymbolUtilities.getFillColorOfAffiliation(symbolID);
476
477        int alpha = -1;
478
479
480        //SVG rendering variables
481        MSInfo msi = null;
482        String iconID = null;
483        SVGInfo siIcon = null;
484        String mod1ID = null;
485        SVGInfo siMod1 = null;
486        int top = 0;
487        int left = 0;
488        int width = 0;
489        int height = 0;
490        String svgStart = null;
491        String strSVG = null;
492        SVG mySVG = null;
493
494        float ratio = 0;
495
496        Rect symbolBounds = null;
497        RectF fullBounds = null;
498        Bitmap fullBMP = null;
499
500        boolean drawAsIcon = false;
501        int pixelSize = -1;
502        boolean keepUnitRatio = true;
503        boolean hasDisplayModifiers = false;
504        boolean hasTextModifiers = false;
505        boolean drawCustomOutline = false;
506
507        msi = MSLookup.getInstance().getMSLInfo(symbolID);
508        int ss = SymbolID.getSymbolSet(symbolID);
509        int ec = SymbolID.getEntityCode(symbolID);
510        int mod1 = 0;
511        int drawRule = 0;
512        if(msi!=null){drawRule = msi.getDrawRule();}
513        boolean hasAPFill = false;
514        if(RendererSettings.getInstance().getActionPointDefaultFill()) {
515            if (SymbolUtilities.isActionPoint(symbolID) || //action points
516                    ec/100 == 2135 || //sonobuoy
517                    ec == 180100 || ec == 180200 || ec == 180400) //ACP, CCP, PUP
518            {
519                if (SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_ControlMeasure) {
520                    lineColor = Color.BLACK;
521                    hasAPFill = true;
522                }
523            }
524        }
525
526        try
527        {
528            if (modifiers == null)
529            {
530                modifiers = new HashMap<>();
531            }
532
533
534            //get symbol info
535
536            msi = MSLookup.getInstance().getMSLInfo(symbolID);
537
538            if (msi == null)//if lookup fails, fix code/use unknown symbol code.
539            {
540                //TODO: change symbolID to Action Point with bad symbolID  in the T or H field
541            }
542
543            /* Fills built into SVG
544            if (SymbolUtilities.hasDefaultFill(symbolID))
545            {
546                fillColor = SymbolUtilities.getFillColorOfAffiliation(symbolID);
547            }
548            if (SymbolUtilities.isTGSPWithFill(symbolID))
549            {
550                fillID = SymbolUtilities.getTGFillSymbolCode(symbolID);
551                if (fillID != null)
552                {
553                    charFillIndex = SinglePointLookup.getInstance().getCharCodeFromSymbol(fillID, symStd);
554                }
555            }
556            else if (SymbolUtilities.isWeatherSPWithFill(symbolID))
557            {
558                charFillIndex = charFrameIndex + 1;
559                fillColor = SymbolUtilities.getFillColorOfWeather(symbolID);
560
561            }//*/
562
563            if (attributes != null)
564            {
565                if (attributes.containsKey(MilStdAttributes.KeepUnitRatio))
566                {
567                    keepUnitRatio = Boolean.parseBoolean(attributes.get(MilStdAttributes.KeepUnitRatio));
568                }
569
570                if (attributes.containsKey(MilStdAttributes.LineColor))
571                {
572                    lineColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.LineColor));
573                }
574
575                if (attributes.containsKey(MilStdAttributes.FillColor))
576                {
577                    fillColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.FillColor));
578                }
579
580                if (attributes.containsKey(MilStdAttributes.Alpha))
581                {
582                    alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
583                }
584
585                if (attributes.containsKey(MilStdAttributes.DrawAsIcon))
586                {
587                    drawAsIcon = Boolean.parseBoolean(attributes.get(MilStdAttributes.DrawAsIcon));
588                }
589
590                if (attributes.containsKey(MilStdAttributes.PixelSize))
591                {
592                    pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize));
593                }
594                else
595                {
596                    pixelSize = RendererSettings.getInstance().getDefaultPixelSize();
597                }
598                /*if(keepUnitRatio == true && msi.getSymbolSet() == SymbolID.SymbolSet_ControlMeasure && msi.getGeometry().equalsIgnoreCase("point"))
599                {
600                    if(msi.getDrawRule() == DrawRules.POINT1)//Action Points
601                        pixelSize = (int)Math.ceil((pixelSize/1.5f) * 2.0f);
602                    else if(SymbolID.getSymbolSet(symbolID)==SymbolID.SymbolSet_ControlMeasure &&
603                            ec/100 == 2135)//Sonobuoy
604                    {
605                        pixelSize = (int)Math.ceil((pixelSize/1.5f) * 2.0f);
606                    }
607                    else
608                        pixelSize = (int)Math.ceil((pixelSize/1.5f) * 1.2f);
609                }//*/
610
611                if(!(drawAsIcon==true || hasAPFill==true))//don't outline icons because they're not going on the map and icons with fills don't need it
612                {
613                    if (attributes.containsKey(MilStdAttributes.OutlineSymbol))
614                        drawCustomOutline = Boolean.parseBoolean(attributes.get(MilStdAttributes.OutlineSymbol));
615                    else
616                        drawCustomOutline = RendererSettings.getInstance().getOutlineSPControlMeasures();
617
618                    //Protection of Cultural Property doesn't get outlined
619                    if(ss==25 && ec >= 360000 && ec < 360400)
620                        drawCustomOutline = false;
621                }
622
623                if(SymbolUtilities.isMultiPoint(symbolID))
624                    drawCustomOutline=false;//icon previews for multipoints do not need outlines since they shouldn't be on the map
625            }
626
627            if (drawAsIcon)//icon won't show modifiers or display icons
628            {
629                keepUnitRatio = false;
630                hasDisplayModifiers = false;
631                hasTextModifiers = false;
632                drawCustomOutline = false;
633            }
634            else
635            {
636                hasDisplayModifiers = ModifierRenderer.hasDisplayModifiers(symbolID, modifiers);
637                hasTextModifiers = ModifierRenderer.hasTextModifiers(symbolID, modifiers);
638            }
639
640            //Check if we need to set 'N' to "ENY"
641            int aff = SymbolID.getAffiliation(symbolID);
642            //int ss = msi.getSymbolSet();
643            if (ss == SymbolID.SymbolSet_ControlMeasure &&
644                    (aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker ||
645                 aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker ) &&
646                    modifiers.containsKey(Modifiers.N_HOSTILE) &&
647                    drawAsIcon == false)
648            {
649                modifiers.put(Modifiers.N_HOSTILE, "ENY");
650            }
651
652        }
653        catch (Exception excModifiers)
654        {
655            ErrorLogger.LogException("SinglePointRenderer", "RenderSP", excModifiers);
656        }
657
658        try
659        {
660            ImageInfo ii = null;
661            int intFill = -1;
662            if (fillColor != null)
663            {
664                intFill = fillColor.toInt();
665            }
666
667
668            if(msi.getSymbolSet() != SymbolID.SymbolSet_ControlMeasure)
669                lineColor = Color.BLACK;//color isn't black but should be fine for weather since colors can't be user defined.
670
671
672
673            if (SymbolID.getSymbolSet(symbolID)==SymbolID.SymbolSet_ControlMeasure && SymbolID.getEntityCode(symbolID) == 270701)//static depiction
674            {
675                //add mine fill to image
676                mod1 = SymbolID.getModifier1(symbolID);
677                if (!(mod1 >= 13 && mod1 <= 50))
678                    symbolID = SymbolID.setModifier1(symbolID, 13);
679            }
680
681            String key = makeCacheKey(symbolID, lineColor.toInt(), intFill, pixelSize, keepUnitRatio, drawCustomOutline);
682
683            //see if it's in the cache
684            if(_tgCache != null) {
685                ii = _tgCache.get(key);
686                //safety check in case bitmaps are getting recycled while still in the LRU cache
687                if (ii != null && ii.getImage() != null && ii.getImage().isRecycled()) {
688                    synchronized (_SinglePointCacheMutex) {
689                        _tgCache.remove(key);
690                        ii = null;
691                    }
692                }
693            }
694
695            //if not, generate symbol.
696            if (ii == null)//*/
697            {
698                int version = SymbolID.getVersion(symbolID);
699                //check symbol size////////////////////////////////////////////
700                Rect rect = null;
701                iconID = SVGLookup.getMainIconID(symbolID);
702                siIcon = SVGLookup.getInstance().getSVGLInfo(iconID, version);
703                if(siIcon==null) {
704                    return null;
705                }
706                mod1ID = SVGLookup.getMod1ID(symbolID);
707                siMod1 = SVGLookup.getInstance().getSVGLInfo(mod1ID, version);
708                float borderPadding = 0;
709                if (drawCustomOutline) {
710                    borderPadding = RendererUtilities.findWidestStrokeWidth(siIcon.getSVG());
711                }
712                top = (int)Math.floor(siIcon.getBbox().top);
713                left = (int)Math.floor(siIcon.getBbox().left);
714                width = (int)Math.ceil(siIcon.getBbox().width() + (siIcon.getBbox().left - left));
715                height = (int)Math.ceil(siIcon.getBbox().height() + (siIcon.getBbox().top - top));
716                if(siIcon.getBbox().bottom > 400)
717                    svgStart = "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 612 792\">";
718                else
719                    svgStart = "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 400 400\">";
720
721                String strSVGIcon = null;
722
723                if(keepUnitRatio)
724                {
725                    double scaler = Math.max(width/(float)height, height/(float)width);
726                    if (scaler < 1.2)
727                        scaler = 1.2;
728                    if (scaler > 2)
729                        scaler = 2;
730
731                    if(!SymbolUtilities.isCBRNEvent(symbolID))
732                        pixelSize = (int) Math.ceil((pixelSize / 1.5f) * scaler);
733
734                    /*
735                    double min = Math.min(width/(float)height, height/(float)width);
736                    if (min < 0.6)//Rectangle
737                        pixelSize = (int) Math.ceil((pixelSize / 1.5f) * 2.0f);
738                    else if(min < 0.85)
739                        pixelSize = (int) Math.ceil((pixelSize / 1.5f) * 1.8f);
740                    else //more of a square
741                        pixelSize = (int) Math.ceil((pixelSize / 1.5f) * 1.2f);//*/
742                }
743
744                if(hasAPFill) //action points and a few others //Sonobuoy //ACP, CCP, PUP
745                {
746                    String apFill;
747                    if(fillColor != null)
748                        apFill = RendererUtilities.colorToHexString(fillColor,false);
749                    else
750                        apFill = RendererUtilities.colorToHexString(SymbolUtilities.getFillColorOfAffiliation(symbolID),false);
751                    siIcon = new SVGInfo(siIcon.getID(),siIcon.getBbox(), siIcon.getSVG().replaceAll("fill=\"none\"","fill=\"" + apFill + "\""));
752                }
753
754                //Set dash array depending on affiliation and status
755                siIcon = RendererUtilities.setAffiliationDashArray(symbolID, siIcon);
756
757                //update line and fill color of frame SVG
758                if(msi.getSymbolSet() == SymbolID.SymbolSet_ControlMeasure && (lineColor != null || fillColor != null)) {
759                    if (drawCustomOutline) {
760                        // create outline with larger stroke-width first (if selected)
761                        strSVGIcon = RendererUtilities.setSVGSPCMColors(symbolID, siIcon.getSVG(), RendererUtilities.getIdealOutlineColor(lineColor), fillColor, true);
762                    }
763
764                    // append normal symbol SVG to be layered on top of outline
765                    strSVGIcon += RendererUtilities.setSVGSPCMColors(symbolID, siIcon.getSVG(), lineColor, fillColor, false);
766                }
767                else//weather symbol (don't change color of weather graphics)
768                    strSVGIcon = siIcon.getSVG();
769
770                //If symbol is Static Depiction, add internal mine graphic based on sector modifier 1
771                if(SymbolID.getEntityCode(symbolID) == 270701 && siMod1 != null)
772                {
773                    if (drawCustomOutline) {
774                        // create outline with larger stroke-width first (if selected)
775                        strSVGIcon += RendererUtilities.setSVGSPCMColors(mod1ID, siMod1.getSVG(), RendererUtilities.getIdealOutlineColor(RendererUtilities.getColorFromHexString("#00A651")), RendererUtilities.getColorFromHexString("#00A651"), true);
776                    }
777                    //strSVGIcon += siMod1.getSVG();
778                    strSVGIcon += RendererUtilities.setSVGSPCMColors(mod1ID, siMod1.getSVG(), lineColor, fillColor, false);
779                }
780
781                if (pixelSize > 0)
782                {
783                    symbolBounds = RectUtilities.makeRect(left,top,width,height);
784                    rect = new Rect(symbolBounds);
785
786                    //adjust size
787                    float p = pixelSize;
788                    float h = rect.height();
789                    float w = rect.width();
790
791                    ratio = Math.min((p / h), (p / w));
792
793                    symbolBounds = RectUtilities.makeRect(0f, 0f, w * ratio, h * ratio);
794
795                    //make sure border padding isn't excessive.
796                    w = symbolBounds.width();
797                    h = symbolBounds.height();
798
799                    if(borderPadding > 0) {
800                        if (h / (h + borderPadding) > 0.10) {
801                            borderPadding = (float) (h * 0.1);
802                        } else if (w / (w + borderPadding) > 0.10) {
803                            borderPadding = (float) (w * 0.1);
804                        }
805                    }
806                }
807
808                //Draw glyphs to bitmap
809                Bitmap bmp = Bitmap.createBitmap((symbolBounds.width() + Math.round(borderPadding)), (symbolBounds.height() + Math.round(borderPadding)), Config.ARGB_8888);
810                Canvas canvas = new Canvas(bmp);
811
812                symbolBounds = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
813
814                //grow size SVG to accommodate the outline we added
815                int offset = 0;
816                if(drawCustomOutline)
817                {
818                    RectUtilities.grow(rect, 2);
819                    offset = 4;
820
821                    //RectUtilities.grow(rect, Math.round(borderPadding / ratio));
822                    //offset = (int)borderPadding;
823                }//*/
824
825
826                if(SymbolUtilities.isActionPoint(symbolID))//smooth out action points
827                    strSVGIcon = "/n<g stroke-linejoin=\"round\" >/n" + strSVGIcon + "/n</g>";
828
829                strSVG = svgStart + strSVGIcon + "</svg>";
830                mySVG = SVG.getFromString(strSVG);
831                //mySVG.setDocumentViewBox(left,top,width,height);
832                mySVG.setDocumentViewBox(rect.left,rect.top,rect.width(),rect.height());
833                mySVG.renderToCanvas(canvas);
834
835                Point centerPoint = SymbolUtilities.getCMSymbolAnchorPoint(symbolID,new RectF(offset, offset, symbolBounds.right-offset, symbolBounds.bottom-offset));
836                if(offset > 0)
837                    centerPoint.offset(offset,offset);
838
839                ii = new ImageInfo(bmp, centerPoint, symbolBounds);
840
841                if(cacheEnabled && drawAsIcon == false && bmp.getAllocationByteCount() <= maxCachedEntrySize)
842                {
843                    synchronized (_SinglePointCacheMutex)
844                    {
845                        if(_tgCache.get(key) == null)
846                            _tgCache.put(key, ii);
847                    }
848                }
849                /*if (drawAsIcon == false && pixelSize <= 100)
850
851                    _tgCache.put(key, ii);
852                }//*/
853            }
854
855            //Process Modifiers
856            ImageInfo iiNew = null;
857            if (drawAsIcon == false && (hasTextModifiers || hasDisplayModifiers))
858            {
859                SymbolDimensionInfo sdiTemp = null;
860                if (SymbolUtilities.isSPWithSpecialModifierLayout(symbolID))//(SymbolUtilitiesD.isTGSPWithSpecialModifierLayout(symbolID))
861                {
862                    sdiTemp = ModifierRenderer.ProcessTGSPWithSpecialModifierLayout(ii, symbolID, modifiers, attributes, lineColor);
863                }
864                else
865                {
866                    sdiTemp = ModifierRenderer.ProcessTGSPModifiers(ii, symbolID, modifiers, attributes, lineColor);
867                }
868                iiNew = (sdiTemp instanceof ImageInfo ? (ImageInfo)sdiTemp : null);
869            }
870
871            if (iiNew != null)
872            {
873                ii = iiNew;
874            }
875
876            //cleanup
877            //bmp.recycle();
878            symbolBounds = null;
879            fullBMP = null;
880            fullBounds = null;
881            mySVG = null;
882
883
884            if (drawAsIcon)
885            {
886                return ii.getSquareImageInfo();
887            }
888            else
889            {
890                return ii;
891            }
892
893        }
894        catch (Exception exc)
895        {
896            ErrorLogger.LogException("SinglePointRenderer", "RenderSP(" + SymbolUtilities.getBasicSymbolID(symbolID) + ")", exc);
897        }
898        return null;
899    }
900
901
902    /**
903     *
904     * @param symbolID
905     * @return
906     */
907    @SuppressWarnings("unused")
908    public ImageInfo RenderModifier(String symbolID, Map<String,String> attributes)
909    {
910        ImageInfo temp = null;
911        String basicSymbolID = null;
912
913        Color lineColor = null;
914        Color fillColor = null;//SymbolUtilities.getFillColorOfAffiliation(symbolID);
915
916        int alpha = -1;
917
918
919        //SVG rendering variables
920        MSInfo msi = null;
921        String iconID = null;
922        SVGInfo siIcon = null;
923        int top = 0;
924        int left = 0;
925        int width = 0;
926        int height = 0;
927        String svgStart = null;
928        String strSVG = null;
929        SVG mySVG = null;
930
931        float ratio = 0;
932
933        Rect symbolBounds = null;
934        RectF fullBounds = null;
935        Bitmap fullBMP = null;
936
937        boolean drawAsIcon = false;
938        int pixelSize = -1;
939        boolean keepUnitRatio = true;
940        boolean hasDisplayModifiers = false;
941        boolean hasTextModifiers = false;
942        int symbolOutlineWidth = RendererSettings.getInstance().getSinglePointSymbolOutlineWidth();
943        boolean drawCustomOutline = false;
944
945        try
946        {
947
948            msi = MSLookup.getInstance().getMSLInfo(symbolID);
949            if (attributes != null)
950            {
951                if (attributes.containsKey(MilStdAttributes.KeepUnitRatio))
952                {
953                    keepUnitRatio = Boolean.parseBoolean(attributes.get(MilStdAttributes.KeepUnitRatio));
954                }
955
956                if (attributes.containsKey(MilStdAttributes.LineColor))
957                {
958                    lineColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.LineColor));
959                }
960
961                if (attributes.containsKey(MilStdAttributes.FillColor))
962                {
963                    fillColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.FillColor));
964                }
965
966                if (attributes.containsKey(MilStdAttributes.Alpha))
967                {
968                    alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
969                }
970
971                if (attributes.containsKey(MilStdAttributes.DrawAsIcon))
972                {
973                    drawAsIcon = Boolean.parseBoolean(attributes.get(MilStdAttributes.DrawAsIcon));
974                }
975
976                if (attributes.containsKey(MilStdAttributes.PixelSize))
977                {
978                    pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize));
979                    if(msi.getSymbolSet() == SymbolID.SymbolSet_ControlMeasure)
980                    {
981                        if(SymbolID.getEntityCode(symbolID)==270701)//static depiction
982                            pixelSize = (int)(pixelSize * 0.9);//try to scale to be somewhat in line with units
983                    }
984                }
985
986                if(drawAsIcon==false)//don't outline icons because they're not going on the map
987                {
988                    if(attributes.containsKey(MilStdAttributes.OutlineSymbol))
989                        drawCustomOutline = Boolean.parseBoolean(attributes.get(MilStdAttributes.OutlineSymbol));
990                    else
991                        drawCustomOutline = RendererSettings.getInstance().getOutlineSPControlMeasures();
992                }
993
994                if(SymbolUtilities.isMultiPoint(symbolID))
995                    drawCustomOutline=false;//icon previews for multipoints do not need outlines since they shouldn't be on the map
996
997                /*if (attributes.containsKey(MilStdAttributes.OutlineWidth)>=0)
998                 symbolOutlineWidth = Integer.parseInt(attributes.get(MilStdAttributes.OutlineWidth));//*/
999            }
1000
1001            int outlineOffset = symbolOutlineWidth;
1002            if (drawCustomOutline && outlineOffset > 2)
1003            {
1004                outlineOffset = (outlineOffset - 1) / 2;
1005            }
1006            else
1007            {
1008                outlineOffset = 0;
1009            }
1010
1011        }
1012        catch (Exception excModifiers)
1013        {
1014            ErrorLogger.LogException("SinglePointRenderer", "RenderModifier", excModifiers);
1015        }
1016
1017        try
1018        {
1019            ImageInfo ii = null;
1020            int intFill = -1;
1021            if (fillColor != null)
1022            {
1023                intFill = fillColor.toInt();
1024            }
1025
1026
1027            if(msi.getSymbolSet() != SymbolID.SymbolSet_ControlMeasure)
1028                lineColor = Color.BLACK;//color isn't black but should be fine for weather since colors can't be user defined.
1029
1030
1031            //if not, generate symbol
1032            if (ii == null)//*/
1033            {
1034                int version = SymbolID.getVersion(symbolID);
1035                //check symbol size////////////////////////////////////////////
1036                Rect rect = null;
1037
1038                iconID = SVGLookup.getMod1ID(symbolID);
1039                siIcon = SVGLookup.getInstance().getSVGLInfo(iconID, version);
1040                top = Math.round(siIcon.getBbox().top);
1041                left = Math.round(siIcon.getBbox().left);
1042                width = Math.round(siIcon.getBbox().width());
1043                height = Math.round(siIcon.getBbox().height());
1044                if(siIcon.getBbox().bottom > 400)
1045                    svgStart = "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 612 792\">";
1046                else
1047                    svgStart = "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 400 400\">";
1048
1049                String strSVGIcon = null;
1050                String strSVGOutline = null;
1051
1052                //update line and fill color of frame SVG
1053                if(msi.getSymbolSet() == SymbolID.SymbolSet_ControlMeasure && (lineColor != null || fillColor != null))
1054                    strSVGIcon = RendererUtilities.setSVGFrameColors(symbolID,siIcon.getSVG(),lineColor,fillColor);
1055                else
1056                    strSVGIcon = siIcon.getSVG();
1057
1058                if (pixelSize > 0)
1059                {
1060                    symbolBounds = RectUtilities.makeRect(left,top,width,height);
1061                    rect = new Rect(symbolBounds);
1062
1063                    //adjust size
1064                    float p = pixelSize;
1065                    float h = rect.height();
1066                    float w = rect.width();
1067
1068                    ratio = Math.min((p / h), (p / w));
1069
1070                    symbolBounds = RectUtilities.makeRect(0f, 0f, w * ratio, h * ratio);
1071
1072                }
1073
1074
1075                //TODO: figure out how to draw an outline and adjust the symbol bounds accordingly
1076
1077                //Draw glyphs to bitmap
1078                Bitmap bmp = Bitmap.createBitmap((symbolBounds.width()), (symbolBounds.height()), Config.ARGB_8888);
1079                Canvas canvas = new Canvas(bmp);
1080
1081                symbolBounds = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
1082
1083                strSVG = svgStart + strSVGIcon + "</svg>";
1084                mySVG = SVG.getFromString(strSVG);
1085                mySVG.setDocumentViewBox(left,top,width,height);
1086                mySVG.renderToCanvas(canvas);
1087
1088                Point centerPoint = SymbolUtilities.getCMSymbolAnchorPoint(symbolID,new RectF(0, 0, symbolBounds.right, symbolBounds.bottom));
1089
1090                ii = new ImageInfo(bmp, centerPoint, symbolBounds);
1091
1092
1093                /*if (drawAsIcon == false && pixelSize <= 100)
1094                {
1095                    _tgCache.put(key, ii);
1096                }//*/
1097            }
1098
1099
1100            //cleanup
1101            //bmp.recycle();
1102            symbolBounds = null;
1103            fullBMP = null;
1104            fullBounds = null;
1105            mySVG = null;
1106
1107
1108            if (drawAsIcon)
1109            {
1110                return ii.getSquareImageInfo();
1111            }
1112            else
1113            {
1114                return ii;
1115            }
1116
1117        }
1118        catch (Exception exc)
1119        {
1120            ErrorLogger.LogException("SinglePointRenderer", "RenderModifier", exc);
1121        }
1122        return null;
1123    }
1124
1125
1126
1127    /**
1128     *
1129     * @param symbolID
1130     * @param lineColor
1131     * @param fillColor
1132     * @param size
1133     * @param keepUnitRatio
1134     * @param drawOutline (only for single-point Control Measures)
1135     * @return
1136     */
1137    private static String makeCacheKey(String symbolID, int lineColor, int fillColor, int size, boolean keepUnitRatio, boolean drawOutline)
1138    {
1139        return makeCacheKey(symbolID, lineColor, fillColor, "null",size, keepUnitRatio, false);
1140    }
1141
1142    private static String makeCacheKey(String symbolID, int lineColor, int fillColor, String iconColor, int size, boolean keepUnitRatio, boolean drawOutline)
1143    {
1144        //String key = symbolID.substring(0, 20) + String.valueOf(lineColor) + String.valueOf(fillColor) + String.valueOf(size) + String.valueOf(keepUnitRatio);
1145        String key = symbolID.substring(0, 7) + symbolID.substring(10, 20) + SymbolID.getFrameShape(symbolID) + lineColor + fillColor + iconColor + size + keepUnitRatio + drawOutline;
1146        return key;
1147    }
1148
1149    public void logError(String tag, Throwable thrown)
1150    {
1151        if (tag == null || tag.equals(""))
1152        {
1153            tag = "singlePointRenderer";
1154        }
1155
1156        String message = thrown.getMessage();
1157        String stack = getStackTrace(thrown);
1158        if (message != null)
1159        {
1160            Log.e(tag, message);
1161        }
1162        if (stack != null)
1163        {
1164            Log.e(tag, stack);
1165        }
1166    }
1167
1168    public String getStackTrace(Throwable thrown)
1169    {
1170        try
1171        {
1172            if (thrown != null)
1173            {
1174                if (thrown.getStackTrace() != null)
1175                {
1176                    String eol = System.getProperty("line.separator");
1177                    StringBuilder sb = new StringBuilder();
1178                    sb.append(thrown.toString());
1179                    sb.append(eol);
1180                    for (StackTraceElement element : thrown.getStackTrace())
1181                    {
1182                        sb.append("        at ");
1183                        sb.append(element);
1184                        sb.append(eol);
1185                    }
1186                    return sb.toString();
1187                }
1188                else
1189                {
1190                    return thrown.getMessage() + "- no stack trace";
1191                }
1192            }
1193            else
1194            {
1195                return "no stack trace";
1196            }
1197        }
1198        catch (Exception exc)
1199        {
1200            Log.e("getStackTrace", exc.getMessage());
1201        }
1202        return thrown.getMessage();
1203    }//
1204
1205    /*
1206     private static String PrintList(ArrayList list)
1207     {
1208     String message = "";
1209     for(Object item : list)
1210     {
1211
1212     message += item.toString() + "\n";
1213     }
1214     return message;
1215     }//*/
1216    /*
1217     private static String PrintObjectMap(Map<String, Object> map)
1218     {
1219     Iterator<Object> itr = map.values().iterator();
1220     String message = "";
1221     String temp = null;
1222     while(itr.hasNext())
1223     {
1224     temp = String.valueOf(itr.next());
1225     if(temp != null)
1226     message += temp + "\n";
1227     }
1228     //ErrorLogger.LogMessage(message);
1229     return message;
1230     }//*/
1231    @Override
1232    public void onSettingsChanged(SettingsChangedEvent sce)
1233    {
1234
1235        if(sce != null && sce.getEventType().equals(SettingsChangedEvent.EventType_FontChanged))
1236        {
1237            synchronized (_modifierFontMutex)
1238            {
1239                _modifierFont = RendererSettings.getInstance().getModiferFont();
1240                _modifierOutlineFont = RendererSettings.getInstance().getModiferFont();
1241                FontMetrics fm = new FontMetrics();
1242                fm = _modifierFont.getFontMetrics();
1243                _modifierDescent = fm.descent;
1244                //_modifierFontHeight = fm.top + fm.bottom;
1245                _modifierFontHeight = fm.bottom - fm.top;
1246
1247                _modifierFont.setStrokeWidth(RendererSettings.getInstance().getTextOutlineWidth());
1248                _modifierOutlineFont.setColor(Color.white.toInt());
1249                _deviceDPI = RendererSettings.getInstance().getDeviceDPI();
1250
1251                ModifierRenderer.setModifierFont(_modifierFont, _modifierFontHeight, _modifierDescent);
1252
1253            }
1254        }
1255
1256        if(sce != null && sce.getEventType().equals(SettingsChangedEvent.EventType_CacheSizeChanged))
1257        {
1258
1259            int cSize = RendererSettings.getInstance().getCacheSize()/2;
1260            //adjust unit cache
1261            if(cSize != cacheSize) {
1262                cacheSize = cSize;
1263                if (cacheSize >= 5)
1264                    maxCachedEntrySize = cacheSize / 5;
1265                else
1266                    maxCachedEntrySize = 1;
1267
1268                if(cacheEnabled) //if cache enabled, update cache
1269                {
1270
1271                    synchronized (_UnitCacheMutex) {
1272                        if(_unitCache != null)
1273                            _unitCache.evictAll();
1274                        _unitCache = new LruCache<String, ImageInfo>(cSize) {
1275                            @Override
1276                            protected int sizeOf(String key, ImageInfo ii) {
1277                                return ii.getByteCount();// / 1024;
1278                            }
1279                        };
1280                    }
1281                    //adjust tg cache
1282                    synchronized (_SinglePointCacheMutex) {
1283                        if(_tgCache != null)
1284                            _tgCache.evictAll();
1285                        _tgCache = new LruCache<String, ImageInfo>(cSize) {
1286                            @Override
1287                            protected int sizeOf(String key, ImageInfo ii) {
1288                                return ii.getByteCount();// / 1024;
1289                            }
1290                        };
1291                    }
1292                }
1293            }
1294        }
1295        if(sce != null && sce.getEventType().equals(SettingsChangedEvent.EventType_CacheToggled))
1296        {
1297            if(cacheEnabled != RendererSettings.getInstance().getCacheEnabled())
1298            {
1299                cacheEnabled = RendererSettings.getInstance().getCacheEnabled();
1300
1301                if (cacheEnabled == false)
1302                {
1303                    synchronized (_SinglePointCacheMutex)
1304                    {
1305                        if (_tgCache != null)
1306                            _tgCache.evictAll();
1307                        _tgCache = null;
1308                    }
1309                    synchronized (_UnitCacheMutex)
1310                    {
1311                        if (_unitCache != null)
1312                            _unitCache.evictAll();
1313                        _unitCache = null;
1314                    }
1315                }
1316                else
1317                {
1318                    int cSize = RendererSettings.getInstance().getCacheSize() / 2;
1319                    synchronized (_SinglePointCacheMutex)
1320                    {
1321                        if(_tgCache != null)
1322                            _tgCache.evictAll();
1323                        _tgCache = new LruCache<String, ImageInfo>(cSize) {
1324                            @Override
1325                            protected int sizeOf(String key, ImageInfo ii) {
1326                                return ii.getByteCount();// / 1024;
1327                            }
1328                        };
1329                    }
1330                    synchronized (_UnitCacheMutex)
1331                    {
1332                        if(_unitCache != null)
1333                            _unitCache.evictAll();
1334                        _unitCache = new LruCache<String, ImageInfo>(cSize) {
1335                            @Override
1336                            protected int sizeOf(String key, ImageInfo ii) {
1337                                return ii.getByteCount();// / 1024;
1338                            }
1339                        };
1340                    }
1341                }
1342            }
1343        }
1344    }
1345}