001package armyc2.c5isr.renderer;
002
003import java.util.ArrayList;
004import java.util.Iterator;
005import java.util.List;
006import java.util.Locale;
007import java.util.Map;
008
009import android.graphics.Bitmap;
010import android.graphics.Canvas;
011import android.graphics.DashPathEffect;
012import android.graphics.Paint;
013import android.graphics.Path;
014import android.graphics.Point;
015import android.graphics.PointF;
016import android.graphics.Rect;
017import android.graphics.RectF;
018import android.graphics.Bitmap.Config;
019import android.graphics.Paint.Cap;
020import android.graphics.Paint.Join;
021import android.graphics.Paint.Style;
022import android.graphics.Path.Direction;
023import android.graphics.Typeface;
024
025import armyc2.c5isr.renderer.utilities.Color;
026import armyc2.c5isr.renderer.utilities.ErrorLogger;
027import armyc2.c5isr.renderer.utilities.GENCLookup;
028import armyc2.c5isr.renderer.utilities.ImageInfo;
029import armyc2.c5isr.renderer.utilities.MSInfo;
030import armyc2.c5isr.renderer.utilities.MSLookup;
031import armyc2.c5isr.renderer.utilities.MilStdAttributes;
032import armyc2.c5isr.renderer.utilities.Modifier;
033import armyc2.c5isr.renderer.utilities.Modifiers;
034import armyc2.c5isr.renderer.utilities.PathUtilities;
035import armyc2.c5isr.renderer.utilities.RectUtilities;
036import armyc2.c5isr.renderer.utilities.RendererSettings;
037import armyc2.c5isr.renderer.utilities.RendererUtilities;
038import armyc2.c5isr.renderer.utilities.SVGInfo;
039import armyc2.c5isr.renderer.utilities.SVGLookup;
040import armyc2.c5isr.renderer.utilities.SVGPath;
041import armyc2.c5isr.renderer.utilities.SVGSymbolInfo;
042import armyc2.c5isr.renderer.utilities.Shape2SVG;
043import armyc2.c5isr.renderer.utilities.SymbolDimensionInfo;
044import armyc2.c5isr.renderer.utilities.SymbolID;
045import armyc2.c5isr.renderer.utilities.SymbolUtilities;
046import armyc2.c5isr.renderer.utilities.TextInfo;
047
048/**
049 * This class is used for rendering the labels/amplifiers/modifiers around the single point symbol.
050 */
051public class ModifierRenderer
052{
053
054    private static Paint _modifierFont = null;
055    private static float _modifierFontHeight = 10f;
056    private static float _modifierFontDescent = 2f;
057    private static RendererSettings RS = RendererSettings.getInstance();
058
059    private static final Object modifierFontMutex = new Object();
060    public static void setModifierFont(Paint font, float height, float descent)
061    {
062        synchronized (modifierFontMutex) {
063            _modifierFont = font;
064            _modifierFontHeight = height;
065            _modifierFontDescent = descent;
066        }
067    }
068
069    public static SymbolDimensionInfo processUnitDisplayModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Boolean hasTextModifiers, Map<String,String> attributes)
070    {
071
072        ImageInfo ii = null;
073        ImageInfo newii = null;
074        SVGSymbolInfo ssi = null;
075        SymbolDimensionInfo newsdi = null;
076        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
077        Rect imageBounds = new Rect(sdi.getImageBounds());
078        Point centerPoint = new Point(sdi.getCenterPoint());
079        Point symbolCenter = new Point(symbolBounds.centerX(), symbolBounds.centerY());
080        TextInfo tiEchelon = null;
081        TextInfo tiAM = null;
082        Rect echelonBounds = null;
083        Rect amBounds = null;
084        Color textColor = Color.BLACK;
085        Color textBackgroundColor = null;
086        float strokeWidth = 3.0f;
087        float strokeWidthNL = 3.0f;
088        Color lineColor = SymbolUtilities.getLineColorOfAffiliation(symbolID);
089        Color fillColor = SymbolUtilities.getFillColorOfAffiliation(symbolID);
090        int buffer = 0;
091        int alpha = 255;
092        //ctx = null;
093        int offsetX = 0;
094        int offsetY = 0;
095        int pixelSize = RendererSettings.getInstance().getDefaultPixelSize();
096        SVGPath svgMobilityPath = null;
097        String svgMobilityGroup = null;
098
099        Paint modifierFont = getFont(attributes);
100        float[] hd = getFontHeightandDescent(modifierFont);
101        float modifierFontHeight = hd[0];
102        float modifierFontDescent = hd[1];
103
104        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
105        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
106        {
107            String temp = attributes.get(MilStdAttributes.FontFamily);
108            if(temp != null && !temp.isEmpty())
109                modifierFontName = temp;
110        }
111
112        int ss = SymbolID.getSymbolSet(symbolID);
113
114        if (attributes.containsKey(MilStdAttributes.Alpha))
115        {
116            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
117            textColor.setAlpha(alpha);
118        }
119        if (attributes.containsKey(MilStdAttributes.TextColor))
120        {
121            textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
122            if(alpha > -1)
123                textColor.setAlpha(alpha);
124        }
125        if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
126        {
127            textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
128            if(alpha > -1)
129                textBackgroundColor.setAlpha(alpha);
130        }
131        if (attributes.containsKey(MilStdAttributes.LineColor))
132        {
133            lineColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.LineColor));
134        }
135        if (attributes.containsKey(MilStdAttributes.FillColor))
136        {
137            fillColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.FillColor));
138        }
139        if(attributes.containsKey(MilStdAttributes.PixelSize))
140        {
141            pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize));
142        }
143
144        //float fontsize = RendererSettings.getInstance().getModiferFont().getTextSize();
145
146        // <editor-fold defaultstate="collapsed" desc="Build Mobility Modifiers">
147        float strokeWidthBasedOnDPI = 1;//min//Math.max(RendererSettings.getInstance().getDeviceDPI()/210,1);//min DPI
148        strokeWidthBasedOnDPI = Math.max(pixelSize / 25f,strokeWidthBasedOnDPI);//dpi base on symbol size
149        strokeWidthBasedOnDPI = Math.min(strokeWidthBasedOnDPI,RendererSettings.getInstance().getDeviceDPI()/32f);//max dpi
150
151        RectF mobilityBounds = null;
152        int ad = SymbolID.getAmplifierDescriptor(symbolID);//echelon/mobility
153        List<Path> shapes = new ArrayList<Path>();
154        Path mobilityPath = null;
155        Path mobilityPathFill = null;
156        if (ad >= SymbolID.Mobility_WheeledLimitedCrossCountry &&
157                (SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.R_MOBILITY_INDICATOR) ||
158                 SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AG_AUX_EQUIP_INDICATOR)))
159        {
160
161            //Draw Mobility
162            int fifth = (int) ((symbolBounds.width() * 0.2) + 0.5f);
163            mobilityPath = new Path();
164            svgMobilityPath = null;
165            svgMobilityGroup = null;
166
167            int x = 0;
168            int y = 0;
169            int centerX = 0;
170            int bottomY = 0;
171            int height = 0;
172            int width = 0;
173            int middleY = 0;
174            int wheelOffset = 2;
175            int wheelSize = fifth;//10;
176            int rrHeight = fifth;//10;
177            int rrArcWidth = (int) ((fifth * 1.5) + 0.5f);//16;
178            float rad = wheelSize/2;
179
180
181            x = (int) symbolBounds.left + 1;
182            y = (int) symbolBounds.top;
183            height = Math.round(symbolBounds.height());
184            width = Math.round(symbolBounds.width()) - 3;
185            bottomY = y + height + 2;
186
187
188
189            if (ad >= SymbolID.Mobility_WheeledLimitedCrossCountry && //31, mobility starts above 30
190                    SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.R_MOBILITY_INDICATOR))
191            {
192                bottomY = y + height + 2;
193
194                //wheelSize = width / 7;
195                //rrHeight = width / 7;
196                //rrArcWidth = width / 7;
197                if (ad == SymbolID.Mobility_WheeledLimitedCrossCountry)
198                {
199                    //line
200                    PathUtilities.addLine(mobilityPath, x, bottomY, x + width, bottomY);
201
202                    //left circle
203                    PathUtilities.addEllipse(mobilityPath, x, bottomY + wheelOffset, wheelSize, wheelSize);
204
205                    //right circle
206                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
207
208                    //SVG
209                    svgMobilityGroup = "<line x1=\"" + x + "\" y1=\"" + bottomY + "\" x2=\"" + (x + width) + "\" y2=\"" + bottomY + "\" />\n";
210                    svgMobilityGroup += "<circle cx=\"" + (x + (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\"  ></circle>\n";
211                    svgMobilityGroup += "<circle cx=\"" + (x + width - (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\"  ></circle>\n";
212                }
213                else if (ad == SymbolID.Mobility_WheeledCrossCountry)
214                {
215                    //line
216                    PathUtilities.addLine(mobilityPath, x, bottomY, x + width, bottomY);
217
218                    //left circle
219                    PathUtilities.addEllipse(mobilityPath, x, bottomY + wheelOffset, wheelSize, wheelSize);
220
221                    //right circle
222                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
223
224                    //center wheel
225                    PathUtilities.addEllipse(mobilityPath, x + (width / 2) - (wheelSize / 2), bottomY + wheelOffset, wheelSize, wheelSize);
226
227                    //SVG
228                    svgMobilityGroup = "<line x1=\"" + x + "\" y1=\"" + bottomY + "\" x2=\"" + (x + width) + "\" y2=\"" + bottomY + "\" />\n";
229                    svgMobilityGroup += "<circle cx=\"" + (x + (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" stroke=\"black\" ></circle>\n";
230                    svgMobilityGroup += "<circle cx=\"" + (x + width - (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" stroke=\"black\" ></circle>\n";
231                    svgMobilityGroup += "<circle cx=\"" + (x + (width/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" stroke=\"black\" ></circle>\n";
232                }
233                else if (ad == SymbolID.Mobility_Tracked)
234                {
235                    //round rectangle
236                    PathUtilities.addRoundedRect(mobilityPath, x, bottomY, width, rrHeight, rrHeight/2, rrHeight);
237                    svgMobilityGroup = "<rect width=\"" + width + "\" height=\"" + rrHeight + "\" x=\"" + x + "\" y=\"" + bottomY + "\" rx=\"" + rrHeight/2 + "\" ry=\"" + rrHeight + "\" />\n";
238
239                }
240                else if (ad == SymbolID.Mobility_Wheeled_Tracked)
241                {
242                    //round rectangle
243                    PathUtilities.addRoundedRect(mobilityPath, x, bottomY, width, rrHeight, wheelSize/2, rrHeight);
244                    svgMobilityGroup = "<rect width=\"" + width + "\" height=\"" + rrHeight + "\" x=\"" + x + "\" y=\"" + bottomY + "\" rx=\"" + rrHeight/2 + "\" ry=\"" + rrHeight + "\" />\n";
245
246                    //left circle
247                    PathUtilities.addEllipse(mobilityPath, x - wheelSize - wheelSize, bottomY, wheelSize, wheelSize);
248                    svgMobilityGroup += "<circle cx=\"" + (x - wheelSize - wheelSize/2) + "\" cy=\"" + (bottomY + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\"  stroke=\"black\" ></circle>\n";
249                }
250                else if (ad == SymbolID.Mobility_Towed)
251                {
252                    //line
253                    PathUtilities.addLine(mobilityPath, x + wheelSize, bottomY + (wheelSize / 2),
254                            x + width - wheelSize, bottomY + (wheelSize / 2));
255
256                    //left circle
257                    PathUtilities.addEllipse(mobilityPath, x, bottomY, wheelSize, wheelSize);
258
259                    //right circle
260                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY, wheelSize, wheelSize);
261
262                    //SVG
263                    svgMobilityGroup = "<line x1=\"" + (x + wheelSize) + "\" y1=\"" + (bottomY + (wheelSize/2) + "\" x2=\"" + (x + width - wheelSize) + "\" y2=\"" + (bottomY + (wheelSize/2))) + "\" />\n";
264                    svgMobilityGroup += "<circle cx=\"" + (x + (wheelSize/2)) + "\" cy=\"" + (bottomY + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" fill=\"none\" stroke=\"black\" ></circle>\n";
265                    svgMobilityGroup += "<circle cx=\"" + (x + width - (wheelSize/2)) + "\" cy=\"" + (bottomY + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" fill=\"none\" stroke=\"black\" ></circle>\n";
266                }
267                else if (ad == SymbolID.Mobility_Rail)
268                {
269                    //line
270                    PathUtilities.addLine(mobilityPath, x, bottomY, x + width, bottomY);
271
272                    //left circle
273                    PathUtilities.addEllipse(mobilityPath, x + wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
274
275                    //left circle2
276                    PathUtilities.addEllipse(mobilityPath, x, bottomY + wheelOffset, wheelSize, wheelSize);
277
278                    //right circle
279                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
280
281                    //right circle2
282                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
283
284                    //SVG
285                    svgMobilityGroup = "<line x1=\"" + x + "\" y1=\"" + bottomY + "\" x2=\"" + (x + width) + "\" y2=\"" + bottomY + "\" />\n";
286
287                    svgMobilityGroup += "<circle cx=\"" + (x + rad) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
288                    svgMobilityGroup += "<circle cx=\"" + (x + rad + wheelSize) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
289
290                    svgMobilityGroup += "<circle cx=\"" + (x + width - rad) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
291                    svgMobilityGroup += "<circle cx=\"" + (x + width - rad - wheelSize) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
292
293                }
294                else if (ad == SymbolID.Mobility_OverSnow)
295                {
296                        float halfWidth = (rrArcWidth * 0.5f);
297                    mobilityPath.moveTo(x, bottomY);
298                    mobilityPath.lineTo(x + halfWidth, bottomY + halfWidth);
299                    mobilityPath.lineTo(x + width, bottomY + halfWidth);
300
301                    //SVG
302                    svgMobilityPath = new SVGPath();
303                    svgMobilityPath.moveTo(x,bottomY);
304                    svgMobilityPath.lineTo(x + halfWidth, bottomY + halfWidth);
305                    svgMobilityPath.lineTo(x + width, bottomY + halfWidth);
306
307                }
308                else if (ad == SymbolID.Mobility_Sled)
309                {
310                    mobilityPath.moveTo(x, bottomY);
311
312                    mobilityPath.cubicTo(x, bottomY, x - rrHeight, bottomY + rrHeight/2, x, bottomY + rrHeight);
313                    //mobilityPath.bezierCurveTo(x, bottomY, x-rrArcWidth, bottomY+3, x, bottomY+rrHeight);
314
315                    mobilityPath.lineTo(x + width, bottomY + rrHeight);
316
317                    mobilityPath.cubicTo(x + width, bottomY + rrHeight, x + width + rrHeight, bottomY + rrHeight/2, x + width, bottomY);
318                    //shapeMobility.curveTo(x + width, bottomY + rrHeight, x+ width + rrArcWidth, bottomY+3, x + width, bottomY);
319
320                    //SVG
321                    svgMobilityPath = new SVGPath();
322                    svgMobilityPath.moveTo(x, bottomY);
323                    svgMobilityPath.bezierCurveTo(x, bottomY, x - rrHeight, bottomY + rrHeight/2, x, bottomY + rrHeight);
324                    svgMobilityPath.lineTo(x + width, bottomY + rrHeight);
325                    svgMobilityPath.bezierCurveTo(x + width, bottomY + rrHeight, x + width + rrHeight, bottomY + rrHeight/2, x + width, bottomY);
326
327                }
328                else if (ad == SymbolID.Mobility_PackAnimals)
329                {
330                    centerX = Math.round(RectUtilities.getCenterX(symbolBounds));
331                    int angleWidth = rrHeight / 2;
332                    mobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
333                    mobilityPath.lineTo(centerX - angleWidth, bottomY);
334                    mobilityPath.lineTo(centerX - angleWidth*2, bottomY + rrHeight + 2);
335
336                    mobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
337                    mobilityPath.lineTo(centerX + angleWidth, bottomY);
338                    mobilityPath.lineTo(centerX + angleWidth*2, bottomY + rrHeight + 2);
339
340                    //SVG
341                    svgMobilityPath = new SVGPath();
342                    svgMobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
343                    svgMobilityPath.lineTo(centerX - angleWidth, bottomY);
344                    svgMobilityPath.lineTo(centerX - angleWidth*2, bottomY + rrHeight + 2);
345
346                    svgMobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
347                    svgMobilityPath.lineTo(centerX + angleWidth, bottomY);
348                    svgMobilityPath.lineTo(centerX + angleWidth*2, bottomY + rrHeight + 2);
349                }
350                else if (ad == SymbolID.Mobility_Barge)
351                {
352                    centerX = Math.round(RectUtilities.getCenterX(symbolBounds));
353                    PathUtilities.addLine(mobilityPath, x + width, bottomY, x, bottomY);
354                    //var line = new SO.Line(x + width, bottomY,x, bottomY);
355
356                    float quarterX = (centerX - x) / 2;
357                    //var quarterY = (((bottomY + rrHeight) - bottomY)/2);
358
359                    mobilityPath.moveTo(x, bottomY);
360                    mobilityPath.cubicTo(x + quarterX, bottomY + rrHeight, centerX + quarterX, bottomY + rrHeight, x + width, bottomY);
361                    //shapes.push(new SO.BCurve(x, bottomY,x+quarterX, bottomY+rrHeight, centerX + quarterX, bottomY + rrHeight, x + width, bottomY));
362
363                    //SVG
364                    svgMobilityPath = new SVGPath();
365                    svgMobilityPath.moveTo(x + width, bottomY);
366                    svgMobilityPath.lineTo(x, bottomY);
367                    svgMobilityPath.moveTo(x, bottomY);
368                    svgMobilityPath.bezierCurveTo(x + quarterX, bottomY + rrHeight, centerX + quarterX, bottomY + rrHeight, x + width, bottomY);
369                }
370
371                else if (ad == SymbolID.Mobility_Amphibious)
372                {
373                    float incrementX = width / 7;
374                    middleY = (bottomY + (rrHeight / 2));
375
376                    x = Math.round(x + (incrementX / 2));
377                    float r = Math.round(incrementX / 2);
378
379                    //mobilityPath.arcTo(oval, sAngle, sAngle, moveTo);
380                    PathUtilities.arc(mobilityPath, x, middleY, r, 180, 180);
381                    PathUtilities.arc(mobilityPath, x + incrementX, middleY, r, 180, -180, false);
382                    PathUtilities.arc(mobilityPath, x + incrementX * 2, middleY, r, 180, 180, false);
383                    PathUtilities.arc(mobilityPath, x + incrementX * 3, middleY, r, 180, -180, false);
384                    PathUtilities.arc(mobilityPath, x + incrementX * 4, middleY, r, 180, 180, false);
385                    PathUtilities.arc(mobilityPath, x + incrementX * 5, middleY, r, 180, -180, false);
386                    PathUtilities.arc(mobilityPath, x + incrementX * 6, middleY, r, 180, 180, false);
387
388                    //SVG
389                    x = symbolBounds.left + 1;
390                    svgMobilityGroup = "<path d=\"M" + x + " " + middleY + " ";
391                    svgMobilityGroup += "C " + x + " " + bottomY + " " + (x + incrementX) + " " + bottomY + " " + (x + incrementX) + " " + middleY + " ";
392                    svgMobilityGroup += "C " + (x + incrementX) + " " + (bottomY + rrHeight) + " " + (x + (incrementX * 2)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX*2)) + " " + middleY + " ";
393                    svgMobilityGroup += "C " + (x + (incrementX*2))  + " " + bottomY + " " + (x + (incrementX*3)) + " " + bottomY + " " + (x + incrementX*3) + " " + middleY + " ";
394                    svgMobilityGroup += "C " + (x + (incrementX*3)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX * 4)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX*4)) + " " + middleY + " ";
395                    svgMobilityGroup += "C " + (x + (incrementX*4))  + " " + bottomY + " " + (x + (incrementX*5)) + " " + bottomY + " " + (x + incrementX*5) + " " + middleY + " ";
396                    svgMobilityGroup += "C " + (x + (incrementX*5)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX * 6)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX*6)) + " " + middleY + " ";
397                    svgMobilityGroup += "C " + (x + (incrementX*6))  + " " + bottomY + " " + (x + (incrementX*7)) + " " + bottomY + " " + (x + incrementX*7) + " " + middleY + " ";
398                    svgMobilityGroup += "\"/>";
399
400
401                }
402
403                if(svgMobilityGroup != null)
404                    svgMobilityGroup = "<g stroke-width=\"" + strokeWidthBasedOnDPI + "\" fill=\"none\"" + " stroke=\"" + RendererUtilities.colorToHexString(lineColor,false) + "\"" + ">\n" + svgMobilityGroup + "</g>\n";
405
406            }
407            //Draw Towed Array Sonar
408            if ((ad == SymbolID.Mobility_ShortTowedArray || ad == SymbolID.Mobility_LongTowedArray) &&
409                    SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AG_AUX_EQUIP_INDICATOR)) {
410                int boxHeight = (int) ((rrHeight * 0.8f) + 0.5f);
411                bottomY = y + height + (boxHeight / 7);
412                mobilityPathFill = new Path();
413                offsetY = boxHeight / 7;//1;
414                centerX = Math.round(symbolBounds.left + (symbolBounds.right - symbolBounds.left) / 2);
415                int squareOffset = Math.round(boxHeight * 0.5f);
416                middleY = ((boxHeight / 2) + bottomY) + offsetY;//+1 for offset from symbol
417                if (ad == SymbolID.Mobility_ShortTowedArray) {
418                    //subtract 0.5 because lines 1 pixel thick get aliased into
419                    //a line two pixels wide.
420                    //line
421                    PathUtilities.addLine(mobilityPath, centerX - 1, bottomY - 1, centerX - 1, bottomY + offsetY + boxHeight + offsetY);
422                    //shapes.push(new SO.Line(centerX-1,bottomY-1,centerX-1, bottomY + rrHeight + 3));
423                    //shapeLines.append(new Line2D.Double(centerX,bottomY - 2,centerX, bottomY + rrHeight + 1), false);
424                    //line
425                    PathUtilities.addLine(mobilityPath, x, middleY, x + width, middleY);
426                    //shapes.push(new SO.Line(x,middleY,x + width, middleY));
427                    //shapeLines.append(new Line2D.Double(x,middleY,x + width, middleY), false);
428                    //square
429                    mobilityPathFill.addRect(PathUtilities.makeRectF(x - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
430                    //shapes.push(new SO.Rectangle(x-squareOffset, bottomY+offsetY, 5, 5));
431                    //shapeSquares.append(new Rectangle2D.Double(x-squareOffset, bottomY, 5, 5), false);
432                    //square
433                    mobilityPathFill.addRect(PathUtilities.makeRectF(Math.round(centerX - squareOffset), bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
434                    //shapes.push(new SO.Rectangle(Math.round(centerX-squareOffset), bottomY+offsetY, 5, 5));
435                    //shapeSquares.append(new Rectangle2D.Double(centerX-squareOffset, bottomY, 5, 5), false);
436                    //square
437                    mobilityPathFill.addRect(PathUtilities.makeRectF(x + width - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
438                    //shapes.push(new SO.Rectangle(x + width - squareOffset, bottomY+offsetY, 5, 5));
439                    //shapeSquares.append(new Rectangle2D.Double(x + width - squareOffset, bottomY, 5, 5), false);
440
441                    //SVG
442                    String svgColor = RendererUtilities.colorToHexString(lineColor,false);
443                    svgMobilityGroup = "<line x1=\"" + (centerX - 1) + "\" y1=\"" + (bottomY - 1) + "\" x2=\"" + (centerX - 1) + "\" y2=\"" + (bottomY + offsetY + boxHeight + offsetY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
444                    svgMobilityGroup += "<line x1=\"" + (x) + "\" y1=\"" + (middleY) + "\" x2=\"" + (x + width) + "\" y2=\"" + (middleY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
445                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
446                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (centerX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
447                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x + width - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
448
449
450                } else if (ad == SymbolID.Mobility_LongTowedArray) {
451                    int leftX = x + (centerX - x) / 2,
452                            rightX = centerX + (x + width - centerX) / 2;
453
454                    //line vertical left
455                    PathUtilities.addLine(mobilityPath, leftX, bottomY - 1, leftX, bottomY + offsetY + boxHeight + offsetY);
456                    //shapes.push(new SO.Line(leftX,bottomY - 1,leftX, bottomY + rrHeight + 3));
457                    //shapeLines.append(new Line2D.Double(leftX,bottomY - 2,leftX, bottomY + rrHeight + 1), false);
458                    //line vertical right
459                    PathUtilities.addLine(mobilityPath, rightX, bottomY - 1, rightX, bottomY + offsetY + boxHeight + offsetY);
460                    //shapes.push(new SO.Line(rightX,bottomY - 1,rightX, bottomY + rrHeight + 3));
461                    //shapeLines.append(new Line2D.Double(rightX,bottomY - 2,rightX, bottomY + rrHeight + 1), false);
462                    //line horizontal
463                    PathUtilities.addLine(mobilityPath, x, middleY, x + width, middleY);
464                    //shapes.push(new SO.Line(x,middleY,x + width, middleY));
465                    //shapeLines.append(new Line2D.Double(x,middleY,x + width, middleY), false);
466                    //square left
467                    mobilityPathFill.addRect(PathUtilities.makeRectF(x - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
468                    //shapes.push(new SO.Rectangle(x-squareOffset, bottomY+offsetY, 5, 5));
469                    //shapeSquares.append(new Rectangle2D.Double(x-squareOffset, bottomY, 5, 5), false);
470                    //square middle
471                    mobilityPathFill.addRect(PathUtilities.makeRectF(centerX - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
472                    //shapes.push(new SO.Rectangle(centerX-squareOffset, bottomY+offsetY, 5, 5));
473                    //shapeSquares.append(new Rectangle2D.Double(centerX-squareOffset, bottomY, 5, 5), false);
474                    //square right
475                    mobilityPathFill.addRect(PathUtilities.makeRectF(x + width - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
476                    //shapes.push(new SO.Rectangle(x + width - squareOffset, bottomY+offsetY, 5, 5));
477                    //shapeSquares.append(new Rectangle2D.Double(x + width - squareOffset, bottomY, 5, 5), false);
478                    //square middle left
479                    mobilityPathFill.addRect(PathUtilities.makeRectF(leftX - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
480                    //shapes.push(new SO.Rectangle(leftX - squareOffset, bottomY+offsetY, 5, 5));
481                    //shapeSquares.append(new Rectangle2D.Double(leftX - squareOffset, bottomY, 5, 5), false);
482                    //square middle right
483                    mobilityPathFill.addRect(PathUtilities.makeRectF(rightX - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
484                    //shapes.push(new SO.Rectangle(rightX - squareOffset, bottomY+offsetY, 5, 5));
485                    //shapeSquares.append(new Rectangle2D.Double(rightX - squareOffset, bottomY, 5, 5), false);
486
487                    //SVG
488                    String svgColor = RendererUtilities.colorToHexString(lineColor,false);
489                    svgMobilityGroup = "<line x1=\"" + (leftX) + "\" y1=\"" + (bottomY - 1) + "\" x2=\"" + (leftX) + "\" y2=\"" + (bottomY + offsetY + boxHeight + offsetY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
490                    svgMobilityGroup += "<line x1=\"" + (rightX) + "\" y1=\"" + (bottomY - 1) + "\" x2=\"" + (rightX) + "\" y2=\"" + (bottomY + offsetY + boxHeight + offsetY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
491                    svgMobilityGroup += "<line x1=\"" + (x) + "\" y1=\"" + (middleY) + "\" x2=\"" + (x + width) + "\" y2=\"" + (middleY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
492                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
493                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (centerX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
494                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x + width - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
495                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (leftX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
496                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (rightX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
497
498                }
499                if(svgMobilityGroup != null)
500                    svgMobilityGroup = "<g stroke-width=\"" + strokeWidthBasedOnDPI + "\" fill=\"" + RendererUtilities.colorToHexString(lineColor,false) + "\"" + " stroke=\"" + RendererUtilities.colorToHexString(lineColor,false) + "\"" +  ">\n" + svgMobilityGroup + "\n</g>";
501            }
502
503            //get mobility bounds
504            if (mobilityPath != null)
505            {
506
507                //build mobility bounds
508                mobilityBounds = new RectF();
509                mobilityPath.computeBounds(mobilityBounds, true);
510
511                RectF mobilityFillBounds = new RectF();
512                if (mobilityPathFill != null)
513                {
514                    mobilityPathFill.computeBounds(mobilityFillBounds, true);
515                    mobilityBounds.union(mobilityFillBounds);
516                }
517
518                //grow by one because we use a line thickness of 2.
519                RectUtilities.grow(mobilityBounds,Math.round(strokeWidthBasedOnDPI/2));
520                //mobilityBounds.set(mobilityBounds.left - 1, mobilityBounds.top - 1, mobilityBounds.right + 1, mobilityBounds.bottom + 1);
521                imageBounds.union(RectUtilities.makeRectFromRectF(mobilityBounds));
522            }
523        }
524        // </editor-fold>
525
526        // <editor-fold defaultstate="collapsed" desc="Leadership Indicator Modifier">
527        RectF liBounds = null;
528        Path liPath = null;
529        PointF liTop = null;
530        PointF liLeft = null;
531        PointF liRight = null;
532        if(ad == SymbolID.Leadership_Individual && ss == SymbolID.SymbolSet_DismountedIndividuals &&
533                (SymbolID.getFrameShape(symbolID)==SymbolID.FrameShape_DismountedIndividuals ||
534                        SymbolID.getFrameShape(symbolID)==SymbolID.FrameShape_Unknown))
535        {
536            liPath = new Path();
537
538            int si = SymbolID.getStandardIdentity(symbolID);
539            int af = SymbolID.getAffiliation(symbolID);
540            int c = SymbolID.getContext(symbolID);
541            //int fs = SymbolID.getFrameShape(symbolID);
542            double centerOffset = 0;
543            double sideOffset = 0;
544            double left = symbolBounds.left;
545            double right = symbolBounds.left + symbolBounds.width();
546
547            if(af == SymbolID.StandardIdentity_Affiliation_Unknown || af == SymbolID.StandardIdentity_Affiliation_Pending)
548            {
549                centerOffset = (symbolBounds.height()*0.1012528735632184);
550                sideOffset = (right - left)*0.3583513488109785;
551                //left = symbolBounds.getCenterX() - ((symbolBounds.getWidth() / 2) * 0.66420458);
552                //right = symbolBounds.getCenterX() + ((symbolBounds.getWidth() / 2) * 0.66420458);
553            }
554            if(af == SymbolID.StandardIdentity_Affiliation_Neutral)
555            {
556                centerOffset = (symbolBounds.height()*0.25378787878787878);
557                sideOffset = (right - left)*0.2051402812352822;
558            }
559            if(SymbolUtilities.isReality(symbolID) || SymbolUtilities.isSimulation(symbolID))
560            {
561                if(af==SymbolID.StandardIdentity_Affiliation_Friend || af==SymbolID.StandardIdentity_Affiliation_AssumedFriend)
562                {//hexagon friend/assumed friend
563                    centerOffset = (symbolBounds.height()*0.08);
564                    sideOffset = (right - left)*0.282714524168219;//(symbolBounds.getHeight()*0.29);
565                }
566                else if(af==SymbolID.StandardIdentity_Affiliation_Hostile_Faker || af==SymbolID.StandardIdentity_Affiliation_Suspect_Joker)
567                {//diamond hostile/suspect
568
569                    left = symbolBounds.centerX() - ((symbolBounds.width() / 2) * 1.0653694149);//1.07);//1.0653694149);
570                    right = symbolBounds.centerX() + ((symbolBounds.width() / 2) * 1.0653694149);//1.07);//1.0653694149);
571
572                    centerOffset = (symbolBounds.height()*0.08);//0.0751139601139601
573                    sideOffset = (right - left)*0.4923255424955992;
574                }
575            }
576            else//Exercise
577            {
578                //hexagon
579                if(af!=SymbolID.StandardIdentity_Affiliation_Unknown ||
580                        af==SymbolID.StandardIdentity_Affiliation_Neutral)
581                {
582                    centerOffset = (symbolBounds.height()*0.08);
583                    sideOffset = (right - left)*0.282714524168219;
584                }
585            }
586
587            //create leadership indicator /\
588            liTop = new PointF(symbolBounds.centerX(), (float)(symbolBounds.top - centerOffset));
589            liLeft = new PointF((float)left, (float)(liTop.y + sideOffset));
590            liRight = new PointF((float)right, (float)(liTop.y + sideOffset));
591
592
593            liPath.moveTo(liTop.x, liTop.y);
594            liPath.lineTo(liLeft.x, liLeft.y);
595            liPath.moveTo(liTop.x, liTop.y);
596            liPath.lineTo(liRight.x, liRight.y);//*/
597
598
599            liBounds = new RectF(liLeft.x, liTop.y, liRight.x - liLeft.x, liLeft.y - liTop.y);
600
601            RectUtilities.grow(liBounds,2);
602
603            imageBounds.union(RectUtilities.makeRectFromRectF(liBounds));
604        }
605
606        // </editor-fold>
607
608        // <editor-fold defaultstate="collapsed" desc="Build Echelon">
609        //Draw Echelon
610        int intEchelon = SymbolID.getAmplifierDescriptor(symbolID);
611        String strEchelon = SymbolUtilities.getEchelonText(intEchelon);
612
613        if (strEchelon != null
614                && SymbolUtilities.hasModifier(symbolID, Modifiers.B_ECHELON))
615        {
616
617            int echelonOffset = 2,
618                    outlineOffset = RS.getTextOutlineWidth();
619
620            tiEchelon = new TextInfo(strEchelon, 0, 0, modifierFont, modifierFontName);
621            echelonBounds = tiEchelon.getTextBounds();
622
623            int y = Math.round(symbolBounds.left - echelonOffset);
624            int x = Math.round(symbolBounds.left + (symbolBounds.width() / 2)
625                    - (echelonBounds.width() / 2));
626            tiEchelon.setLocation(x, y);
627
628            //There will never be lowercase characters in an echelon so trim that fat.
629            //Remove the descent from the bounding box.
630            tiEchelon.getTextOutlineBounds();//.shiftBR(0,Math.round(-(echelonBounds.height()*0.3)));
631
632            //make echelon bounds a little more spacious for things like nearby labels and Task Force.
633            RectUtilities.grow(echelonBounds, outlineOffset);
634            //tiEchelon.getTextOutlineBounds();
635//                RectUtilities.shift(echelonBounds, x, -outlineOffset);
636            //echelonBounds.shift(0,-outlineOffset);// - Math.round(echelonOffset/2));
637            tiEchelon.setLocation(x, y - outlineOffset);
638
639            imageBounds.union(echelonBounds);
640
641        }
642        // </editor-fold>
643
644        // <editor-fold defaultstate="collapsed" desc="Build Affiliation Modifier">
645        //Draw Echelon
646        String affiliationModifier = null;
647        if (RS.getDrawAffiliationModifierAsLabel() == false)
648        {
649            affiliationModifier = SymbolUtilities.getStandardIdentityModifier(symbolID);
650        }
651        if (affiliationModifier != null)
652        {
653
654            int amOffset = 2;
655            int outlineOffset = RS.getTextOutlineWidth();
656
657            tiAM = new TextInfo(affiliationModifier, 0, 0, modifierFont, modifierFontName);
658            amBounds = tiAM.getTextBounds();
659
660            int x, y;
661
662            if (echelonBounds != null
663                    && ((echelonBounds.left + echelonBounds.width() > symbolBounds.left + symbolBounds.width())))
664            {
665                y = Math.round(symbolBounds.top - amOffset);
666                x = echelonBounds.left + echelonBounds.width();
667            }
668            else
669            {
670                y = Math.round(symbolBounds.top - amOffset);
671                x = Math.round(symbolBounds.left + symbolBounds.width());
672            }
673            tiAM.setLocation(x, y);
674
675            //adjust for outline.
676            RectUtilities.grow(amBounds, outlineOffset);
677            RectUtilities.shift(amBounds, 0, -outlineOffset);
678            tiAM.setLocation(x, y - outlineOffset);
679
680            imageBounds.union(amBounds);
681        }
682        // </editor-fold>
683
684        // <editor-fold defaultstate="collapsed" desc="Build Task Force">
685        Rect tfBounds = null;
686        Rect tfRectangle = null;
687        if (SymbolUtilities.isTaskForce(symbolID) && SymbolUtilities.hasModifier(symbolID, Modifiers.D_TASK_FORCE_INDICATOR))
688        {
689
690            int height = Math.round(symbolBounds.height() / 4.0f);
691            int width = Math.round(symbolBounds.width() / 3.0f);
692
693            if(!SymbolUtilities.hasRectangleFrame(symbolID))
694            {
695                height = (int)Math.round(symbolBounds.height() / 6.0f);
696            }
697
698            tfRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
699                    (int) symbolBounds.top - height,
700                    width,
701                    height);
702
703            tfBounds = RectUtilities.makeRect(tfRectangle.left + -1,
704                    tfRectangle.top - 1,
705                    tfRectangle.width() + 2,
706                    tfRectangle.height() + 2);
707
708            if (echelonBounds != null)
709            {
710                /*tfRectangle = new Rect(echelonBounds.left,
711                        echelonBounds.top,// + outlineOffset,
712                        echelonBounds.right,
713                        symbolBounds.top-1);
714                tfBounds = new Rect(tfRectangle);*/
715
716                int tfx = tfRectangle.left;
717                int tfw = tfRectangle.width();
718                int tfy = tfRectangle.top;
719                int tfh = tfRectangle.height();
720
721                if(echelonBounds.width() > tfRectangle.width())
722                {
723                    tfx = symbolBounds.left + symbolBounds.width()/2 - (echelonBounds.width()/2) - 1;
724                    tfw = echelonBounds.width()+2;
725                }
726                if(echelonBounds.height() > tfRectangle.height())
727                {
728                    tfy = echelonBounds.top-1;
729                    tfh = echelonBounds.height()+2;
730
731                }
732                tfRectangle = RectUtilities.makeRect((int)tfx,
733                        tfy,// + outlineOffset,
734                        tfw,
735                        tfh);
736
737
738                tfBounds = RectUtilities.makeRect((tfRectangle.left - 1),
739                        (tfRectangle.top - 1),
740                        (tfRectangle.width() + 2),
741                        (tfRectangle.height() + 2));
742            }
743
744            imageBounds.union(tfBounds);
745        }
746        // </editor-fold>
747
748        // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
749        Rect fdiBounds = null;
750        Point fdiTop = null;
751        Point fdiLeft = null;
752        Point fdiRight = null;
753
754
755        if (SymbolUtilities.hasFDI(symbolID)
756                && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AB_FEINT_DUMMY_INDICATOR))
757        {
758            //create feint indicator /\
759            fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
760            fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
761            fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
762
763
764            fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
765            fdiBounds.union(fdiTop.x, fdiTop.y);
766            fdiBounds.union(fdiRight.x, fdiRight.y);
767
768            float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
769            RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
770
771            if (echelonBounds != null)
772            {
773                int shiftY = Math.round(symbolBounds.top - echelonBounds.height() - 2);
774                fdiLeft.offset(0, shiftY);
775                fdiTop.offset(0, shiftY);
776                fdiRight.offset(0, shiftY);
777                fdiBounds.offset(0, shiftY);
778            }
779
780            imageBounds.union(fdiBounds);
781
782        }
783        // </editor-fold>
784
785        //Using SVG files for installation indicator now
786        // <editor-fold defaultstate="collapsed" desc="Build Installation">
787        /*//Using SVG files for the installation indicator
788        Rect instRectangle = null;
789        Rect instBounds = null;
790        if (SymbolUtilities.hasInstallationModifier(symbolID)
791                && SymbolUtilitiesD.canSymbolHaveModifier(symbolID, Modifiers.AC_INSTALLATION))
792        {//the actual installation symbols have the modifier
793            //built in.  everything else, we have to draw it.
794            //
795            ////get indicator dimensions////////////////////////////////
796            int width;
797            int height;
798            char affiliation = SymbolUtilities.getAffiliation(symbolID);
799
800            if (affiliation == 'F'
801                    || affiliation == 'A'
802                    || affiliation == 'D'
803                    || affiliation == 'M'
804                    || affiliation == 'J'
805                    || affiliation == 'K')
806            {
807                //4th height, 3rd width
808                height = Math.round(symbolBounds.height() / 4);
809                width = Math.round(symbolBounds.width() / 3);
810            }
811            else if (affiliation == 'H' || affiliation == 'S')//hostile,suspect
812            {
813                //6th height, 3rd width
814                height = Math.round(symbolBounds.height() / 6);
815                width = Math.round(symbolBounds.width() / 3);
816            }
817            else if (affiliation == 'N' || affiliation == 'L')//neutral,exercise neutral
818            {
819                //6th height, 3rd width
820                height = Math.round(symbolBounds.height() / 6);
821                width = Math.round(symbolBounds.width() / 3);
822            }
823            else if (affiliation == 'P'
824                    || affiliation == 'U'
825                    || affiliation == 'G'
826                    || affiliation == 'W')
827            {
828                //6th height, 3rd width
829                height = Math.round(symbolBounds.height() / 6);
830                width = Math.round(symbolBounds.width() / 3);
831            }
832            else
833            {
834                //6th height, 3rd width
835                height = Math.round(symbolBounds.height() / 6);
836                width = Math.round(symbolBounds.width() / 3);
837            }
838
839//                    if(width * 3 < symbolBounds.width())
840//                        width++;
841            //set installation position/////////////////////////////////
842            //set position of indicator
843            if (affiliation == 'F'
844                    || affiliation == 'A'
845                    || affiliation == 'D'
846                    || affiliation == 'M'
847                    || affiliation == 'J'
848                    || affiliation == 'K'
849                    || affiliation == 'N'
850                    || affiliation == 'L')
851            {
852                instRectangle = RectUtilities.makeRect((int) (symbolBounds.left + width),
853                        (int) (symbolBounds.top - height),
854                        width,
855                        height);
856            }
857            else if (affiliation == 'H' || affiliation == 'S')//hostile,suspect
858            {
859                instRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
860                        Math.round((int) symbolBounds.top - (height * 0.15f)),
861                        width,
862                        height);
863            }
864            else if (affiliation == 'P'
865                    || affiliation == 'U'
866                    || affiliation == 'G'
867                    || affiliation == 'W')
868            {
869                instRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
870                        Math.round(symbolBounds.top - (height * 0.3f)),
871                        width,
872                        height);
873            }
874            else
875            {
876                instRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
877                        Math.round(symbolBounds.top - (height * 0.3f)),
878                        width,
879                        height);
880            }
881
882            //generate installation bounds//////////////////////////////
883            instBounds = new Rect(instRectangle.left + -1,
884                    instRectangle.top - 1,
885                    instRectangle.width() + 2,
886                    instRectangle.height() + 2);
887
888            imageBounds.union(instBounds);
889
890        }//*/
891        // </editor-fold>
892
893        // <editor-fold defaultstate="collapsed" desc="Build Engagement Bar (AO)">
894        //A:BBB-CC
895        String strAO = null;
896        Rect ebRectangle = null;
897        Rect ebBounds = null;
898        Rect ebTextBounds = null;
899        TextInfo ebText = null;
900
901        int ebTop = 0;
902        int ebLeft = 0;
903        int ebWidth = 0;
904        int ebHeight = 0;
905        Color ebColor = null;//SymbolUtilities.getFillColorOfAffiliation(symbolID);
906
907        if(attributes.containsKey(MilStdAttributes.EngagementBarColor))
908            ebColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.EngagementBarColor));
909        else
910            ebColor = fillColor;
911
912        if(SymbolUtilities.hasModifier(symbolID, Modifiers.AO_ENGAGEMENT_BAR) &&
913                modifiers.containsKey(Modifiers.AO_ENGAGEMENT_BAR))
914            strAO = modifiers.get(Modifiers.AO_ENGAGEMENT_BAR);
915        if(strAO != null)
916        {
917            ebText = new TextInfo(strAO, 0, 0, modifierFont, modifierFontName);
918            ebTextBounds = ebText.getTextBounds();
919            ebHeight = ebTextBounds.height() + 4;
920
921            int barOffset = Math.max(RendererSettings.getInstance().getDeviceDPI()/32, 4);
922
923            if(fdiBounds != null)//set bar above FDI if present
924            {
925                ebTop = fdiBounds.top - ebHeight - barOffset;
926            }
927            else if(tfBounds != null)//set bar above TF if present
928            {
929                ebTop = tfBounds.top - ebHeight - barOffset;
930            }
931            else if(echelonBounds != null)//set bar above echelon if present
932            {
933                ebTop = echelonBounds.top - ebHeight - barOffset;
934            }
935            else if(isCOnTop(symbolID) && modifiers.containsKey(Modifiers.C_QUANTITY))//OR frame in air/space
936            {
937                ebTop = symbolBounds.top - (int)(ebHeight*2.5f);
938            }
939            else if(ss == SymbolID.SymbolSet_LandInstallation)
940            {
941                ebTop = symbolBounds.top - ebHeight - (barOffset * 2);
942            }
943            else//position above symbol
944            {
945                ebTop = symbolBounds.top - ebHeight - barOffset;
946            }
947
948            //if text wider than symbol, extend the bar.
949            if(ebTextBounds.width() > symbolBounds.width())
950            {
951                ebWidth = ebTextBounds.width() + 4;
952                ebLeft = symbolCenter.x - (ebWidth/2);
953            }
954            else
955            {
956                ebLeft = symbolBounds.left + (int)Math.ceil(strokeWidthBasedOnDPI/2f);//1;//leave room for outline
957                ebWidth = symbolBounds.width() - (int)Math.ceil(strokeWidthBasedOnDPI);//2;//leave room for outline
958            }
959
960            //set text location within the bar
961            ebText.setLocation(symbolCenter.x - (ebTextBounds.width()/2), ebTop + ebHeight - ((ebHeight - ebTextBounds.height()) / 2));
962
963            ebRectangle = RectUtilities.makeRect(ebLeft,ebTop,ebWidth,ebHeight);
964            ebBounds = new Rect(ebRectangle);
965            RectUtilities.grow(ebBounds,(int)Math.ceil(strokeWidthBasedOnDPI/2f));
966
967            imageBounds.union(ebBounds);
968        }
969
970
971        // </editor-fold>
972
973        // <editor-fold defaultstate="collapsed" desc="Build HQ Staff">
974        Point pt1HQ = null;
975        Point pt2HQ = null;
976        Rect hqBounds = null;
977        //Draw HQ Staff
978        if (SymbolUtilities.isHQ(symbolID))
979        {
980            int affiliation = SymbolID.getAffiliation(symbolID);
981            int context = SymbolID.getContext(symbolID);
982            //get points for the HQ staff
983            if (SymbolUtilities.hasRectangleFrame(symbolID))
984            {
985                pt1HQ = new Point((int) symbolBounds.left + 1,
986                        (int) (symbolBounds.top + symbolBounds.height() - 1));
987            }
988            else
989            {
990                pt1HQ = new Point((int) symbolBounds.left + 1,
991                        (int) (symbolBounds.top + (symbolBounds.height() / 2)));
992            }
993            pt2HQ = new Point((int) pt1HQ.x, (int) (pt1HQ.y + symbolBounds.height()));
994
995            //create bounding rectangle for HQ staff.
996            hqBounds = new Rect(pt1HQ.x, pt1HQ.y, pt1HQ.x + 2, pt2HQ.y);
997            //adjust the image bounds accordingly.
998            imageBounds.union(hqBounds);
999            //imageBounds.shiftBR(0,pt2HQ.y-imageBounds.bottom);
1000            //adjust symbol center
1001            centerPoint.set(pt2HQ.x, pt2HQ.y);
1002        }
1003
1004        // </editor-fold>
1005
1006        // <editor-fold defaultstate="collapsed" desc="Build DOM Arrow">
1007        Point[] domPoints = null;
1008        Rect domBounds = null;
1009        if (modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT)
1010                && SymbolUtilities.hasModifier(symbolID, Modifiers.Q_DIRECTION_OF_MOVEMENT))
1011        {
1012                String strQ = modifiers.get(Modifiers.Q_DIRECTION_OF_MOVEMENT);
1013                
1014                if(strQ != null && SymbolUtilities.isNumber(strQ))
1015                {
1016                    float q = Float.valueOf(strQ);
1017        
1018                    boolean isY = (modifiers.containsKey(Modifiers.Y_LOCATION));
1019        
1020                    domPoints = createDOMArrowPoints(symbolID, symbolBounds, symbolCenter, q, isY, modifierFontHeight);
1021        
1022                    domBounds = new Rect(domPoints[0].x, domPoints[0].y, 1, 1);
1023        
1024                    Point temp = null;
1025                    for (int i = 1; i < 6; i++)
1026                    {
1027                        temp = domPoints[i];
1028                        if (temp != null)
1029                        {
1030                            domBounds.union(temp.x, temp.y);
1031                        }
1032                    }
1033                    imageBounds.union(domBounds);
1034                }
1035        }
1036
1037        // </editor-fold>
1038
1039        // <editor-fold defaultstate="collapsed" desc="Build Operational Condition Indicator">
1040        Rect ociBounds = null;
1041        RectF ociBoundsF = null;
1042        Rect ociShape = null;
1043        Path ociSlashShape = null;
1044        int ociOffset = Math.max(RendererSettings.getInstance().getDeviceDPI()/32, 4);
1045        if (SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AL_OPERATIONAL_CONDITION)) {
1046            if (mobilityBounds != null)
1047            {
1048                ociOffset = Math.round(mobilityBounds.bottom - symbolBounds.bottom) + 4;
1049            }
1050            if(RendererSettings.getInstance().getOperationalConditionModifierType() == RendererSettings.OperationalConditionModifierType_BAR)
1051            {
1052                ociShape = processOperationalConditionIndicator(symbolID, symbolBounds, ociOffset);
1053                if (ociShape != null)
1054                {
1055                    Rect temp = new Rect(ociShape);
1056                    RectUtilities.grow(temp, 2);
1057                    ociBounds = temp;
1058                    imageBounds.union(ociBounds);
1059                }
1060            }
1061            else//slash
1062            {
1063                ociSlashShape = processOperationalConditionIndicatorSlash(symbolID, symbolBounds);
1064                if (ociSlashShape != null)
1065                {
1066                    //build mobility bounds
1067                    ociBoundsF = new RectF();
1068                    ociBounds = new Rect();
1069                    ociSlashShape.computeBounds(ociBoundsF, true);
1070                    ociBoundsF.roundOut(ociBounds);
1071                    imageBounds.union(ociBounds);
1072                    ociBounds = null;
1073                }
1074            }
1075        }
1076
1077        // </editor-fold>
1078
1079        // <editor-fold defaultstate="collapsed" desc="Build Restricted Indicator">
1080        RectF rBounds = null;
1081        Path rPath = null;
1082        Path rPath2 = null;
1083        SVGPath rsvgPath = null;
1084        SVGPath rsvgPath2 = null;
1085        PointF rcirclePt = null;
1086        PointF rdotPt = null;
1087        float rdotRadius = 0;
1088        float rStrokeWidth = 3;
1089        if(SymbolID.getContext(symbolID) == SymbolID.StandardIdentity_Context_Restricted_Target_Reality)
1090        {
1091            // <path id="primary" d="M380,320l38,-67l40,67h-78m38,-11v-1m0,-10l0,-20" fill="yellow" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="7" />
1092            float nsTx = 0;
1093            float nsTy = 0;
1094            float ratio = 1;
1095            SVGInfo si = SVGLookup.getInstance().getSVGLInfo(SVGLookup.getFrameID(symbolID),SymbolID.getVersion(symbolID));
1096            if(symbolBounds.height() > symbolBounds.width())
1097            {
1098                double sHeight = si.getBbox().height();
1099                ratio = (float)(symbolBounds.height() / sHeight);
1100            }
1101            else
1102            {
1103                double sWidth = si.getBbox().width();
1104                ratio = (float)(symbolBounds.width() / sWidth);
1105            }
1106
1107            nsTx = (float)(si.getBbox().left * ratio) * -1;
1108            nsTy = (float)(si.getBbox().top * ratio) * -1;
1109
1110            //<path d="m373,313l53,-97l57,97l-110,0" fill="yellow" id="triangle" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="6"/>
1111            //<path d="m373,313L426,216L483,313L373,313" fill="yellow" id="triangle" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="6"/>
1112            rPath = new Path();//triangle
1113            rPath.moveTo(373f * ratio, 313f * ratio);
1114            rPath.lineTo(426f * ratio, 216f * ratio);
1115            rPath.lineTo(483f * ratio, 313f * ratio);
1116            rPath.lineTo(373f * ratio, 313f * ratio);
1117            rsvgPath = new SVGPath();//triangle
1118            rsvgPath.moveTo(373f * ratio, 313f * ratio);
1119            rsvgPath.lineTo(426f * ratio, 216f * ratio);
1120            rsvgPath.lineTo(483f * ratio, 313f * ratio);
1121            rsvgPath.lineTo(373f * ratio, 313f * ratio);
1122
1123            //<path d="M426.5,276L426.5,244" fill="none" id="line" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="10"/>
1124            rPath2 = new Path();//line
1125            rPath2.moveTo(426.5f * ratio, 276f * ratio);
1126            rPath2.lineTo(426.5f * ratio, 248f * ratio);
1127            rsvgPath2 = new SVGPath();//line
1128            rsvgPath2.moveTo(426.5f * ratio, 276f * ratio);
1129            rsvgPath2.lineTo(426.5f * ratio, 248f * ratio);
1130
1131            //<circle cx="426.5" cy="293" r="6" id="dot"/>//DOT
1132            rdotPt = new PointF(426.5f * ratio, 293 * ratio);
1133            rdotRadius = 5f * ratio;
1134
1135            //need to shift like we do the frame and main icons since it's based in that space
1136            rPath.offset(nsTx, nsTy);
1137            rPath2.offset(nsTx, nsTy);
1138            rsvgPath.shift(nsTx,nsTy);
1139            rsvgPath2.shift(nsTx,nsTy);
1140            rdotPt.offset(nsTx,nsTy);
1141            //rCircle = (Ellipse2D) txfm.createTransformedShape(rCircle);
1142
1143
1144            //RectF bounds = new RectF();
1145            //bounds = rPath.computeBounds(bounds);  //getBounds();//triangle bounds
1146            Rect bounds = rsvgPath.getBounds();
1147            rBounds = RectUtilities.makeRectF(bounds.left,bounds.top,bounds.width(), bounds.height());
1148            rStrokeWidth = (2/66.666667f) * ((float)symbolBounds.height() / SymbolUtilities.getUnitRatioHeight(symbolID));
1149            RectUtilities.grow(rBounds,(int)Math.ceil(rStrokeWidth/2));
1150            RectUtilities.grow(bounds,(int)Math.ceil(rStrokeWidth/2));
1151            imageBounds.union(bounds);
1152        }
1153        // </editor-fold>
1154
1155        // <editor-fold defaultstate="collapsed" desc="Build No Strike Indicator">
1156        RectF nsBounds = null;
1157        PointF nsCirclePt = null;
1158        float nsRadius = 0;
1159        Path nsLine = null;
1160        SVGPath nssvgLine = null;
1161        double nsStrokeWidth = 3;
1162        if(SymbolID.getContext(symbolID) == SymbolID.StandardIdentity_Context_No_Strike_Entity_Reality)
1163        {
1164            //octagon~182.08058166503906~272.0794677734375~245.8407440185547~244.85235595703125
1165            //restricted~375.44801678047673~248.63298320770264~85.1039714496415~79.36734275822477
1166            //no-strike~378.0~248.0~80.0~80.0
1167            //<circle cx="418" cy="288" fill="yellow" r="36" stroke="black" stroke-width="8"/>
1168            //<line fill="none" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" x1="390" x2="446" y1="265" y2="310"/>
1169            //nsCircle = new Ellipse(x,y,radius * 2, radius * 2);
1170            //nsLine = new Line(390 * ratio, 265 * ratio, 446 * ratio, 310 * ratio);
1171            float nsTx = 0;
1172            float nsTy = 0;
1173            float ratio = 1;
1174            SVGInfo si = SVGLookup.getInstance().getSVGLInfo(SVGLookup.getFrameID(symbolID),SymbolID.getVersion(symbolID));
1175            if(symbolBounds.height() > symbolBounds.width())
1176            {
1177                float sHeight = si.getBbox().height();
1178                ratio = symbolBounds.height() / sHeight;
1179            }
1180            else
1181            {
1182                float sWidth = si.getBbox().width();
1183                ratio = symbolBounds.width() / sWidth;
1184            }
1185
1186            nsTx = (si.getBbox().left * ratio) * -1;
1187            nsTy = (si.getBbox().top * ratio) * -1;
1188
1189            float radius = 50f * ratio;
1190            float x = 426f * ratio;
1191            float y = 267f * ratio;
1192            nsCirclePt = new PointF(x,y);
1193            nsRadius = radius;
1194            nsLine = new Path();
1195            nsLine.moveTo(390 * ratio, 235 * ratio);
1196            nsLine.lineTo(463 * ratio, 298 * ratio);
1197            nssvgLine = new SVGPath();
1198            nssvgLine.moveTo(390 * ratio, 235 * ratio);
1199            nssvgLine.lineTo(463 * ratio, 298 * ratio);
1200
1201            //need to shift like we do the frame and main icons since it's based in that space
1202            nsCirclePt.offset(nsTx,nsTy);
1203            nsLine.offset(nsTx,nsTy);
1204            nssvgLine.shift(nsTx,nsTy);
1205
1206            nsBounds = RectUtilities.makeRectF(nsCirclePt.x - radius, nsCirclePt.y - radius, radius * 2, radius * 2);
1207
1208            nsStrokeWidth = (2/66.666667) * (symbolBounds.height() / SymbolUtilities.getUnitRatioHeight(symbolID));
1209            RectUtilities.grow(nsBounds,(int)Math.ceil(nsStrokeWidth/2));
1210            imageBounds.union(RectUtilities.makeRectFromRectF(nsBounds));
1211        }
1212        // </editor-fold>
1213
1214        // <editor-fold defaultstate="collapsed" desc="Shift Modifiers">
1215        //adjust points if necessary
1216        if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
1217        {
1218            int shiftX = Math.abs(imageBounds.left);
1219            int shiftY = Math.abs(imageBounds.top);
1220
1221            if (hqBounds != null)
1222            {
1223                pt1HQ.offset(shiftX, shiftY);
1224                pt2HQ.offset(shiftX, shiftY);
1225            }
1226            if (echelonBounds != null)
1227            {
1228                tiEchelon.setLocation(tiEchelon.getLocation().x + shiftX, tiEchelon.getLocation().y + shiftY);
1229            }
1230            if (amBounds != null)
1231            {
1232                tiAM.setLocation(tiAM.getLocation().x + shiftX, tiAM.getLocation().y + shiftY);
1233            }
1234            if (tfBounds != null)
1235            {
1236                tfRectangle.offset(shiftX, shiftY);
1237                tfBounds.offset(shiftX, shiftY);
1238            }
1239            if(ebBounds != null)
1240            {
1241                ebRectangle.offset(shiftX, shiftY);
1242                ebBounds.offset(shiftX, shiftY);
1243                ebText.shift(shiftX, shiftY);
1244                ebTextBounds.offset(shiftX, shiftY);
1245            }
1246            /*if (instBounds != null)//part of symbol bounds now
1247            {
1248                instRectangle.offset(shiftX, shiftY);
1249                instBounds.offset(shiftX, shiftY);
1250            }//*/
1251            if (fdiBounds != null)
1252            {
1253                fdiBounds.offset(shiftX, shiftY);
1254                fdiLeft.offset(shiftX, shiftY);
1255                fdiTop.offset(shiftX, shiftY);
1256                fdiRight.offset(shiftX, shiftY);
1257            }
1258            if (liBounds != null)
1259            {
1260                liBounds.offset(shiftX, shiftY);
1261                liLeft.offset(shiftX, shiftY);
1262                liTop.offset(shiftX, shiftY);
1263                liRight.offset(shiftX, shiftY);
1264                if(liPath != null)
1265                {
1266                    liPath.offset(shiftX,shiftY);
1267                }
1268            }
1269            if (ociBounds != null)
1270            {
1271                ociBounds.offset(shiftX, shiftY);
1272                ociShape.offset(shiftX, shiftY);
1273            }
1274            if(ociBoundsF != null)
1275            {
1276                ociBoundsF.offset(shiftX, shiftY);
1277                ociSlashShape.offset(shiftX, shiftY);
1278            }
1279            if(rBounds != null)
1280            {
1281                rBounds.offset(shiftX, shiftY);//bounds
1282                rPath.offset(shiftX, shiftY);//triangle
1283                rPath2.offset(shiftX, shiftY);//exclamation
1284                rdotPt.offset(shiftX, shiftY);//dot
1285            }
1286            if(nsBounds != null)
1287            {
1288                nsBounds.offset(shiftX, shiftY);//bounds
1289                nsCirclePt.offset(shiftX, shiftY);//circle
1290                nsLine.offset(shiftX, shiftY);//line
1291            }
1292            if (domBounds != null)
1293            {
1294                for (int i = 0; i < 6; i++)
1295                {
1296                    Point temp = domPoints[i];
1297                    if (temp != null)
1298                    {
1299                        temp.offset(shiftX, shiftY);
1300                    }
1301                }
1302                domBounds.offset(shiftX, shiftY);
1303            }
1304            if (mobilityBounds != null)
1305            {
1306                //shift mobility points
1307                mobilityPath.offset(shiftX, shiftY);
1308                if (mobilityPathFill != null)
1309                {
1310                    mobilityPathFill.offset(shiftX, shiftY);
1311                }
1312
1313                mobilityBounds.offset(shiftX, shiftY);
1314            }
1315
1316            centerPoint.offset(shiftX, shiftY);
1317            symbolBounds.offset(shiftX, shiftY);
1318            imageBounds.offset(shiftX, shiftY);
1319        }
1320        // </editor-fold>
1321
1322        // <editor-fold defaultstate="collapsed" desc="Convert to SVG (SVGSymbolInfo)">
1323        if(sdi instanceof SVGSymbolInfo)
1324        {
1325            StringBuilder sbSVG = new StringBuilder();
1326            Path temp = null;
1327            SVGPath svgtemp = null;
1328            String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
1329            String svgFill = RendererUtilities.colorToHexString(fillColor,false);
1330            String svgTextColor = RendererUtilities.colorToHexString(textColor,false);
1331            String svgTextBGColor = RendererUtilities.colorToHexString(textBackgroundColor,false);
1332            String svgStrokeWidth = String.valueOf(strokeWidthBasedOnDPI);
1333            String svgTextOutlineWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
1334            String svgAlpha = "1";
1335            if(alpha >= 0 && alpha <= 1)
1336                svgAlpha = String.valueOf(alpha);
1337            String svgDashArray = null;
1338
1339            if(hqBounds != null)
1340            {
1341                /*Line2D hqStaff = new Line2D.Double(pt1HQ,pt2HQ);
1342                temp = new Path2D.Double();
1343                temp.append(hqStaff,false);
1344                sbSVG.append(Shape2SVG.Convert(temp, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, null));//*/
1345
1346                svgtemp = new SVGPath();
1347                svgtemp.moveTo(pt1HQ.x, pt1HQ.y);
1348                svgtemp.lineTo(pt2HQ.x, pt2HQ.y);
1349                svgtemp.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,Float.parseFloat(svgAlpha),Float.parseFloat(svgAlpha),null);
1350            }
1351            if (echelonBounds != null)
1352            {
1353                sbSVG.append(Shape2SVG.Convert(tiEchelon, svgTextBGColor, svgTextColor, svgTextOutlineWidth, svgAlpha, svgAlpha, null));
1354            }
1355            if (amBounds != null)
1356            {
1357                sbSVG.append(Shape2SVG.Convert(tiAM, svgTextBGColor, svgTextColor, svgTextOutlineWidth, svgAlpha, svgAlpha, null));
1358            }
1359            if (tfBounds != null)
1360            {
1361                sbSVG.append(Shape2SVG.Convert(tfRectangle, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, null,null));
1362            }
1363            if(ebBounds != null)
1364            {
1365                String svgEBFill = RendererUtilities.colorToHexString(ebColor,false);
1366                //create fill and outline
1367                sbSVG.append(Shape2SVG.Convert(ebRectangle, svgStroke, svgEBFill, svgStrokeWidth, svgAlpha, svgAlpha, null,null));
1368                //create internal text
1369                sbSVG.append(Shape2SVG.Convert(ebText, null, "#000000", null, svgAlpha, svgAlpha, null));
1370            }
1371            if (fdiBounds != null)
1372            {
1373                /*int dpi = RendererSettings.getInstance().getDeviceDPI();
1374                int lineLength = dpi / 96 * 6;
1375                int lineGap = dpi / 96 * 4;
1376                String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
1377
1378                /// ///////////////////////////////////
1379                //Divide line in 14 parts. line is 3 parts to 2 parts gap
1380                float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
1381                //distance = distance / 14f;
1382                int lineGap = (int)((distance / 14f) * 2);
1383                int lineLength = (int)((distance / 14f) * 3);
1384                String svgFDIDashArray = "" + lineLength + " " + lineGap;
1385                /// //////////////////////////////////
1386
1387                SVGPath fdiPath = new SVGPath();
1388
1389                fdiPath.moveTo(fdiTop.x, fdiTop.y);
1390                fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
1391                fdiPath.moveTo(fdiTop.x, fdiTop.y);
1392                fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
1393
1394                sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray,"round"));
1395
1396            }
1397            if (liBounds != null)
1398            {
1399                SVGPath svgliPath = new SVGPath();
1400                svgliPath.moveTo(liTop.x, liTop.y);
1401                svgliPath.lineTo(liLeft.x, liLeft.y);
1402                svgliPath.moveTo(liTop.x, liTop.y);
1403                svgliPath.lineTo(liRight.x, liRight.y);
1404
1405                sbSVG.append(svgliPath.toSVGElement(svgStroke,strokeWidthBasedOnDPI,null,Float.parseFloat(svgAlpha),Float.parseFloat(svgAlpha),"round"));
1406                //sbSVG.append(Shape2SVG.Convert(liPath, svgStroke, null, String.valueOf(liStrokeWidth), svgAlpha, svgAlpha, null));
1407            }
1408            if (ociBounds != null && ociShape != null)
1409            {
1410
1411                int status = SymbolID.getStatus(symbolID);
1412                Color statusColor = null;
1413
1414                switch (status) {
1415                    //Fully Capable
1416                    case SymbolID.Status_Present_FullyCapable:
1417                        statusColor = Color.green;
1418                        break;
1419                    //Damaged
1420                    case SymbolID.Status_Present_Damaged:
1421                        statusColor = Color.yellow;
1422                        break;
1423                    //Destroyed
1424                    case SymbolID.Status_Present_Destroyed:
1425                        statusColor = Color.red;
1426                        break;
1427                    //full to capacity(hospital)
1428                    case SymbolID.Status_Present_FullToCapacity:
1429                        statusColor = Color.blue;
1430                        break;
1431                    default:
1432                        break;
1433                }
1434
1435                String svgOCIStatusColor = RendererUtilities.colorToHexString(statusColor,false);
1436                sbSVG.append(Shape2SVG.Convert(ociBounds, null, svgStroke, svgStrokeWidth, svgAlpha, svgAlpha, null,null));
1437                sbSVG.append(Shape2SVG.Convert(ociShape, null, svgOCIStatusColor, svgStrokeWidth, svgAlpha, svgAlpha, null,null));
1438
1439                ociBounds = null;
1440                ociShape = null;
1441
1442            }
1443
1444            if (mobilityBounds != null)
1445            {
1446                if(svgMobilityGroup != null)
1447                    sbSVG.append(svgMobilityGroup);
1448                else if (svgMobilityPath != null)
1449                    sbSVG.append(svgMobilityPath.toSVGElement(svgStroke,strokeWidthBasedOnDPI,null,Float.parseFloat(svgAlpha),Float.parseFloat(svgAlpha),null));
1450
1451                mobilityBounds = null;
1452            }
1453
1454            //add symbol
1455            ssi = (SVGSymbolInfo)sdi;
1456            sbSVG.append(ssi.getSVG());
1457
1458            if (ociBounds != null && ociSlashShape != null)
1459            {
1460                SVGPath svgociSlash = processOperationalConditionIndicatorSlashSVG(symbolID,symbolBounds);
1461
1462                double size = symbolBounds.width();
1463                float ociStrokeWidth = 3f;
1464
1465                ociStrokeWidth = (float) size / 20f;
1466                if (ociStrokeWidth < 1f)
1467                    ociStrokeWidth = 1f;
1468
1469                sbSVG.append(svgociSlash.toSVGElement(svgStroke,ociStrokeWidth,null,Float.parseFloat(svgAlpha),Float.parseFloat(svgAlpha),null));
1470                //sbSVG.append(Shape2SVG.Convert(ociSlashShape, svgStroke, null, String.valueOf(ociStrokeWidth), svgAlpha, svgAlpha, null));
1471                ociBounds = null;
1472                ociSlashShape = null;
1473            }
1474
1475            if(rBounds != null)
1476            {
1477                String restrictedGroup = "<g id=\"restricted\" stroke-linecap=\"round\" stroke-linejoin=\"round\">";
1478                //triangle
1479                restrictedGroup += Shape2SVG.Convert(rsvgPath, "#000000", "#FFFF00", String.valueOf(rStrokeWidth),svgAlpha,svgAlpha,null,null);
1480                //exclamation
1481                restrictedGroup += Shape2SVG.Convert(rsvgPath2, "#000000", null, String.valueOf(rStrokeWidth * 1.66667),svgAlpha,svgAlpha,null,null);
1482                //dot
1483                restrictedGroup += Shape2SVG.ConvertCircle(rdotPt, rdotRadius, "#000000", "#000000", String.valueOf(rStrokeWidth),svgAlpha,svgAlpha,null);
1484                restrictedGroup += "</g>";
1485
1486                sbSVG.append(restrictedGroup);
1487            }
1488
1489            if(nsBounds != null)
1490            {
1491                String noStrikeGroup = "<g id=\"nostrike\">";
1492                noStrikeGroup += Shape2SVG.ConvertCircle(nsCirclePt, nsRadius,"#000000", "#FFFF00", String.valueOf(nsStrokeWidth),svgAlpha,svgAlpha,null);
1493                noStrikeGroup += Shape2SVG.Convert(nssvgLine, "#000000", null, String.valueOf(nsStrokeWidth),svgAlpha,svgAlpha,null,null);
1494                noStrikeGroup += "</g>";
1495                sbSVG.append(noStrikeGroup);
1496            }
1497
1498            if (domBounds != null)
1499            {
1500                //Path2D domPath = new Path2D.Double();
1501                SVGPath domPath = new SVGPath();
1502
1503                domPath.moveTo(domPoints[0].x, domPoints[0].y);
1504                if (domPoints[1] != null)
1505                {
1506                    domPath.lineTo(domPoints[1].x, domPoints[1].y);
1507                }
1508                if (domPoints[2] != null)
1509                {
1510                    domPath.lineTo(domPoints[2].x, domPoints[2].y);
1511                }
1512                //sbSVG.append(Shape2SVG.Convert(domPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, null));
1513                sbSVG.append(domPath.toSVGElement(svgStroke, Float.parseFloat(svgStrokeWidth), null,Float.parseFloat(svgAlpha), Float.parseFloat(svgAlpha),null));
1514
1515
1516                //domPath.reset();
1517                domPath = new SVGPath();
1518
1519                domPath.moveTo(domPoints[3].x, domPoints[3].y);
1520                domPath.lineTo(domPoints[4].x, domPoints[4].y);
1521                domPath.lineTo(domPoints[5].x, domPoints[5].y);
1522                sbSVG.append(Shape2SVG.Convert(domPath, "none", svgStroke, "0", svgAlpha, svgAlpha, null,null));
1523                sbSVG.append(domPath.toSVGElement("none", 0f, svgStroke,Float.parseFloat(svgAlpha), Float.parseFloat(svgAlpha),null));
1524
1525                domBounds = null;
1526                domPoints = null;
1527            }
1528
1529            newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
1530        }
1531
1532        // </editor-fold>
1533
1534        // <editor-fold defaultstate="collapsed" desc="Draw Modifiers (ImageInfo)">
1535        if(sdi instanceof ImageInfo)
1536        {
1537            ii = (ImageInfo) sdi;
1538
1539            Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
1540            Canvas ctx = new Canvas(bmp);
1541
1542            if (echelonBounds != null || amBounds != null) {
1543                //   ctx.font = RendererSettings.getModifierFont();
1544            }
1545
1546            //render////////////////////////////////////////////////////////
1547            Paint paint = new Paint();
1548            paint.setStyle(Style.STROKE);
1549            //paint.setColor(Color.black.toInt());
1550            paint.setColor(lineColor.toInt());
1551            if (alpha > -1)
1552                paint.setAlpha(alpha);
1553            paint.setStrokeWidth(2.0f);
1554
1555            paint.setStrokeWidth(strokeWidthBasedOnDPI);
1556
1557            if (hqBounds != null) {
1558                ctx.drawLine(pt1HQ.x, pt1HQ.y, pt2HQ.x, pt2HQ.y, paint);
1559            }
1560
1561            if (tfBounds != null) {
1562                ctx.drawRect(tfRectangle, paint);
1563            }
1564
1565        /*if (instBounds != null) Part of frame SVG now
1566        {
1567            paint.setStyle(Style.FILL);
1568            ctx.drawRect(instRectangle, paint);
1569        }//*/
1570
1571            if (ebBounds != null) {
1572                //draw bar fill
1573                paint.setStyle(Style.FILL);
1574                paint.setColor(ebColor.toInt());
1575                ctx.drawRect(ebRectangle, paint);
1576
1577                //draw bar outline
1578                paint.setStyle(Style.STROKE);
1579                paint.setStrokeWidth(4.0f);
1580                paint.setColor(lineColor.toInt());
1581                ctx.drawRect(ebRectangle, paint);
1582
1583                //draw bar text
1584                modifierFont.setColor(Color.BLACK.toInt());
1585                modifierFont.setStyle(Style.FILL);
1586                ctx.drawText(ebText.getText(), ebText.getLocation().x, ebText.getLocation().y, modifierFont);
1587
1588                ebBounds = null;
1589                ebText = null;
1590                ebRectangle = null;
1591                paint.setStrokeWidth(strokeWidthBasedOnDPI);//2.0f
1592            }
1593
1594            if (echelonBounds != null) {
1595                TextInfo[] aTiEchelon =
1596                        {
1597                                tiEchelon
1598                        };
1599                renderText(ctx, aTiEchelon, textColor, textBackgroundColor, modifierFont);
1600
1601                echelonBounds = null;
1602                tiEchelon = null;
1603            }
1604
1605            if (amBounds != null) {
1606                TextInfo[] aTiAM =
1607                        {
1608                                tiAM
1609                        };
1610                renderText(ctx, aTiAM, textColor, textBackgroundColor, modifierFont);
1611                amBounds = null;
1612                tiAM = null;
1613            }
1614
1615            if (fdiBounds != null) {
1616
1617                Paint fdiPaint = new Paint();
1618                fdiPaint.setAntiAlias(true);
1619                fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
1620                if (alpha > -1)
1621                    fdiPaint.setAlpha(alpha);
1622                fdiPaint.setStyle(Style.STROKE);
1623
1624                /*int dpi = RendererSettings.getInstance().getDeviceDPI();
1625
1626                int lineLength = dpi / 96 * 6;
1627                int lineGap = dpi / 96 * 4;//*/
1628
1629                /// ///////////////////////////////////
1630                //Divide line in 14 parts. line is 3 parts to 2 parts gap
1631                float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
1632                //distance = distance / 14f;
1633                int lineGap = (int)((distance / 14f) * 2);
1634                int lineLength = (int)((distance / 14f) * 3);
1635                /// //////////////////////////////////
1636
1637                fdiPaint.setPathEffect(new DashPathEffect(new float[]
1638                        {
1639                                lineLength, lineGap
1640                        }, 0));
1641
1642
1643                fdiPaint.setStrokeCap(Cap.ROUND);
1644                fdiPaint.setStrokeJoin(Join.MITER);
1645                fdiPaint.setStrokeWidth(strokeWidthBasedOnDPI);
1646
1647                Path fdiPath = new Path();
1648
1649                fdiPath.moveTo(fdiTop.x, fdiTop.y);
1650                fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
1651                fdiPath.moveTo(fdiTop.x, fdiTop.y);
1652                fdiPath.lineTo(fdiRight.x, fdiRight.y);
1653                ctx.drawPath(fdiPath, fdiPaint);
1654
1655                fdiBounds = null;
1656
1657            }
1658
1659            if (liBounds != null) {
1660
1661                Paint liPaint = new Paint();
1662                liPaint.setAntiAlias(true);
1663                liPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
1664                if (alpha > -1)
1665                    liPaint.setAlpha(alpha);
1666                liPaint.setStyle(Style.STROKE);
1667
1668                int dpi = RendererSettings.getInstance().getDeviceDPI();
1669
1670                liPaint.setStrokeCap(Cap.BUTT);
1671                liPaint.setStrokeJoin(Join.MITER);
1672                liPaint.setStrokeWidth(strokeWidthBasedOnDPI);
1673
1674                ctx.drawPath(liPath, liPaint);
1675
1676                liBounds = null;
1677
1678            }
1679
1680            if (mobilityBounds != null) {
1681                Paint mobilityPaint = new Paint();
1682                mobilityPaint.setStyle(Style.STROKE);
1683                //mobilityPaint.setColor(Color.black.toInt());
1684                mobilityPaint.setColor(lineColor.toInt());
1685                if (alpha > -1)
1686                    mobilityPaint.setAlpha(alpha);
1687
1688                //ctx.lineCap = "butt";
1689                //ctx.lineJoin = "miter";
1690                if (ad >= SymbolID.Mobility_WheeledLimitedCrossCountry && ad < SymbolID.Mobility_ShortTowedArray)//mobility
1691                {
1692                    //mobilityPaint.setStrokeWidth(3f);
1693                    mobilityPaint.setStrokeWidth(strokeWidthBasedOnDPI);
1694                    mobilityPaint.setAntiAlias(true);
1695                } else //towed-array
1696                {
1697                    //mobilityPaint.setStrokeWidth(3f);
1698                    mobilityPaint.setStrokeWidth(strokeWidthBasedOnDPI);
1699                    //mobilityPaint.setAntiAlias(true);
1700                }
1701
1702                ctx.drawPath(mobilityPath, mobilityPaint);
1703
1704                if (mobilityPathFill != null) {
1705                    mobilityPaint.setStyle(Style.FILL);
1706                    ctx.drawPath(mobilityPathFill, mobilityPaint);
1707                }
1708
1709                mobilityBounds = null;
1710
1711            }
1712
1713            if (ociBounds != null) {
1714                Paint ociPaint = new Paint();
1715
1716                int statusColor = 0;
1717                int status = SymbolID.getStatus(symbolID);
1718                if (status == (SymbolID.Status_Present_FullyCapable))//Fully Capable
1719                {
1720                    statusColor = Color.green.toInt();
1721                } else if (status == (SymbolID.Status_Present_Damaged))//Damage
1722                {
1723                    statusColor = Color.yellow.toInt();
1724                } else if (status == (SymbolID.Status_Present_Destroyed)) {
1725                    statusColor = Color.red.toInt();
1726                } else if (status == (SymbolID.Status_Present_FullToCapacity))//full to capacity(hospital)
1727                {
1728                    statusColor = Color.blue.toInt();
1729                }
1730
1731                ociPaint.setColor(lineColor.toInt());
1732                ociPaint.setStyle(Style.FILL);
1733
1734                if (alpha > -1)
1735                    ociPaint.setAlpha(alpha);
1736                ctx.drawRect(ociBounds, ociPaint);
1737                ociPaint.setColor(statusColor);
1738                if (alpha > -1)
1739                    ociPaint.setAlpha(alpha);
1740                ctx.drawRect(ociShape, ociPaint);
1741
1742                ociBounds = null;
1743                ociShape = null;
1744            }
1745
1746            //draw original icon.
1747            //ctx.drawImage(ii.getImage(),symbolBounds.left, symbolBounds.top);
1748            ctx.drawBitmap(ii.getImage(), null, symbolBounds, null);
1749
1750            if(rBounds != null)
1751            {
1752                Paint rPaint = new Paint();
1753                rPaint.setColor(Color.YELLOW.toInt());
1754                rPaint.setAlpha(alpha);
1755                rPaint.setStrokeCap(Cap.ROUND);
1756                rPaint.setStrokeJoin(Join.ROUND);
1757                rPaint.setStyle(Style.FILL);
1758                //triangle fill
1759                ctx.drawPath(rPath, rPaint);
1760
1761                //triangle outline
1762                rPaint.setStrokeWidth(rStrokeWidth);
1763                rPaint.setStyle(Style.STROKE);
1764                rPaint.setColor(Color.BLACK.toInt());
1765                ctx.drawPath(rPath, rPaint);
1766
1767                //exclamation line
1768                rPaint.setStrokeWidth(rStrokeWidth * 1.66667f);
1769                ctx.drawPath(rPath2, rPaint);
1770
1771                //exclamation dot
1772                rPaint.setStrokeWidth(rStrokeWidth);
1773                rPaint.setStyle(Style.FILL_AND_STROKE);
1774                ctx.drawCircle(rdotPt.x,rdotPt.y,rdotRadius,rPaint);
1775
1776            }
1777            if(nsBounds != null)
1778            {
1779                Paint nsPaint = new Paint();
1780                nsPaint.setColor(Color.YELLOW.toInt());
1781                nsPaint.setAlpha(alpha);
1782                nsPaint.setStrokeCap(Cap.ROUND);
1783                nsPaint.setStrokeJoin(Join.ROUND);
1784                nsPaint.setStyle(Style.FILL);
1785
1786                //circle fill
1787                ctx.drawCircle(nsCirclePt.x, nsCirclePt.y,nsRadius,nsPaint);
1788
1789                //circle outline
1790                nsPaint.setStyle(Style.STROKE);
1791                nsPaint.setColor(Color.BLACK.toInt());
1792                nsPaint.setStrokeWidth((float)nsStrokeWidth);
1793                ctx.drawCircle(nsCirclePt.x,nsCirclePt.y,nsRadius,nsPaint);
1794
1795                //draw slash
1796                ctx.drawPath(nsLine,nsPaint);
1797
1798            }
1799
1800            if (domBounds != null) {
1801                drawDOMArrow(ctx, domPoints, alpha, lineColor);
1802
1803                domBounds = null;
1804                domPoints = null;
1805            }
1806
1807            if (ociBoundsF != null) {
1808                Paint ociPaint = new Paint();
1809                int size = symbolBounds.width();
1810                float ociStrokeWidth = 3f;
1811
1812                ociStrokeWidth = size / 20f;
1813                if (ociStrokeWidth < 1f)
1814                    ociStrokeWidth = 1f;
1815            /*if(size > 50 && size < 100)
1816                ociStrokeWidth = 5f;
1817            else if(size >= 100 && size < 200)
1818                ociStrokeWidth = 7f;
1819            else if(size >= 200)
1820                ociStrokeWidth = 10f;*/
1821                //ociPaint.setColor(Color.black.toInt());
1822                ociPaint.setColor(lineColor.toInt());
1823                if (alpha > -1)
1824                    ociPaint.setAlpha(alpha);
1825                ociPaint.setStrokeWidth(ociStrokeWidth);
1826                ociPaint.setStrokeCap(Cap.BUTT);
1827                ociPaint.setStyle(Style.STROKE);
1828                ociPaint.setAntiAlias(true);
1829                ctx.drawPath(ociSlashShape, ociPaint);
1830
1831                ociBoundsF = null;
1832                ociSlashShape = null;
1833            }
1834
1835
1836            if (bmp != null)
1837                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
1838        }
1839        // </editor-fold>
1840
1841        // <editor-fold defaultstate="collapsed" desc="Cleanup">
1842        // </editor-fold>
1843        if (newsdi != null)
1844        {
1845            return newsdi;
1846        }
1847        else
1848        {
1849            return null;
1850        }
1851
1852    }
1853
1854    /**
1855     *
1856     * @param symbolID
1857     * @return
1858     * @deprecated no longer a thing in 2525D
1859     * TODO: remove
1860     */
1861    private static double getYPositionForSCC(String symbolID)
1862    {
1863        double yPosition = 0.32;
1864        /*int aff = SymbolID.getAffiliation(symbolID);
1865        int context = SymbolID.getContext(symbolID);
1866        char affiliation = symbolID.charAt(1);
1867
1868        if(temp.equals("WMGC--"))//GROUND (BOTTOM) MILCO
1869        {
1870            if(affiliation == 'H' || 
1871                    affiliation == 'S')//suspect
1872                yPosition = 0.29;
1873            else if(affiliation == 'N' ||
1874                    affiliation == 'L')//exercise neutral
1875                yPosition = 0.32;
1876            else if(affiliation == 'F' ||
1877                    affiliation == 'A' ||//assumed friend
1878                    affiliation == 'D' ||//exercise friend
1879                    affiliation == 'M' ||//exercise assumed friend
1880                    affiliation == 'K' ||//faker
1881                    affiliation == 'J')//joker
1882                yPosition = 0.32;
1883            else
1884                yPosition = 0.34;
1885        }
1886        else if(temp.equals("WMMC--"))//MOORED MILCO
1887        {
1888            if(affiliation == 'H' || 
1889                    affiliation == 'S')//suspect
1890                yPosition = 0.25;
1891            else if(affiliation == 'N' ||
1892                    affiliation == 'L')//exercise neutral
1893                yPosition = 0.25;
1894            else if(affiliation == 'F' ||
1895                    affiliation == 'A' ||//assumed friend
1896                    affiliation == 'D' ||//exercise friend
1897                    affiliation == 'M' ||//exercise assumed friend
1898                    affiliation == 'K' ||//faker
1899                    affiliation == 'J')//joker
1900                yPosition = 0.25;
1901            else
1902                yPosition = 0.28;
1903        }
1904        else if(temp.equals("WMFC--"))//FLOATING MILCO
1905        {
1906            if(affiliation == 'H' || 
1907                    affiliation == 'S')//suspect
1908                yPosition = 0.29;
1909            else if(affiliation == 'N' ||
1910                    affiliation == 'L')//exercise neutral
1911                yPosition = 0.32;
1912            else if(affiliation == 'F' ||
1913                    affiliation == 'A' ||//assumed friend
1914                    affiliation == 'D' ||//exercise friend
1915                    affiliation == 'M' ||//exercise assumed friend
1916                    affiliation == 'K' ||//faker
1917                    affiliation == 'J')//joker
1918                yPosition = 0.32;
1919            else
1920                yPosition= 0.34;
1921        }
1922        else if(temp.equals("WMC---"))//GENERAL MILCO
1923        {
1924            if(affiliation == 'H' || 
1925                    affiliation == 'S')//suspect
1926                yPosition = 0.33;
1927            else if(affiliation == 'N' ||
1928                    affiliation == 'L')//exercise neutral
1929                yPosition = 0.36;
1930            else if(affiliation == 'F' ||
1931                    affiliation == 'A' ||//assumed friend
1932                    affiliation == 'D' ||//exercise friend
1933                    affiliation == 'M' ||//exercise assumed friend
1934                    affiliation == 'K' ||//faker
1935                    affiliation == 'J')//joker
1936                yPosition = 0.36;
1937            else
1938                yPosition = 0.36;
1939        }*/
1940        
1941        return yPosition;
1942    }
1943
1944    /**
1945     *
1946     * @param {type} symbolID
1947     * @param {type} bounds symbolBounds SO.Rectangle
1948     * @param {type} center SO.Point Location where symbol is centered.
1949     * @param {type} angle in degrees
1950     * @param {Boolean} isY Boolean.
1951     * @returns {Array} of SO.Point. First 3 items are the line. Last three are
1952     * the arrowhead.
1953     */
1954    private static Point[] createDOMArrowPoints(String symbolID, Rect bounds, Point center, float angle, boolean isY, float modifierFontHeight)
1955    {
1956        Point[] arrowPoints = new Point[6];
1957        Point pt1 = null;
1958        Point pt2 = null;
1959        Point pt3 = null;
1960
1961        int affiliation = SymbolID.getAffiliation(symbolID);
1962        int context = SymbolID.getContext(symbolID);
1963        int length = 40;
1964        if (SymbolUtilities.isCBRNEvent(symbolID))
1965        {
1966            length = Math.round(bounds.height() / 2);
1967        }
1968        else if((SymbolUtilities.isHQ(symbolID)))
1969        {
1970            if(SymbolUtilities.hasRectangleFrame(symbolID))
1971                length = bounds.height();
1972            else
1973                length = (int)Math.round(bounds.height() * 0.7);
1974        }
1975        else// if(bounds.height() >= 100)
1976        {
1977            length = (int)Math.round(bounds.height() * 0.7);
1978        }
1979
1980        //get endpoint
1981        int dx2, dy2,
1982                x1, y1,
1983                x2, y2;
1984
1985        x1 = Math.round(center.x);
1986        y1 = Math.round(center.y);
1987
1988        pt1 = new Point(x1, y1);
1989
1990        if (SymbolUtilities.hasModifier(symbolID, Modifiers.Q_DIRECTION_OF_MOVEMENT ) &&
1991            SymbolUtilities.isCBRNEvent(symbolID) ||
1992                SymbolUtilities.isLand(symbolID) ||
1993                SymbolID.getSymbolSet(symbolID)==SymbolID.SymbolSet_DismountedIndividuals)
1994        {
1995            //drawStaff = true;
1996            if(SymbolUtilities.isHQ(symbolID)==false)//has HQ staff to start from
1997            {
1998                y1 = bounds.top + bounds.height();
1999                pt1 = new Point(x1, y1);
2000
2001                if (isY == true && SymbolUtilities.isCBRNEvent(symbolID))//make room for y modifier
2002                {
2003                    int yModifierOffset = (int) modifierFontHeight;
2004
2005                    yModifierOffset += RS.getTextOutlineWidth();
2006
2007                    pt1.offset(0, yModifierOffset);
2008                }
2009
2010                y1 = y1 + length;
2011                pt2 = new Point(x1, y1);
2012            }
2013            else
2014            {
2015                x1 = bounds.left+1;
2016                pt2 = new Point(x1, y1);
2017                if(SymbolUtilities.hasRectangleFrame(symbolID))
2018                {
2019                    /*y1 = bounds.top + bounds.height();
2020                    pt1 = new Point(x1, y1);
2021                    y1 = y1 + length;
2022                    pt2 = new Point(x1, y1);//*/
2023
2024                    pt1.x = x1;
2025                    y1 = bounds.top + (bounds.height());
2026                    pt1.y = y1;
2027                    x2 = x1;
2028                    pt2.x = x2;
2029                    y1 = pt1.y + bounds.height();
2030                    pt2.y = y1;//*/
2031
2032                }
2033                else
2034                {
2035                    pt1.x = x1;
2036                    y1 = bounds.top + (bounds.height() / 2);
2037                    pt1.y = y1;
2038                    x2 = x1;
2039                    pt2.x = x2;
2040                    y1 = pt1.y + bounds.height();
2041                    pt2.y = y1;
2042                }
2043            }
2044        }
2045
2046            //get endpoint given start point and an angle
2047        //x2 = x1 + (length * Math.cos(radians)));
2048        //y2 = y1 + (length * Math.sin(radians)));
2049        angle = angle - 90;//in java, east is zero, we want north to be zero
2050        double radians = 0;
2051        radians = (angle * (Math.PI / 180));//convert degrees to radians
2052
2053        dx2 = x1 + (int) (length * Math.cos(radians));
2054        dy2 = y1 + (int) (length * Math.sin(radians));
2055        x2 = Math.round(dx2);
2056        y2 = Math.round(dy2);
2057
2058
2059        //UPDATED ARROWHEAD CODE
2060        Point[] head = null;
2061        Point endPoint = new Point((int) x2, (int) y2);
2062        if(pt2 != null)
2063            head = createDOMArrowHead(pt2, endPoint);//pt3);
2064        else
2065            head = createDOMArrowHead(pt1, endPoint);//pt3);
2066
2067        if(head != null)
2068        {
2069            arrowPoints[0] = pt1;
2070            arrowPoints[1] = pt2;
2071            arrowPoints[2] = pt3;
2072            arrowPoints[3] = head[0];
2073            arrowPoints[4] = head[1];
2074            arrowPoints[5] = head[2];
2075
2076            //adjusted endpoint
2077            if(head.length >= 4 && head[3] != null)
2078            {
2079                arrowPoints[2] = head[3];
2080            }
2081        }
2082
2083        return arrowPoints;
2084
2085    }
2086
2087    private static Point[] createDOMArrowHead(Point lpt1, Point lpt2)
2088    {
2089        Point[] arrowPoints = new Point[6];
2090        Point pt1 = null;
2091        Point pt2 = null;
2092        Point pt3 = null;
2093
2094        int x1 = lpt1.x;
2095        int y1 = lpt1.y;
2096        int x2 = lpt2.x;
2097        int y2 = lpt2.y;
2098
2099        // Compute direction vector
2100        double dx = x2 - x1;
2101        double dy = y2 - y1;
2102        double length = Math.sqrt(dx * dx + dy * dy);
2103
2104        // Scale triangle size
2105        double scale = length * 0.1;  // Scaling factor for size
2106        double offset = scale * 1.5;  // Move triangle further down the line
2107
2108        // Normalize direction vector
2109        double unitX = dx / length;
2110        double unitY = dy / length;
2111
2112        // Compute perpendicular vector for triangle base
2113        double nx = -unitY;
2114        double ny = unitX;
2115
2116        // Compute adjusted triangle vertices
2117        int tipX = x2;
2118        int tipY = y2;
2119        int baseX1 = (int) (x2 - offset * unitX + scale * nx);
2120        int baseY1 = (int) (y2 - offset * unitY + scale * ny);
2121        int baseX2 = (int) (x2 - offset * unitX - scale * nx);
2122        int baseY2 = (int) (y2 - offset * unitY - scale * ny);
2123
2124
2125        //arrowHead = new Polygon(xPoints, yPoints, 3);
2126        arrowPoints[0] = new Point(tipX,tipY);
2127        arrowPoints[1] = new Point(baseX1,baseY1);
2128        arrowPoints[2] = new Point(baseX2,baseY2);
2129        // Adjust line endpoint to be the middle of the base line of the arrowhead
2130        int adjustedX2 = (baseX1 + baseX2) / 2;
2131        int adjustedY2 = (baseY1 + baseY2) / 2;
2132        arrowPoints[3] = new Point(adjustedX2,adjustedY2);
2133
2134        return arrowPoints;
2135
2136    }
2137
2138    private static void drawDOMArrow(Canvas ctx, Point[] domPoints, int alpha, Color lineColor)
2139    {
2140        float domStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
2141        if(domStrokeWidth < 1)
2142            domStrokeWidth=1;
2143
2144
2145        Paint domPaint = new Paint();
2146        domPaint.setAntiAlias(true);
2147        domPaint.setStrokeCap(Cap.BUTT);
2148        domPaint.setStrokeJoin(Join.MITER);
2149        domPaint.setStrokeWidth(domStrokeWidth);//3
2150        domPaint.setColor(lineColor.toInt());
2151        domPaint.setStyle(Style.STROKE);
2152        if(alpha > -1)
2153            domPaint.setAlpha(alpha);
2154
2155        Path domPath = new Path();
2156        domPath.moveTo(domPoints[0].x, domPoints[0].y);
2157        if (domPoints[1] != null)
2158        {
2159            domPath.lineTo(domPoints[1].x, domPoints[1].y);
2160        }
2161        if (domPoints[2] != null)
2162        {
2163            domPath.lineTo(domPoints[2].x, domPoints[2].y);
2164        }
2165        ctx.drawPath(domPath, domPaint);
2166
2167        domPath.reset();
2168        domPaint.setStyle(Style.FILL);
2169        domPath.moveTo(domPoints[3].x, domPoints[3].y);
2170        domPath.lineTo(domPoints[4].x, domPoints[4].y);
2171        domPath.lineTo(domPoints[5].x, domPoints[5].y);
2172        ctx.drawPath(domPath, domPaint);
2173    }
2174
2175    private static Rect processOperationalConditionIndicator(String symbolID, Rect symbolBounds, int offsetY)
2176    {
2177        //create Operational Condition Indicator
2178        //set color
2179        Rect bar = null;
2180        int status;
2181        Color statusColor;
2182        int barSize = 0;
2183        int pixelSize = symbolBounds.height();
2184
2185        status = SymbolID.getStatus(symbolID);
2186        if (status == SymbolID.Status_Present_FullyCapable ||
2187                status == SymbolID.Status_Present_Damaged ||
2188                status == SymbolID.Status_Present_Destroyed ||
2189                status == SymbolID.Status_Present_FullToCapacity)
2190        {
2191            if (pixelSize > 0)
2192            {
2193                barSize = Math.round(pixelSize / 5);
2194            }
2195
2196            if (barSize < 2)
2197            {
2198                barSize = 2;
2199            }
2200
2201            offsetY += Math.round(symbolBounds.top + symbolBounds.height());
2202
2203            bar = RectUtilities.makeRect(symbolBounds.left + 2, offsetY, Math.round(symbolBounds.width()) - 4, barSize);
2204        }
2205
2206        return bar;
2207    }
2208
2209    private static Path processOperationalConditionIndicatorSlash(String symbolID, Rect symbolBounds)
2210    {
2211        //create Operational Condition Indicator
2212        Path path = null;
2213        int status;
2214        status = SymbolID.getStatus(symbolID);
2215
2216        if (status == SymbolID.Status_Present_Damaged  || status == SymbolID.Status_Present_Destroyed)
2217        {
2218            float widthRatio = SymbolUtilities.getUnitRatioWidth(symbolID);
2219            float heightRatio = SymbolUtilities.getUnitRatioHeight(symbolID);
2220
2221            float slashHeight = (symbolBounds.height() / heightRatio * 1.47f);
2222            float slashWidth = (symbolBounds.width() / widthRatio * 0.85f);
2223            float centerX = symbolBounds.exactCenterX();
2224            float centerY = symbolBounds.exactCenterY();
2225            path = new Path();
2226            if(status == SymbolID.Status_Present_Damaged)//Damaged /
2227            {
2228                path.moveTo(centerX - (slashWidth/2),centerY+(slashHeight/2));
2229                path.lineTo(centerX + (slashWidth/2),centerY-(slashHeight/2));
2230            }
2231            else if(status == SymbolID.Status_Present_Destroyed)//Destroyed X
2232            {
2233                path.moveTo(centerX - (slashWidth/2),centerY+(slashHeight/2));
2234                path.lineTo(centerX + (slashWidth/2),centerY-(slashHeight/2));
2235                path.moveTo(centerX - (slashWidth/2),centerY-(slashHeight/2));
2236                path.lineTo(centerX + (slashWidth/2),centerY+(slashHeight/2));
2237            }
2238            return path;
2239
2240        }
2241
2242        return path;
2243    }
2244
2245    private static SVGPath processOperationalConditionIndicatorSlashSVG(String symbolID, Rect symbolBounds)
2246    {
2247        //create Operational Condition Indicator
2248        SVGPath path = null;
2249        int status;
2250        status = SymbolID.getStatus(symbolID);
2251
2252        if (status == SymbolID.Status_Present_Damaged  || status == SymbolID.Status_Present_Destroyed)
2253        {
2254            float widthRatio = SymbolUtilities.getUnitRatioWidth(symbolID);
2255            float heightRatio = SymbolUtilities.getUnitRatioHeight(symbolID);
2256
2257            float slashHeight = (symbolBounds.height() / heightRatio * 1.47f);
2258            float slashWidth = (symbolBounds.width() / widthRatio * 0.85f);
2259            float centerX = symbolBounds.exactCenterX();
2260            float centerY = symbolBounds.exactCenterY();
2261            path = new SVGPath();
2262            if(status == SymbolID.Status_Present_Damaged)//Damaged /
2263            {
2264                path.moveTo(centerX - (slashWidth/2),centerY+(slashHeight/2));
2265                path.lineTo(centerX + (slashWidth/2),centerY-(slashHeight/2));
2266            }
2267            else if(status == SymbolID.Status_Present_Destroyed)//Destroyed X
2268            {
2269                path.moveTo(centerX - (slashWidth/2),centerY+(slashHeight/2));
2270                path.lineTo(centerX + (slashWidth/2),centerY-(slashHeight/2));
2271                path.moveTo(centerX - (slashWidth/2),centerY-(slashHeight/2));
2272                path.lineTo(centerX + (slashWidth/2),centerY+(slashHeight/2));
2273            }
2274            return path;
2275
2276        }
2277
2278        return path;
2279    }
2280
2281
2282    public static SymbolDimensionInfo processSpeedLeader(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
2283    {
2284        SymbolDimensionInfo rsdi = sdi;
2285
2286        Rect imageBounds = sdi.getImageBounds();
2287        Rect symbolBounds = sdi.getSymbolBounds();
2288        Point symbolCenter = sdi.getCenterPoint();
2289        int ss = SymbolID.getSymbolSet(symbolID);
2290        int pixelSize = RendererSettings.getInstance().getDefaultPixelSize();
2291        int dpi = RendererSettings.getInstance().getDeviceDPI();
2292        if(attributes.containsKey(MilStdAttributes.PixelSize))
2293            pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize));
2294        float strokeWidth = 3f;
2295        strokeWidth = (float) dpi / 48f;
2296        if (strokeWidth < 1f)
2297            strokeWidth = 1f;
2298
2299        Path slPath = null;
2300        SVGPath slsvgPath = null;
2301        Rect slBounds = null;
2302        try {
2303            if (SymbolUtilities.hasModifier(symbolID, Modifiers.AJ_SPEED_LEADER) &&
2304                    (modifiers.containsKey(Modifiers.AJ_SPEED_LEADER))) {
2305                String aj = modifiers.get(Modifiers.AJ_SPEED_LEADER);
2306                String[] values = aj.split(" ");
2307                if (values.length >= 3) {
2308                    int speed = Integer.parseInt(values[0]);
2309                    String speedUnit = values[1];
2310                    int angle = 0;
2311                    if (values[2].length() == 3)
2312                        angle = Integer.parseInt(values[2]) - 90;
2313                    else
2314                        angle = (int) (Integer.parseInt(values[2]) * 0.05625) - 90;
2315
2316                    slPath = new Path();
2317                    slPath.moveTo(symbolCenter.x, symbolCenter.y);
2318                    slsvgPath = new SVGPath();
2319                    slsvgPath.moveTo(symbolCenter.x, symbolCenter.y);
2320
2321                    //convert to Knots
2322                    switch (speedUnit)//KPH, KPS, MPH, NMH, KTS//https://www.aviationhunt.com/speed-converter/
2323                    {
2324                        case "KPH":
2325                            speed = (int) (speed * 0.539957);
2326                            break;
2327                        case "KPS"://https://www.metric-conversions.org/speed/kilometers-per-second-to-knots.htm
2328                            speed = (int) (speed * 1943.84);
2329                            break;
2330                        case "MPH":
2331                            speed = (int) (speed * 0.86897);
2332                            break;
2333                    }
2334
2335                    int distance = 0;
2336                    char frame = SymbolID.getFrameShape(symbolID);
2337                    boolean fast = false;
2338                    if (frame == '0' && ss == SymbolID.SymbolSet_Air ||
2339                            ss == SymbolID.SymbolSet_AirMissile ||
2340                            ss == SymbolID.SymbolSet_SignalsIntelligence_Air ||
2341                            ss == SymbolID.SymbolSet_SpaceMissile ||
2342                            ss == SymbolID.SymbolSet_Space ||
2343                            (SymbolID.getVersion(symbolID) <= SymbolID.Version_2525Dch1 && ss == SymbolID.SymbolSet_SignalsIntelligence_Space))
2344                    {
2345                        fast = true;
2346                    }
2347                    else if(frame == SymbolID.FrameShape_Air || frame == SymbolID.FrameShape_Space)
2348                    {
2349                        fast = true;
2350                    }
2351
2352                    float distanceScaler = dpi;//spec does scale by inch, but if the symbol is too big, scale by pixel size
2353                    if(dpi < pixelSize)
2354                        distanceScaler = pixelSize;
2355
2356                    if(fast)
2357                    {//aircraft might be 1/4 inch if its speed is less than 300 knots, 1/2 inch if its speed is between 300 and 600 knots and 3/4 inch if its speed is more than 600 knots.
2358                        if (speed < 300)
2359                            distance = (int) (distanceScaler * 0.25)/300 * speed;
2360                        else if (speed < 600)
2361                            distance = (int) (distanceScaler * 0.5)/600 * speed;
2362                        else
2363                            distance = (int) (distanceScaler * 0.75);
2364                    }
2365                    else//submarine might be 1/4 inch if its speed is less than 15 knots, 1/2 inch if its speed is between 15 and 30 knots and 3/4 inch if its speed is more than 30 knots
2366                    {
2367                        if (speed < 15)
2368                            distance = (int) (distanceScaler * 0.25)/15 * speed;
2369                        else if (speed < 30)
2370                            distance = (int) (distanceScaler * 0.5)/30 * speed;
2371                        else
2372                            distance = (int) (distanceScaler * 0.75);
2373                    }
2374                    double radians = (angle * (Math.PI / 180));//convert degrees to radians
2375                    int x2 = (int) (symbolCenter.x + distance * Math.cos(radians));
2376                    int y2 = (int) (symbolCenter.y + distance * Math.sin(radians));
2377
2378                    slPath.lineTo(x2, y2);
2379                    slsvgPath.lineTo(x2, y2);
2380                    slBounds = slsvgPath.getBounds();
2381                    imageBounds.union(slBounds);
2382                }
2383
2384                if (sdi instanceof ImageInfo) {
2385                    Bitmap bmp = Bitmap.createBitmap((int) Math.ceil(imageBounds.width()), (int) Math.ceil(imageBounds.height()), Config.ARGB_8888);
2386                    Canvas ctx = new Canvas(bmp);
2387
2388                    int alpha = 1;
2389                    if (attributes.containsKey(MilStdAttributes.Alpha))
2390                        alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
2391
2392
2393                    Paint slPaint = new Paint();
2394                    slPaint.setColor(Color.BLACK.toInt());
2395                    slPaint.setAlpha(alpha * 255);
2396                    slPaint.setStyle(Style.STROKE);
2397                    slPaint.setStrokeWidth(strokeWidth);
2398
2399
2400                    float offsetX = 0;
2401                    float offsetY = 0;
2402                    if (imageBounds.left < 0)
2403                        offsetX = imageBounds.left * -1;
2404                    if (imageBounds.top < 0)
2405                        offsetY = imageBounds.top * -1;
2406
2407                    slPath.offset(offsetX,offsetY);
2408
2409                    ctx.drawBitmap(((ImageInfo) sdi).getImage(), offsetX, offsetY, null);
2410                    ctx.drawPath(slPath,slPaint);
2411
2412                    imageBounds.offset((int)offsetX,(int)offsetY);
2413                    symbolBounds.offset((int)offsetX,(int)offsetY);
2414                    symbolCenter.offset((int)offsetX,(int)offsetY);
2415
2416                    rsdi = new ImageInfo(bmp, symbolCenter, symbolBounds);
2417                }
2418                else if (sdi instanceof SVGSymbolInfo)
2419                {//public static String Convert(Shape shape,String stroke, String fill, String strokeWidth, String strokeOpacity, String fillOpacity, String dashArray, String lineCap)
2420                    String svg = ((SVGSymbolInfo) sdi).getSVG();
2421                    svg += slsvgPath.toSVGElement("#000000",strokeWidth,"none",1,1,null);
2422                    //svg += (Shape2SVG.Convert(slPath, "#000000", "none", String.valueOf(strokeWidth),null,null,null, null));
2423                    rsdi = new SVGSymbolInfo(svg,symbolCenter,symbolBounds,imageBounds);
2424                }
2425            }
2426        }
2427        catch(Exception exc)
2428        {
2429            ErrorLogger.LogException("ModifierRenderer","processSpeedLineIndicator",exc);
2430        }
2431
2432        return rsdi;
2433    }
2434
2435    /**
2436     * uses 2525C layout which shows most modifiers
2437     * @param sdi
2438     * @param symbolID
2439     * @param modifiers
2440     * @param attributes
2441     * @return
2442     */
2443    public static SymbolDimensionInfo processUnknownTextModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
2444    {
2445        Paint modifierFont = getFont(attributes);
2446        float[] hd = getFontHeightandDescent(modifierFont);
2447        float modifierFontHeight = hd[0];
2448        float modifierFontDescent = hd[1];
2449
2450        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
2451        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
2452        {
2453            String temp = attributes.get(MilStdAttributes.FontFamily);
2454            if(temp != null && !temp.isEmpty())
2455                modifierFontName = temp;
2456        }
2457
2458        int bufferHorizontal = (int)modifierFontHeight/2;
2459        int bufferXL = bufferHorizontal;
2460        int bufferXR = bufferHorizontal;
2461        int bufferY = 2;
2462        int bufferText = 2;
2463        int x = 0;
2464        int y = 0;//best y
2465
2466        SymbolDimensionInfo  newsdi = null;
2467
2468        ArrayList<TextInfo> tiArray = new ArrayList<TextInfo>(modifiers.size());
2469
2470        int descent = (int) (modifierFontDescent + 0.5);
2471
2472        Rect labelBounds = null;
2473        int labelWidth, labelHeight;
2474
2475        Rect bounds = new Rect(sdi.getSymbolBounds());
2476        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
2477        Point centerPoint = new Point(sdi.getCenterPoint());
2478        Rect imageBounds = new Rect(sdi.getImageBounds());
2479
2480        int echelon = SymbolID.getAmplifierDescriptor(symbolID);
2481        String echelonText = SymbolUtilities.getEchelonText(echelon);
2482        String amText = SymbolUtilities.getStandardIdentityModifier(symbolID);
2483        int mobility = SymbolID.getAmplifierDescriptor(symbolID);
2484
2485        //adjust width of bounds for mobility/echelon/engagement bar which could be wider than the symbol
2486        bounds = RectUtilities.makeRect(imageBounds.left, bounds.top, imageBounds.width(), bounds.height());
2487
2488
2489        //check if text is too tall:
2490        boolean byLabelHeight = false;
2491        labelHeight = (int) (modifierFontHeight + 0.5);/* RendererUtilities.measureTextHeight(RendererSettings.getModifierFontName(),
2492         RendererSettings.getModifierFontSize(),
2493         RendererSettings.getModifierFontStyle()).fullHeight;*/
2494
2495        int maxHeight = (bounds.height());
2496        if ((labelHeight * 3) > maxHeight)
2497        {
2498            byLabelHeight = true;
2499        }
2500
2501        //Affiliation Modifier being drawn as a display modifier
2502        String affiliationModifier = null;
2503        if (RS.getDrawAffiliationModifierAsLabel() == true)
2504        {
2505            affiliationModifier = SymbolUtilities.getStandardIdentityModifier(symbolID);
2506        }
2507        if (affiliationModifier != null)
2508        {   //Set affiliation modifier
2509            modifiers.put(Modifiers.E_FRAME_SHAPE_MODIFIER, affiliationModifier);
2510            //modifiers[Modifiers.E_FRAME_SHAPE_MODIFIER] = affiliationModifier;
2511        }//*/
2512
2513
2514        //            int y0 = 0;//W            E/F
2515        //            int y1 = 0;//X/Y          G
2516        //            int y2 = 0;//V/AD/AE      H/AF
2517        //            int y3 = 0;//T            M CC
2518        //            int y4 = 0;//Z            J/K/L/N/P
2519        //
2520
2521        // <editor-fold defaultstate="collapsed" desc="Build Modifiers">
2522        String modifierValue = null;
2523        TextInfo tiTemp = null;
2524        //if(Modifiers.C_QUANTITY in modifiers
2525        if (modifiers.containsKey(Modifiers.C_QUANTITY)
2526                && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.C_QUANTITY))
2527        {
2528            String text = modifiers.get(Modifiers.C_QUANTITY);
2529            if(text != null)
2530            {
2531                    //bounds = armyc2.c5isr.renderer.utilities.RendererUtilities.getTextOutlineBounds(modifierFont, text, new SO.Point(0,0));
2532                    tiTemp = new TextInfo(text, 0, 0, modifierFont, modifierFontName);
2533                    labelBounds = tiTemp.getTextBounds();
2534                    labelWidth = labelBounds.width();
2535                    x = Math.round((symbolBounds.left + (symbolBounds.width() * 0.5f)) - (labelWidth * 0.5f));
2536                    y = Math.round(symbolBounds.top - bufferY - descent);
2537                    tiTemp.setLocation(x, y);
2538                    tiArray.add(tiTemp);
2539            }
2540        }
2541
2542        //if(Modifiers.X_ALTITUDE_DEPTH in modifiers || Modifiers.Y_LOCATION in modifiers)
2543        if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
2544        {
2545            modifierValue = null;
2546
2547            String xm = null,
2548                    ym = null;
2549
2550            if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.X_ALTITUDE_DEPTH))
2551            {
2552                xm = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);// xm = modifiers.X;
2553            }
2554            if (modifiers.containsKey(Modifiers.Y_LOCATION))
2555            {
2556                ym = modifiers.get(Modifiers.Y_LOCATION);// ym = modifiers.Y;
2557            }
2558            if (xm == null && ym != null)
2559            {
2560                modifierValue = ym;
2561            }
2562            else if (xm != null && ym == null)
2563            {
2564                modifierValue = xm;
2565            }
2566            else if (xm != null && ym != null)
2567            {
2568                modifierValue = xm + "  " + ym;
2569            }
2570
2571            if(modifierValue != null)
2572            {
2573                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2574                    labelBounds = tiTemp.getTextBounds();
2575                    labelWidth = labelBounds.width();
2576        
2577                    if (!byLabelHeight)
2578                    {
2579                        x = bounds.left - labelBounds.width() - bufferXL;
2580                        y = bounds.top + labelHeight - descent;
2581                    }
2582                    else
2583                    {
2584                        x = bounds.left - labelBounds.width() - bufferXL;
2585        
2586                        y = (bounds.height());
2587                        y = (int) ((y * 0.5) + (labelHeight * 0.5));
2588        
2589                        y = y - ((labelHeight + bufferText));
2590                        y = bounds.top + y;
2591                    }
2592        
2593                    tiTemp.setLocation(x, y);
2594                    tiArray.add(tiTemp);
2595            }
2596        }
2597
2598        if (modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) )
2599        {
2600            modifierValue = modifiers.get(Modifiers.G_STAFF_COMMENTS);
2601
2602            if(modifierValue != null)
2603            {
2604                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2605                    labelBounds = tiTemp.getTextBounds();
2606                    labelWidth = labelBounds.width();
2607        
2608                    x = bounds.left + bounds.width() + bufferXR;
2609                    if (!byLabelHeight)
2610                    {
2611                        y = bounds.top + labelHeight - descent;
2612                    }
2613                    else
2614                    {
2615                        y = (bounds.height());
2616                        y = (int) ((y * 0.5) + (labelHeight * 0.5));
2617        
2618                        y = y - ((labelHeight + bufferText));
2619                        y = bounds.top + y;
2620                    }
2621        
2622                    tiTemp.setLocation(x, y);
2623                    tiArray.add(tiTemp);
2624
2625            }
2626        }
2627
2628        if ((modifiers.containsKey(Modifiers.V_EQUIP_TYPE)) ||
2629                (modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE)) ||
2630                (modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME)))
2631        {
2632            String vm = null,
2633                    adm = null,
2634                    aem = null;
2635
2636            if (modifiers.containsKey(Modifiers.V_EQUIP_TYPE) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.V_EQUIP_TYPE))
2637            {
2638                vm = modifiers.get(Modifiers.V_EQUIP_TYPE);
2639            }
2640            if (modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AD_PLATFORM_TYPE))
2641            {
2642                adm = modifiers.get(Modifiers.AD_PLATFORM_TYPE);
2643            }
2644            if (modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
2645            {
2646                aem = modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
2647            }
2648
2649            modifierValue = "";
2650            if(vm != null && vm.equals("") == false)
2651                modifierValue = vm;
2652            if(adm != null && adm.equals("") == false)
2653                modifierValue += " " + adm;
2654            if(aem != null && aem.equals("") == false)
2655                modifierValue += " " + aem;
2656
2657            if(modifierValue != null)
2658                modifierValue = modifierValue.trim();
2659            if(modifierValue != null && modifierValue.equals("") == false)
2660            {
2661                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2662                    labelBounds = tiTemp.getTextBounds();
2663                    labelWidth = labelBounds.width();
2664        
2665                    x = bounds.left - labelBounds.width() - bufferXL;
2666        
2667                    y = (bounds.height());
2668                    y = (int) ((y * 0.5f) + ((labelHeight - descent) * 0.5f));
2669                    y = bounds.top + y;
2670        
2671                    tiTemp.setLocation(x, y);
2672                    tiArray.add(tiTemp);
2673            }
2674        }
2675
2676        if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
2677        {
2678            modifierValue = "";
2679            String hm = "",
2680                    afm = "";
2681
2682            hm = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
2683            if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
2684            {
2685                hm = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
2686            }
2687            if (modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AF_COMMON_IDENTIFIER))
2688            {
2689                afm = modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
2690            }
2691
2692            modifierValue = hm + " " + afm;
2693            modifierValue = modifierValue.trim();
2694
2695            if(modifierValue != null && modifierValue.equals("") == false)
2696            {
2697                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2698                    labelBounds = tiTemp.getTextBounds();
2699                    labelWidth = labelBounds.width();
2700        
2701                    x = bounds.left + bounds.width() + bufferXR;
2702        
2703                    y = (bounds.height());
2704                    y = (int) ((y * 0.5) + ((labelHeight - descent) * 0.5));
2705                    y = bounds.top + y;
2706        
2707                    tiTemp.setLocation(x, y);
2708                    tiArray.add(tiTemp);
2709
2710            }
2711        }
2712
2713        if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
2714        {
2715            modifierValue = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
2716
2717            if(modifierValue != null)
2718            {
2719                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2720                    labelBounds = tiTemp.getTextBounds();
2721                    labelWidth = labelBounds.width();
2722        
2723                    if (!byLabelHeight)
2724                    {
2725                        x = bounds.left - labelWidth - bufferXL;
2726                        y = bounds.top + bounds.height();
2727                    }
2728                    else
2729                    {
2730                        x = bounds.left - labelWidth - bufferXL;
2731        
2732                        y = (bounds.height());
2733                        y = (int) ((y * 0.5) + (labelHeight * 0.5));
2734        
2735                        y = y + ((labelHeight + bufferText) - descent);
2736                        y = bounds.top + y;
2737                    }
2738        
2739                    tiTemp.setLocation(x, y);
2740                    tiArray.add(tiTemp);
2741            }
2742        }
2743
2744        if (modifiers.containsKey(Modifiers.M_HIGHER_FORMATION) || modifiers.containsKey(Modifiers.AS_COUNTRY))
2745        {
2746            modifierValue = "";
2747
2748            if (modifiers.containsKey(Modifiers.M_HIGHER_FORMATION) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.M_HIGHER_FORMATION))
2749            {
2750                modifierValue += modifiers.get(Modifiers.M_HIGHER_FORMATION);
2751            }
2752            if (modifiers.containsKey(Modifiers.AS_COUNTRY))
2753            {
2754                if (modifierValue.length() > 0)
2755                {
2756                    modifierValue += " ";
2757                }
2758                modifierValue += modifiers.get(Modifiers.AS_COUNTRY);
2759            }
2760
2761            if(modifierValue.equals("")==false)
2762            {
2763                tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2764                labelBounds = tiTemp.getTextBounds();
2765                labelWidth = labelBounds.width();
2766
2767                x = bounds.left + bounds.width() + bufferXR;
2768                if (!byLabelHeight)
2769                {
2770                    y = bounds.top + bounds.height();
2771                }
2772                else
2773                {
2774                    y = (bounds.height());
2775                    y = (int) ((y * 0.5) + (labelHeight * 0.5));
2776
2777                    y = y + ((labelHeight + bufferText - descent));
2778                    y = bounds.top + y;
2779                }
2780
2781                tiTemp.setLocation(x, y);
2782                tiArray.add(tiTemp);
2783
2784            }
2785        }
2786
2787        if (modifiers.containsKey(Modifiers.Z_SPEED) )
2788        {
2789            modifierValue = modifiers.get(Modifiers.Z_SPEED);
2790
2791            if(modifierValue != null)
2792            {
2793                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2794                    labelBounds = tiTemp.getTextBounds();
2795                    labelWidth = labelBounds.width();
2796        
2797                    x = bounds.left - labelWidth - bufferXL;
2798                    if (!byLabelHeight)
2799                    {
2800                        y = Math.round(bounds.top + bounds.height() + labelHeight + bufferText);
2801                    }
2802                    else
2803                    {
2804                        y = (bounds.height());
2805                        y = (int) ((y * 0.5) + (labelHeight * 0.5));
2806        
2807                        y = y + ((labelHeight + bufferText) * 2) - (descent * 2);
2808                        y = Math.round(bounds.top + y);
2809                    }
2810        
2811                    tiTemp.setLocation(x, y);
2812                    tiArray.add(tiTemp);
2813            }
2814        }
2815
2816        if (modifiers.containsKey(Modifiers.J_EVALUATION_RATING)
2817                || modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS)//
2818                || modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP)//
2819                || modifiers.containsKey(Modifiers.N_HOSTILE)//
2820                || modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))//
2821        {
2822            modifierValue = null;
2823
2824            String jm = null,
2825                    km = null,
2826                    lm = null,
2827                    nm = null,
2828                    pm = null;
2829
2830            if (modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
2831            {
2832                jm = modifiers.get(Modifiers.J_EVALUATION_RATING);
2833            }
2834            if (modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.K_COMBAT_EFFECTIVENESS))
2835            {
2836                km = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS);
2837            }
2838            if (modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.L_SIGNATURE_EQUIP))
2839            {
2840                lm = modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
2841            }
2842            if (modifiers.containsKey(Modifiers.N_HOSTILE) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.N_HOSTILE))
2843            {
2844                nm = modifiers.get(Modifiers.N_HOSTILE);
2845            }
2846            if (modifiers.containsKey(Modifiers.P_IFF_SIF_AIS) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.P_IFF_SIF_AIS))
2847            {
2848                pm = modifiers.get(Modifiers.P_IFF_SIF_AIS);
2849            }
2850
2851            modifierValue = "";
2852            if (jm != null && jm.equals("") == false)
2853            {
2854                modifierValue = modifierValue + jm;
2855            }
2856            if (km != null && km.equals("") == false)
2857            {
2858                modifierValue = modifierValue + " " + km;
2859            }
2860            if (lm != null && lm.equals("") == false)
2861            {
2862                modifierValue = modifierValue + " " + lm;
2863            }
2864            if (nm != null && nm.equals("") == false)
2865            {
2866                modifierValue = modifierValue + " " + nm;
2867            }
2868            if (pm != null && pm.equals("") == false)
2869            {
2870                modifierValue = modifierValue + " " + pm;
2871            }
2872
2873            if (modifierValue.length() > 2 && modifierValue.charAt(0) == ' ')
2874            {
2875                modifierValue = modifierValue.substring(1);
2876            }
2877
2878            modifierValue = modifierValue.trim();
2879
2880            if(modifierValue.equals("")==false)
2881            {
2882                tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2883                labelBounds = tiTemp.getTextBounds();
2884                labelWidth = labelBounds.width();
2885
2886                x = bounds.left + bounds.width() + bufferXR;
2887                if (!byLabelHeight)
2888                {
2889                    y = Math.round(bounds.top + bounds.height() + labelHeight + bufferText);
2890                }
2891                else
2892                {
2893                    y = (bounds.height());
2894                    y = (int) ((y * 0.5) + (labelHeight * 0.5));
2895
2896                    y = y + ((labelHeight + bufferText) * 2) - (descent * 2);
2897                    y = Math.round(bounds.top + y);
2898                }
2899
2900                tiTemp.setLocation(x, y);
2901                tiArray.add(tiTemp);
2902
2903            }
2904
2905        }
2906
2907        if (modifiers.containsKey(Modifiers.W_DTG_1))
2908        {
2909            modifierValue = modifiers.get(Modifiers.W_DTG_1);
2910
2911            if(modifierValue != null)
2912            {
2913                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2914                    labelBounds = tiTemp.getTextBounds();
2915                    labelWidth = labelBounds.width();
2916        
2917                    if (!byLabelHeight)
2918                    {
2919                        x = bounds.left - labelWidth - bufferXL;
2920                        y = bounds.top - bufferY - descent;
2921                    }
2922                    else
2923                    {
2924                        x = bounds.left - labelWidth - bufferXL;
2925        
2926                        y = (bounds.height());
2927                        y = (int) ((y * 0.5) + (labelHeight * 0.5));
2928        
2929                        y = y - ((labelHeight + bufferText) * 2);
2930                        y = bounds.top + y;
2931                    }
2932        
2933                    tiTemp.setLocation(x, y);
2934                    tiArray.add(tiTemp);
2935            }
2936        }
2937
2938        if (modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.E_FRAME_SHAPE_MODIFIER))
2939        {
2940            modifierValue = null;
2941            String E = null,
2942                    F = null;
2943
2944            if (modifiers.containsKey(Modifiers.E_FRAME_SHAPE_MODIFIER))
2945            {
2946                E = modifiers.get(Modifiers.E_FRAME_SHAPE_MODIFIER);
2947                modifiers.remove(Modifiers.E_FRAME_SHAPE_MODIFIER);
2948            }
2949            if (modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.F_REINFORCED_REDUCED))
2950            {
2951                F = modifiers.get(Modifiers.F_REINFORCED_REDUCED);
2952            }
2953
2954            if (E != null && E.equals("") == false)
2955            {
2956                modifierValue = E;
2957            }
2958
2959            if (F != null && F.equals("") == false)
2960            {
2961                if (F.toUpperCase(Locale.US) == ("R"))
2962                {
2963                    F = "(+)";
2964                }
2965                else if (F.toUpperCase(Locale.US) == ("D"))
2966                {
2967                    F = "(-)";
2968                }
2969                else if (F.toUpperCase(Locale.US) == ("RD"))
2970                {
2971                    F = "(" + (char) (177) + ")";
2972                }
2973            }
2974
2975            if (F != null && F.equals("") == false)
2976            {
2977                if (modifierValue != null && modifierValue.equals("") == false)
2978                {
2979                    modifierValue = modifierValue + " " + F;
2980                }
2981                else
2982                {
2983                    modifierValue = F;
2984                }
2985            }
2986
2987            if(modifierValue != null)
2988            {
2989                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
2990                    labelBounds = tiTemp.getTextBounds();
2991                    labelWidth = labelBounds.width();
2992        
2993                    if (!byLabelHeight)
2994                    {
2995                        x = bounds.left + bounds.width() + bufferXR;
2996                        y = bounds.top - bufferY - descent;
2997                    }
2998                    else
2999                    {
3000                        x = bounds.left + bounds.width() + bufferXR;
3001        
3002                        y = (bounds.height());
3003                        y = (int) ((y * 0.5) + (labelHeight * 0.5));
3004        
3005                        y = y - ((labelHeight + bufferText) * 2);
3006                        y = bounds.top + y;
3007                    }
3008        
3009                    tiTemp.setLocation(x, y);
3010                    tiArray.add(tiTemp);
3011
3012            }
3013        }
3014
3015        if (modifiers.containsKey(Modifiers.AA_SPECIAL_C2_HQ) && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AA_SPECIAL_C2_HQ))
3016        {
3017            modifierValue = modifiers.get(Modifiers.AA_SPECIAL_C2_HQ);
3018
3019            if(modifierValue != null)
3020            {
3021                    tiTemp = new TextInfo(modifierValue, 0, 0, modifierFont, modifierFontName);
3022                    labelBounds = tiTemp.getTextBounds();
3023                    labelWidth = labelBounds.width();
3024        
3025                    x = (int) ((symbolBounds.left + (symbolBounds.width() * 0.5f)) - (labelWidth * 0.5f));
3026        
3027                    y = (symbolBounds.height());//checkpoint, get box above the point
3028                    y = (int) ((y * 0.5) + ((labelHeight - descent) * 0.5));
3029                    y = symbolBounds.top + y;
3030        
3031                    tiTemp.setLocation(x, y);
3032                    tiArray.add(tiTemp);
3033            }
3034        }
3035
3036
3037        // </editor-fold>
3038
3039        //Shift Points and Draw
3040        newsdi = shiftUnitPointsAndDraw(tiArray,sdi,attributes, modifierFont);
3041
3042        // <editor-fold defaultstate="collapsed" desc="Cleanup">
3043        tiArray = null;
3044        tiTemp = null;
3045        //tempShape = null;
3046        //ctx = null;
3047        //buffer = null;
3048        // </editor-fold>
3049
3050        return newsdi;
3051    }
3052
3053
3054    public static SymbolDimensionInfo  processSPTextModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
3055    {
3056        Paint modifierFont = getFont(attributes);
3057        float[] hd = getFontHeightandDescent(modifierFont);
3058        float modifierFontHeight = hd[0];
3059        float modifierFontDescent = hd[1];
3060
3061        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
3062        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
3063        {
3064            String temp = attributes.get(MilStdAttributes.FontFamily);
3065            if(temp != null && !temp.isEmpty())
3066                modifierFontName = temp;
3067        }
3068
3069        int bufferXL = 7;
3070        int bufferXR = 7;
3071        int bufferY = 2;
3072        int bufferText = 2;
3073        int x = 0;
3074        int y = 0;//best y
3075        SymbolDimensionInfo newsdi = null;
3076
3077        ArrayList<TextInfo> tiArray = new ArrayList<TextInfo>(modifiers.size());
3078
3079        int descent = (int) (modifierFontDescent + 0.5);
3080
3081
3082        Rect labelBounds = null;
3083        int labelWidth, labelHeight;
3084
3085        Rect bounds = new Rect(sdi.getSymbolBounds());
3086        Rect imageBounds = new Rect(sdi.getImageBounds());
3087
3088        //adjust width of bounds for mobility/echelon/engagement bar which could be wider than the symbol
3089        bounds = RectUtilities.makeRect(imageBounds.left, bounds.top, imageBounds.width(), bounds.height());
3090
3091        labelHeight = (int) (modifierFontHeight + 0.5);
3092
3093        //Affiliation Modifier being drawn as a display modifier
3094        String affiliationModifier = null;
3095        if (RS.getDrawAffiliationModifierAsLabel() == true)
3096        {
3097            affiliationModifier = SymbolUtilities.getStandardIdentityModifier(symbolID);
3098        }
3099        if (affiliationModifier != null)
3100        {   //Set affiliation modifier
3101            modifiers.put(Modifiers.E_FRAME_SHAPE_MODIFIER, affiliationModifier);
3102            //modifiers[Modifiers.E_FRAME_SHAPE_MODIFIER] = affiliationModifier;
3103        }//*/
3104
3105        //Check for Valid Country Code
3106        int cc = SymbolID.getCountryCode(symbolID);
3107        String scc = "";
3108        if(cc > 0)
3109        {
3110            scc = GENCLookup.getInstance().get3CharCode(cc);
3111        }
3112        if(!scc.isEmpty())
3113            modifiers.put(Modifiers.AS_COUNTRY, scc);
3114
3115        // <editor-fold defaultstate="collapsed" desc="Build Modifiers">
3116        String modifierValue = null;
3117        TextInfo tiTemp = null;
3118
3119
3120        List<Modifier> mods = getLabelPositionIndexes(symbolID, modifiers, attributes);
3121
3122        Modifier mod = null;
3123        for(int i = 0; i < mods.size(); i++)
3124        {
3125            mod = mods.get(i);
3126
3127            tiTemp = new TextInfo(mod.getText(), 0, 0, modifierFont, modifierFontName);
3128            labelBounds = tiTemp.getTextBounds();
3129            labelWidth = (int)labelBounds.width();
3130
3131            //on left
3132            x = (int)getLabelXPosition(bounds, labelWidth, mod.getIndexX(), modifierFontHeight);
3133            //above center V
3134            y = (int)getLabelYPosition(bounds, labelHeight, descent, bufferText, mod.getCentered(), mod.getIndexY());
3135
3136            tiTemp.setLocation(x, y);
3137            tiArray.add(tiTemp);
3138        }
3139
3140
3141        // </editor-fold>
3142
3143        //Shift Points and Draw
3144        newsdi = shiftUnitPointsAndDraw(tiArray,sdi,attributes, modifierFont);
3145
3146        // <editor-fold defaultstate="collapsed" desc="Cleanup">
3147        tiArray = null;
3148        tiTemp = null;
3149        //tempShape = null;
3150        //ctx = null;
3151        //buffer = null;
3152        // </editor-fold>
3153
3154        return newsdi;
3155    }
3156
3157    public static SymbolDimensionInfo ProcessTGSPWithSpecialModifierLayout(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes, Color lineColor)
3158    {
3159        Paint modifierFont = getFont(attributes);
3160        float[] hd = getFontHeightandDescent(modifierFont);
3161        float modifierFontHeight = hd[0];
3162        float modifierFontDescent = hd[1];
3163
3164        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
3165        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
3166        {
3167            String temp = attributes.get(MilStdAttributes.FontFamily);
3168            if(temp != null && !temp.isEmpty())
3169                modifierFontName = temp;
3170        }
3171
3172        ImageInfo ii = null;
3173        SVGSymbolInfo ssi = null;
3174
3175        int bufferXL = 6;
3176        int bufferXR = 4;
3177        int bufferY = 2;
3178        int bufferText = 2;
3179        int centerOffset = 1; //getCenterX/Y function seems to go over by a pixel
3180        int x = 0;
3181        int y = 0;
3182        int x2 = 0;
3183        int y2 = 0;
3184
3185        int outlineOffset = RS.getTextOutlineWidth();
3186        int labelHeight = 0;
3187        int labelWidth = 0;
3188        int alpha = -1;
3189        SymbolDimensionInfo newsdi = null;
3190        Color textColor = lineColor;
3191        Color textBackgroundColor = null;
3192        int ss = SymbolID.getSymbolSet(symbolID);
3193        int ec = SymbolID.getEntityCode(symbolID);
3194        int e = SymbolID.getEntity(symbolID);
3195        int et = SymbolID.getEntityType(symbolID);
3196        int est = SymbolID.getEntitySubtype(symbolID);
3197
3198        //Feint Dummy Indicator variables
3199        Rect fdiBounds = null;
3200        Point fdiTop = null;
3201        Point fdiLeft = null;
3202        Point fdiRight = null;
3203
3204        ArrayList<TextInfo> arrMods = new ArrayList<TextInfo>();
3205        boolean duplicate = false;
3206
3207        Rect bounds = new Rect(sdi.getSymbolBounds());
3208        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
3209        Point centerPoint = new Point(sdi.getCenterPoint());
3210        Rect imageBounds = new Rect(sdi.getImageBounds());
3211
3212        if (attributes.containsKey(MilStdAttributes.Alpha))
3213        {
3214            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
3215            textColor.setAlpha(alpha);
3216        }
3217
3218        centerPoint = new Point(Math.round(sdi.getCenterPoint().x), Math.round(sdi.getCenterPoint().y));
3219
3220        boolean byLabelHeight = false;
3221        labelHeight = (int) (modifierFontHeight + 0.5f);
3222
3223        int maxHeight = (symbolBounds.height());
3224        if ((labelHeight * 3) > maxHeight)
3225        {
3226            byLabelHeight = true;
3227        }
3228
3229        int descent = (int) (modifierFontDescent + 0.5f);
3230        int yForY = -1;
3231
3232        Rect labelBounds1 = null;//text.getPixelBounds(null, 0, 0);
3233        Rect labelBounds2 = null;
3234        String strText = "";
3235        String strText1 = "";
3236        String strText2 = "";
3237        TextInfo text1 = null;
3238        TextInfo text2 = null;
3239
3240
3241        if (outlineOffset > 2)
3242        {
3243            outlineOffset = ((outlineOffset - 1) / 2);
3244        }
3245        else
3246        {
3247            outlineOffset = 0;
3248        }
3249
3250
3251        // <editor-fold defaultstate="collapsed" desc="Process Special Modifiers">
3252        TextInfo ti = null;
3253        if (SymbolUtilities.isCBRNEvent(symbolID))//chemical
3254        {
3255            if ((labelHeight * 3) > bounds.height())
3256            {
3257                byLabelHeight = true;
3258            }
3259        }
3260
3261        if(ss == SymbolID.SymbolSet_ControlMeasure) {
3262            if (ec == 130500 //contact point
3263                    || ec == 130700) //decision point
3264            {
3265                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3266                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3267                    if (strText != null) {
3268                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3269                        labelWidth = Math.round(ti.getTextBounds().width());
3270                        //One modifier symbols and modifier goes in center
3271                        x = bounds.left + (int) (bounds.width() * 0.5f);
3272                        x = x - (int) (labelWidth * 0.5f);
3273                        y = bounds.top + (int) (bounds.height() * 0.4f);
3274                        y = y + (int) (labelHeight * 0.5f);
3275
3276                        ti.setLocation(Math.round(x), Math.round(y));
3277                        arrMods.add(ti);
3278                    }
3279                }
3280            } else if (ec == 212800)//harbor
3281            {
3282                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3283                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3284                    if (strText != null) {
3285                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3286                        labelWidth = Math.round(ti.getTextBounds().width());
3287                        //One modifier symbols and modifier goes in center
3288                        x = bounds.left + (int) (bounds.width() * 0.5f);
3289                        x = x - (int) (labelWidth * 0.5f);
3290                        y = bounds.top + (int) (bounds.height() * 0.5f);
3291                        y = y + (int) (labelHeight * 0.5f);
3292
3293                        ti.setLocation(Math.round(x), Math.round(y));
3294                        arrMods.add(ti);
3295                    }
3296                }
3297            } else if (ec == 131300)//point of interest
3298            {
3299                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3300                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3301                    if (strText != null) {
3302                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3303                        labelWidth = Math.round(ti.getTextBounds().width());
3304                        //One modifier symbols, top third & center
3305                        x = bounds.left + (int) (bounds.width() * 0.5f);
3306                        x = x - (int) (labelWidth * 0.5f);
3307                        y = bounds.top + (int) (bounds.height() * 0.25f);
3308                        y = y + (int) (labelHeight * 0.5f);
3309
3310                        ti.setLocation(Math.round(x), Math.round(y));
3311                        arrMods.add(ti);
3312                    }
3313                }
3314            } else if (ec == 131800//waypoint
3315                    || ec == 240900)//fire support station
3316            {
3317                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3318                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3319                    if (strText != null) {
3320                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3321
3322                        //One modifier symbols and modifier goes right of center
3323                        if (ec == 131800)
3324                            x = bounds.left + (int) (bounds.width() * 0.75f);
3325                        else
3326                            x = bounds.left + (bounds.width());
3327                        y = bounds.top + (int) (bounds.height() * 0.5f);
3328                        y = y + (int) ((labelHeight - descent) * 0.5f);
3329
3330                        ti.setLocation(Math.round(x), Math.round(y));
3331                        arrMods.add(ti);
3332                    }
3333                }
3334            }
3335            else if (ec == 131900)//Airfield (AEGIS Only)
3336            {
3337                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3338                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3339                    if (strText != null) {
3340                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3341
3342                        //One modifier symbols and modifier goes right of symbol
3343
3344                        x = bounds.left + (bounds.width() + bufferXR);
3345
3346                        y = bounds.top + (int) (bounds.height() * 0.5f);
3347                        y = y + (int) ((labelHeight - descent) * 0.5f);
3348
3349                        ti.setLocation(Math.round(x), Math.round(y));
3350                        arrMods.add(ti);
3351                    }
3352                }
3353            }
3354            else if (ec == 180100 //Air Control point
3355                    || ec == 180200) //Communications Check point
3356            {
3357                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3358                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3359                    if (strText != null) {
3360                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3361                        labelWidth = ti.getTextBounds().width();
3362                        //One modifier symbols and modifier goes just below of center
3363                        x = bounds.left + (int) (bounds.width() * 0.5);
3364                        x = x - (int) (labelWidth * 0.5);
3365                        y = bounds.top + (int) (bounds.height() * 0.5f);
3366                        y = y + (int) (((bounds.height() * 0.5f) - labelHeight) / 2) + labelHeight - descent;
3367
3368                        ti.setLocation(Math.round(x), Math.round(y));
3369                        arrMods.add(ti);
3370                    }
3371                }
3372            } else if (ec == 160300 || //T (target reference point)
3373                    ec == 132000 || //T (Target Handover)
3374                    ec == 240601 || //ap,ap1,x,h (Point/Single Target)
3375                    ec == 240602) //ap (nuclear target)
3376            { //Targets with special modifier positions
3377                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)
3378                        && ec == 240601)//H //point single target
3379                {
3380                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3381                    if (strText != null) {
3382                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3383
3384                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3385                        y = bounds.top + (int) (bounds.height() * 0.75f);
3386                        y = y + (int) (labelHeight * 0.5f);
3387
3388                        ti.setLocation(Math.round(x), Math.round(y));
3389                        arrMods.add(ti);
3390                    }
3391                }
3392                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)
3393                        && ec == 240601)//X point or single target
3394                {
3395                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3396                    if (strText != null) {
3397                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3398                        labelWidth = Math.round(ti.getTextBounds().width());
3399                        x = RectUtilities.getCenterX(bounds) - (int) (bounds.width() * 0.15f);
3400                        x = x - (labelWidth);
3401                        y = bounds.top + (int) (bounds.height() * 0.75f);
3402                        y = y + (int) (labelHeight * 0.5f);
3403
3404                        ti.setLocation(Math.round(x), Math.round(y));
3405                        arrMods.add(ti);
3406                    }
3407                }
3408                strText = null;
3409                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) && (ec == 160300 || ec == 132000)) {
3410                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3411                    if (strText != null) {
3412                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3413
3414                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3415                        y = bounds.top + (int) (bounds.height() * 0.25f);
3416                        y = y + (int) (labelHeight * 0.5f);
3417
3418                        ti.setLocation(Math.round(x), Math.round(y));
3419                        arrMods.add(ti);
3420                    }
3421                }
3422                if (ec == 240601 || ec == 240602)
3423                {
3424                    if (modifiers.containsKey(Modifiers.AP_TARGET_NUMBER)) {
3425                        strText = modifiers.get(Modifiers.AP_TARGET_NUMBER);
3426                    }
3427                    if (ec == 240601 && modifiers.containsKey(Modifiers.AP1_TARGET_NUMBER_EXTENSION)) {
3428                        if (strText != null)
3429                            strText = strText + "  " + modifiers.get(Modifiers.AP1_TARGET_NUMBER_EXTENSION);
3430                        else
3431                            strText = modifiers.get(Modifiers.AP1_TARGET_NUMBER_EXTENSION);
3432                    }
3433                    if (strText != null) {
3434                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3435
3436                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3437                        y = bounds.top + (int) (bounds.height() * 0.25f);
3438                        y = y + (int) (labelHeight * 0.5f);
3439
3440                        ti.setLocation(Math.round(x), Math.round(y));
3441                        arrMods.add(ti);
3442                    }
3443                }
3444            }
3445            else if (ec == 132100)//Key Terrain
3446            {
3447                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3448                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3449                    if (strText != null) {
3450                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3451
3452                        //One modifier symbols and modifier goes right of symbol
3453
3454                        x = bounds.left + (int)(bounds.width() * 0.5) + bufferXL;
3455
3456                        y = bounds.top + (int) (bounds.height() * 0.5f);
3457                        y = y + (int) ((labelHeight - descent) * 0.5f);
3458
3459                        ti.setLocation(Math.round(x), Math.round(y));
3460                        arrMods.add(ti);
3461                    }
3462                }
3463            }
3464            else if(ec == 182600)//Isolated Personnel Location
3465            {
3466                if (modifiers.containsKey(Modifiers.C_QUANTITY)) {
3467                    strText = modifiers.get(Modifiers.C_QUANTITY);
3468                    if (strText != null) {
3469                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3470                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3471                        //subset of NBC, just nuclear
3472                        x = (int)(bounds.left + (bounds.width() * 0.5));
3473                        x = x - (int) (labelWidth * 0.5);
3474                        y = (int)bounds.top - descent;
3475                        ti.setLocation(Math.round(x), Math.round(y));
3476                        arrMods.add(ti);
3477                    }
3478                }
3479                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3480                    strText = modifiers.get(Modifiers.W_DTG_1);
3481                    if (strText != null) {
3482                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3483                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3484
3485                        x = (int)bounds.left - labelWidth - bufferXL;
3486                        if (!byLabelHeight) {
3487                            y = (int)bounds.top + labelHeight - descent;
3488                        } else {
3489                            //y = bounds.y + ((bounds.getHeight * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3490                            y = (int)(bounds.top + ((bounds.height() * 0.5) - ((labelHeight - descent) * 0.5) + (-descent - bufferText)));
3491                        }
3492
3493                        ti.setLocation(Math.round(x), Math.round(y));
3494                        arrMods.add(ti);
3495                    }
3496                }
3497                if (modifiers.containsKey(Modifiers.W1_DTG_2)) {
3498                    strText = modifiers.get(Modifiers.W1_DTG_2);
3499                    if (strText != null) {
3500                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3501                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3502
3503                        x = (int)bounds.left - labelWidth - bufferXL;
3504                        if (!byLabelHeight) {
3505                            y = (int)bounds.top + labelHeight - descent;
3506                        } else {
3507                            //y = bounds.y + ((bounds.getHeight * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3508                            y = (int)(bounds.top + ((bounds.height() * 0.5) - (((labelHeight * 2) - descent) * 0.5) + (-descent - bufferText)));
3509                        }
3510
3511                        ti.setLocation(Math.round(x), Math.round(y));
3512                        arrMods.add(ti);
3513                    }
3514                }
3515            }
3516            else if (SymbolUtilities.isCBRNEvent(symbolID)) //CBRN
3517            {
3518                if (modifiers.containsKey(Modifiers.N_HOSTILE)) {
3519                    strText = modifiers.get(Modifiers.N_HOSTILE);
3520                    if (strText != null) {
3521                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3522
3523                        x = bounds.left + bounds.width() + bufferXR;
3524
3525                        if (!byLabelHeight) {
3526                            y = bounds.top + bounds.height();
3527                        } else {
3528                            y = bounds.top + (int) ((bounds.height() * 0.5f) + ((labelHeight - descent) * 0.5) + (labelHeight - descent + bufferText));
3529                        }
3530
3531                        ti.setLocation(Math.round(x), Math.round(y));
3532                        arrMods.add(ti);
3533                    }
3534
3535                }
3536                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3537                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3538                    if (strText != null) {
3539                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3540
3541                        x = bounds.left + bounds.width() + bufferXR;
3542                        if (!byLabelHeight) {
3543                            y = bounds.top + labelHeight - descent;
3544                        } else {
3545                            //y = bounds.y + ((bounds.height * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3546                            y = bounds.top + (int) ((bounds.height() * 0.5f) - ((labelHeight - descent) * 0.5) + (-descent - bufferText));
3547                        }
3548
3549                        ti.setLocation(Math.round(x), Math.round(y));
3550                        arrMods.add(ti);
3551                    }
3552                }
3553                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3554                    strText = modifiers.get(Modifiers.W_DTG_1);
3555                    if (strText != null) {
3556                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3557                        labelWidth = Math.round(ti.getTextBounds().width());
3558
3559                        x = bounds.left - labelWidth - bufferXL;
3560                        if (!byLabelHeight) {
3561                            y = bounds.top + labelHeight - descent;
3562                        } else {
3563                            //y = bounds.y + ((bounds.height * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3564                            y = bounds.top + (int) ((bounds.height() * 0.5) - ((labelHeight - descent) * 0.5) + (-descent - bufferText));
3565                        }
3566
3567                        ti.setLocation(Math.round(x), Math.round(y));
3568                        arrMods.add(ti);
3569                    }
3570                }
3571                if ((ec == 281500 || ec == 281600) && modifiers.containsKey(Modifiers.V_EQUIP_TYPE)) {//nuclear event or nuclear fallout producing event
3572                    strText = modifiers.get(Modifiers.V_EQUIP_TYPE);
3573                    if (strText != null) {
3574                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3575
3576                        //subset of nbc, just nuclear
3577                        labelWidth = Math.round(ti.getTextBounds().width());
3578                        x = bounds.left - labelWidth - bufferXL;
3579                        y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5));//((bounds.height / 2) - (labelHeight/2));
3580
3581                        ti.setLocation(Math.round(x), Math.round(y));
3582                        arrMods.add(ti);
3583                    }
3584                }
3585                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3586                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3587                    if (strText != null) {
3588                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3589                        labelWidth = Math.round(ti.getTextBounds().width());
3590                        x = bounds.left - labelWidth - bufferXL;
3591                        if (!byLabelHeight) {
3592                            y = bounds.top + bounds.height();
3593                        } else {
3594                            //y = bounds.y + ((bounds.height * 0.5) + ((labelHeight-descent) * 0.5) + (labelHeight + bufferText));
3595                            y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5) + (labelHeight - descent + bufferText));
3596                        }
3597                        ti.setLocation(Math.round(x), Math.round(y));
3598                        arrMods.add(ti);
3599                    }
3600                }
3601                if (modifiers.containsKey(Modifiers.Y_LOCATION)) {
3602                    strText = modifiers.get(Modifiers.Y_LOCATION);
3603                    if (strText != null) {
3604                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3605                        labelWidth = Math.round(ti.getTextBounds().width());
3606                        //just NBC
3607                        //x = bounds.left + (bounds.width() * 0.5);
3608                        //x = x - (labelWidth * 0.5);
3609                        x = bounds.left + (int) (bounds.width() * 0.5f);
3610                        x = x - (int) (labelWidth * 0.5f);
3611
3612                        if (!byLabelHeight) {
3613                            y = bounds.top + bounds.height() + labelHeight - descent + bufferY;
3614                        } else {
3615                            y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5) + ((labelHeight + bufferText) * 2) - descent);
3616
3617                        }
3618                        yForY = y + descent; //so we know where to start the DOM arrow.
3619                        ti.setLocation(Math.round(x), Math.round(y));
3620                        arrMods.add(ti);
3621                    }
3622
3623                }
3624                if (modifiers.containsKey(Modifiers.C_QUANTITY)) {
3625                    strText = modifiers.get(Modifiers.C_QUANTITY);
3626                    if (strText != null) {
3627                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3628                        labelWidth = Math.round(ti.getTextBounds().width());
3629                        //subset of NBC, just nuclear
3630                        x = bounds.left + (int) (bounds.width() * 0.5);
3631                        x = x - (int) (labelWidth * 0.5);
3632                        y = bounds.top - descent;
3633                        ti.setLocation(Math.round(x), Math.round(y));
3634                        arrMods.add(ti);
3635                    }
3636
3637                }
3638            }
3639            else if (ec == 270701)//static depiction
3640            {
3641                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3642                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3643                    if (strText != null) {
3644                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3645                        labelWidth = Math.round(ti.getTextBounds().width());
3646                        x = bounds.left + (int) (bounds.width() * 0.5);
3647                        x = x - (int) (labelWidth * 0.5);
3648                        y = bounds.top - descent;// + (bounds.height * 0.5);
3649                        //y = y + (labelHeight * 0.5);
3650
3651                        ti.setLocation(Math.round(x), Math.round(y));
3652                        arrMods.add(ti);
3653                    }
3654
3655                }
3656                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3657                    strText = modifiers.get(Modifiers.W_DTG_1);
3658                    if (strText != null) {
3659                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3660                        labelWidth = Math.round(ti.getTextBounds().width());
3661                        x = bounds.left + (int) (bounds.width() * 0.5);
3662                        x = x - (int) (labelWidth * 0.5);
3663                        y = bounds.top + (bounds.height());
3664                        y = y + (labelHeight);
3665
3666                        ti.setLocation(Math.round(x), Math.round(y));
3667                        arrMods.add(ti);
3668                    }
3669                }
3670                if (modifiers.containsKey(Modifiers.N_HOSTILE)) {
3671                    strText = modifiers.get(Modifiers.N_HOSTILE);
3672                    if (strText != null) {
3673                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3674                        TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3675                        labelWidth = Math.round(ti.getTextBounds().width());
3676                        x = bounds.left + (bounds.width()) + bufferXR;//right
3677                        //x = x + labelWidth;//- (labelBounds.width * 0.75);
3678
3679                        duplicate = true;
3680
3681                        x2 = bounds.left;//left
3682                        x2 = x2 - labelWidth - bufferXL;// - (labelBounds.width * 0.25);
3683
3684                        y = bounds.top + (int) (bounds.height() * 0.5);//center
3685                        y = y + (int) ((labelHeight - descent) * 0.5);
3686
3687                        y2 = y;
3688
3689                        ti.setLocation(Math.round(x), Math.round(y));
3690                        ti2.setLocation(Math.round(x2), Math.round(y2));
3691                        arrMods.add(ti);
3692                        arrMods.add(ti2);
3693                    }
3694                }
3695
3696            }
3697            else if(e == 21 && et == 35)//sonobuoys
3698            {
3699                //H sitting on center of circle to the right
3700                //T above H
3701                centerPoint = SymbolUtilities.getCMSymbolAnchorPoint(symbolID,RectUtilities.makeRectFFromRect(bounds));
3702                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3703                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3704                    if (strText != null) {
3705                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3706                        TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3707                        labelWidth = Math.round(ti.getTextBounds().width());
3708                        x = bounds.left + (bounds.width()) + bufferXR;//right
3709                        y = centerPoint.y;
3710
3711                        ti.setLocation(Math.round(x), Math.round(y));
3712                        arrMods.add(ti);
3713                    }
3714                }
3715                if (est == 0 || est == 1 || est == 4 || est == 7 || est == 8 || est == 15) {
3716                    if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3717                        strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3718                        if (strText != null) {
3719                            ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3720                            TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3721                            labelWidth = Math.round(ti.getTextBounds().width());
3722                            x = bounds.left + (bounds.width()) + bufferXR;//right
3723                            y = centerPoint.y - labelHeight;
3724
3725                            ti.setLocation(Math.round(x), Math.round(y));
3726                            arrMods.add(ti);
3727                        }
3728                    }
3729                }
3730            }
3731            else if(ec == 282001 || //tower, low
3732                    ec == 282002)   //tower, high
3733            {
3734                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) {
3735                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3736                    if (strText != null) {
3737                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3738                        labelWidth = Math.round(ti.getTextBounds().width());
3739                        x = bounds.left + (int) (bounds.width() * 0.7);
3740                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3741                        //y = y + (labelHeight * 0.5);
3742
3743                        ti.setLocation(Math.round(x), Math.round(y));
3744                        arrMods.add(ti);
3745                    }
3746
3747                }
3748            }
3749            else if(ec == 180600)//TACAN
3750            {
3751                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3752                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3753                    if (strText != null) {
3754                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3755                        labelWidth = Math.round(ti.getTextBounds().width());
3756                        x = bounds.left + bounds.width() + bufferXR;
3757                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3758                        //y = y + (labelHeight * 0.5);
3759
3760                        ti.setLocation(Math.round(x), Math.round(y));
3761                        arrMods.add(ti);
3762                    }
3763
3764                }
3765            }
3766            else if(ec == 210300)//Defended Asset
3767            {
3768                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3769                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3770                    if (strText != null) {
3771                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3772                        labelWidth = Math.round(ti.getTextBounds().width());
3773                        x = bounds.left - labelWidth - bufferXL;
3774                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3775                        //y = y + (labelHeight * 0.5);
3776
3777                        ti.setLocation(Math.round(x), Math.round(y));
3778                        arrMods.add(ti);
3779                    }
3780
3781                }
3782            }
3783            else if(ec == 210600)//Air Detonation
3784            {
3785                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) {
3786                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3787                    if (strText != null) {
3788                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3789                        labelWidth = Math.round(ti.getTextBounds().width());
3790                        x = bounds.left + (bounds.width() + bufferXR);
3791                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3792                        //y = y + (labelHeight * 0.5);
3793
3794                        ti.setLocation(Math.round(x), Math.round(y));
3795                        arrMods.add(ti);
3796                    }
3797
3798                }
3799            }
3800            else if(ec == 210800)//Impact Point
3801            {
3802                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3803                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3804                    if (strText != null) {
3805                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3806                        labelWidth = Math.round(ti.getTextBounds().width());
3807                        x = bounds.left + (int) (bounds.width() * 0.65f);
3808//                  x = x - (labelBounds.width * 0.5);
3809                        y = bounds.top + (int) (bounds.height() * 0.25f);
3810                        y = y + (int) (labelHeight * 0.5f);
3811                        //y = y + (labelHeight * 0.5);
3812
3813                        ti.setLocation(Math.round(x), Math.round(y));
3814                        arrMods.add(ti);
3815                    }
3816
3817                }
3818            }
3819            else if(ec == 211000)//Launched Torpedo
3820            {
3821                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3822                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3823                    if (strText != null) {
3824                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3825                        labelWidth = Math.round(ti.getTextBounds().width());
3826                        x = (int)(bounds.left + (bounds.width() * 0.5) - (labelWidth/2));
3827                        y = bounds.top - bufferY;
3828
3829                        ti.setLocation(Math.round(x), Math.round(y));
3830                        arrMods.add(ti);
3831                    }
3832
3833                }
3834            }
3835            else if(ec == 214900 || ec == 215600)//General Sea SubSurface Station & General Sea Surface Station
3836            {
3837                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3838                    strText = modifiers.get(Modifiers.W_DTG_1);
3839                    if (strText != null) {
3840                        ti = new TextInfo(strText + " - ", 0, 0, modifierFont, modifierFontName);
3841                        x = bounds.left + (bounds.width() + bufferXR);
3842                        y = bounds.top + labelHeight;
3843
3844                        ti.setLocation(Math.round(x), Math.round(y));
3845                        arrMods.add(ti);
3846                    }
3847
3848                }
3849                if (modifiers.containsKey(Modifiers.W1_DTG_2)) {
3850                    strText = modifiers.get(Modifiers.W1_DTG_2);
3851                    if (strText != null) {
3852                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3853                        x = bounds.left + (bounds.width() + bufferXR);
3854                        y = bounds.top + (labelHeight * 2);
3855
3856                        ti.setLocation(Math.round(x), Math.round(y));
3857                        arrMods.add(ti);
3858                    }
3859
3860                }
3861                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3862                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3863                    if (strText != null) {
3864                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3865                        x = bounds.left + (bounds.width() + bufferXR);
3866                        y = bounds.top + (labelHeight * 3);
3867
3868                        ti.setLocation(Math.round(x), Math.round(y));
3869                        arrMods.add(ti);
3870                    }
3871
3872                }
3873            }
3874            else if(ec == 217000)//Shore Control Station
3875            {
3876                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3877                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3878                    if (strText != null) {
3879                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3880                        labelWidth = Math.round(ti.getTextBounds().width());
3881                        x = (int)(bounds.left + (bounds.width() * 0.5) - (labelWidth/2));
3882                        y = bounds.top + bounds.height() + labelHeight + bufferY;
3883
3884                        ti.setLocation(Math.round(x), Math.round(y));
3885                        arrMods.add(ti);
3886                    }
3887
3888                }
3889            }
3890            else if(ec == 250600)//Known Point
3891            {
3892                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3893                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3894                    if (strText != null) {
3895                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3896                        labelWidth = Math.round(ti.getTextBounds().width());
3897                        x = bounds.left + (bounds.width() + bufferXR);
3898//                  x = x - (labelBounds.width * 0.5);
3899                        y = bounds.top + (int) (bounds.height() * 0.25f);
3900                        y = y + (int) (labelHeight * 0.5f);
3901                        //y = y + (labelHeight * 0.5);
3902
3903                        ti.setLocation(Math.round(x), Math.round(y));
3904                        arrMods.add(ti);
3905                    }
3906
3907                }
3908            }
3909        }
3910        else if(ss == SymbolID.SymbolSet_Atmospheric)
3911        {
3912            String modX = null;
3913            if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
3914                modX = (modifiers.get(Modifiers.X_ALTITUDE_DEPTH));
3915
3916            if(ec == 162300)//Freezing Level
3917            {
3918                strText = "0" + (char)(176) + ":";
3919                if(modX != null)
3920                    strText += modX;
3921                else
3922                    strText += "?";
3923
3924                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3925                labelWidth = Math.round(ti.getTextBounds().width());
3926                //One modifier symbols and modifier goes in center
3927                x = bounds.left + (int) (bounds.width() * 0.5f);
3928                x = x - (int) (labelWidth * 0.5f);
3929                y = bounds.top + (int) (bounds.height() * 0.5f);
3930                y = y + (int) ((labelHeight - modifierFontDescent) * 0.5f);
3931
3932                ti.setLocation(Math.round(x), Math.round(y));
3933                arrMods.add(ti);
3934            }
3935            else if(ec == 162200)//tropopause Level
3936            {
3937                strText = "X?";
3938                if(modX != null)
3939                    strText = modX;
3940
3941                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3942                labelWidth = Math.round(ti.getTextBounds().width());
3943                //One modifier symbols and modifier goes in center
3944                x = bounds.left + (int) (bounds.width() * 0.5f);
3945                x = x - (int) (labelWidth * 0.5f);
3946                y = bounds.top + (int) (bounds.height() * 0.5f);
3947                y = y + (int) ((labelHeight - modifierFontDescent) * 0.5f);
3948
3949                ti.setLocation(Math.round(x), Math.round(y));
3950                arrMods.add(ti);
3951            }
3952            else if(ec == 110102)//tropopause Low
3953            {
3954                strText = "X?";
3955                if(modX != null)
3956                    strText = modX;
3957
3958                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3959                labelWidth = Math.round(ti.getTextBounds().width());
3960                //One modifier symbols and modifier goes in center
3961                x = bounds.left + (int) (bounds.width() * 0.5f);
3962                x = x - (int) (labelWidth * 0.5f);
3963                y = bounds.top + (int) (bounds.height() * 0.5f);
3964                y = y - descent;
3965
3966                ti.setLocation(Math.round(x), Math.round(y));
3967                arrMods.add(ti);
3968            }
3969            else if(ec == 110202)//tropopause High
3970            {
3971                strText = "X?";
3972                if(modX != null)
3973                    strText = modX;
3974
3975                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3976                labelWidth = Math.round(ti.getTextBounds().width());
3977                //One modifier symbols and modifier goes in center
3978                x = bounds.left + (int) (bounds.width() * 0.5f);
3979                x = x - (int) (labelWidth * 0.5f);
3980                y = bounds.top + (int) (bounds.height() * 0.5f);
3981                //y = y + (int) ((labelHeight * 0.5f) + (labelHeight/2));
3982                y = y + (int) (((labelHeight * 0.5f) - (labelHeight/2)) + labelHeight - descent);
3983
3984                ti.setLocation(Math.round(x), Math.round(y));
3985                arrMods.add(ti);
3986            }
3987        }
3988        // </editor-fold>
3989
3990        // <editor-fold defaultstate="collapsed" desc="DOM Arrow">
3991        Point[] domPoints = null;
3992        Rect domBounds = null;
3993
3994        if (modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT) &&
3995                SymbolUtilities.isCBRNEvent(symbolID))//CBRN events
3996        {
3997            strText = modifiers.get(Modifiers.Q_DIRECTION_OF_MOVEMENT);
3998            if(strText != null && SymbolUtilities.isNumber(strText))
3999            {
4000                    float q = Float.parseFloat(strText);
4001                    Rect tempBounds = new Rect(bounds);
4002                    tempBounds.union(RectUtilities.getCenterX(bounds), yForY);
4003        
4004                    domPoints = createDOMArrowPoints(symbolID, tempBounds, sdi.getCenterPoint(), q, false, modifierFontHeight);
4005        
4006                    domBounds = RectUtilities.makeRect(domPoints[0].x, domPoints[0].y, 1, 1);
4007        
4008                    Point temp = null;
4009                    for (int i = 1; i < 6; i++)
4010                    {
4011                        temp = domPoints[i];
4012                        if (temp != null)
4013                        {
4014                            domBounds.union(temp.x, temp.y);
4015                        }
4016                    }
4017                    imageBounds.union(domBounds);
4018            }
4019        }
4020        // </editor-fold>
4021
4022        // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
4023        if (SymbolUtilities.hasFDI(symbolID))
4024        {
4025            //create feint indicator /\
4026            fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
4027            fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
4028            fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
4029
4030
4031            fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
4032            fdiBounds.union(fdiTop.x, fdiTop.y);
4033            fdiBounds.union(fdiRight.x, fdiRight.y);
4034
4035            float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4036            RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
4037
4038            ti = new TextInfo("TEST",0,0, modifierFont, modifierFontName);
4039            if (ti != null && SymbolUtilities.isCBRNEvent(symbolID))
4040            {
4041                int shiftY = Math.round(symbolBounds.top - ti.getTextBounds().height() - 2);
4042                fdiLeft.offset(0, shiftY);
4043                fdiTop.offset(0, shiftY);
4044                fdiRight.offset(0, shiftY);
4045                fdiBounds.offset(0, shiftY);
4046            }
4047
4048            imageBounds.union(fdiBounds);
4049
4050        }
4051        // </editor-fold>
4052
4053        // <editor-fold defaultstate="collapsed" desc="Shift Points and Draw">
4054        Rect modifierBounds = null;
4055        if (arrMods != null && arrMods.size() > 0)
4056        {
4057
4058            //build modifier bounds/////////////////////////////////////////
4059            modifierBounds = arrMods.get(0).getTextOutlineBounds();
4060            int size = arrMods.size();
4061            TextInfo tempShape = null;
4062            for (int i = 1; i < size; i++)
4063            {
4064                tempShape = arrMods.get(i);
4065                modifierBounds.union(tempShape.getTextOutlineBounds());
4066            }
4067
4068        }
4069
4070        if (modifierBounds != null || domBounds != null || fdiBounds != null)
4071        {
4072
4073            if (modifierBounds != null)
4074            {
4075                imageBounds.union(modifierBounds);
4076            }
4077            if (domBounds != null)
4078            {
4079                imageBounds.union(domBounds);
4080            }
4081            if (fdiBounds != null)
4082            {
4083                imageBounds.union(fdiBounds);
4084            }
4085
4086            //shift points if needed////////////////////////////////////////
4087            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4088            {
4089                int shiftX = Math.abs(imageBounds.left);
4090                int shiftY = Math.abs(imageBounds.top);
4091
4092                //shift mobility points
4093                int size = arrMods.size();
4094                TextInfo tempShape = null;
4095                for (int i = 0; i < size; i++)
4096                {
4097                    tempShape = arrMods.get(i);
4098                    tempShape.shift(shiftX, shiftY);
4099                }
4100                if(modifierBounds != null)
4101                    modifierBounds.offset(shiftX, shiftY);
4102
4103                if (domBounds != null)
4104                {
4105                    for (int i = 0; i < 6; i++)
4106                    {
4107                        Point temp = domPoints[i];
4108                        if (temp != null)
4109                        {
4110                            temp.offset(shiftX, shiftY);
4111                        }
4112                    }
4113                    domBounds.offset(shiftX, shiftY);
4114                }
4115
4116                //If there's an FDI
4117                if (fdiBounds != null)
4118                {
4119                    fdiBounds.offset(shiftX, shiftY);
4120                    fdiLeft.offset(shiftX, shiftY);
4121                    fdiTop.offset(shiftX, shiftY);
4122                    fdiRight.offset(shiftX, shiftY);
4123                }
4124
4125                //shift image points
4126                centerPoint.offset(shiftX, shiftY);
4127                symbolBounds.offset(shiftX, shiftY);
4128                imageBounds.offset(shiftX, shiftY);
4129            }
4130
4131
4132            if (attributes.containsKey(MilStdAttributes.TextColor))
4133            {
4134                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4135                if(alpha > -1)
4136                    textColor.setAlpha(alpha);
4137            }
4138            if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4139            {
4140                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4141                if(alpha > -1)
4142                    textBackgroundColor.setAlpha(alpha);
4143            }
4144
4145            if(sdi instanceof ImageInfo) {
4146                ii = (ImageInfo)sdi;
4147                //Render modifiers//////////////////////////////////////////////////
4148                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4149                Canvas ctx = new Canvas(bmp);
4150
4151                //render////////////////////////////////////////////////////////
4152                //draw original icon with potential modifiers.
4153                ctx.drawBitmap(ii.getImage(), symbolBounds.left, symbolBounds.top, null);
4154                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4155
4156
4157                renderText(ctx, arrMods, textColor, textBackgroundColor, modifierFont);
4158
4159                //draw DOM arrow
4160                if (domBounds != null)
4161                {
4162                    drawDOMArrow(ctx, domPoints, alpha, lineColor);
4163                }
4164
4165                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4166                if (fdiBounds != null) {
4167
4168                    Paint fdiPaint = new Paint();
4169                    fdiPaint.setAntiAlias(true);
4170                    fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
4171                    if (alpha > -1)
4172                        fdiPaint.setAlpha(alpha);
4173                    fdiPaint.setStyle(Style.STROKE);
4174
4175                    int dpi = RendererSettings.getInstance().getDeviceDPI();
4176                    int lineLength = dpi / 96 * 6;
4177                    int lineGap = dpi / 96 * 4;
4178
4179                    /// ///////////////////////////////////
4180                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4181                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4182                    //distance = distance / 14f;
4183                    lineGap = (int)((distance / 14f) * 2);
4184                    lineLength = (int)((distance / 14f) * 3);
4185                    /// //////////////////////////////////
4186
4187                    fdiPaint.setPathEffect(new DashPathEffect(new float[]
4188                            {
4189                                    lineLength, lineGap
4190                            }, 0));
4191
4192                    float fdiStrokeWidth = Math.round(dpi / 96f);
4193                    if (fdiStrokeWidth < 2)
4194                        fdiStrokeWidth = 2;
4195
4196                    fdiPaint.setStrokeCap(Cap.ROUND);
4197                    fdiPaint.setStrokeJoin(Join.MITER);
4198                    fdiPaint.setStrokeWidth(fdiStrokeWidth);
4199
4200                    Path fdiPath = new Path();
4201
4202                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4203                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4204                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4205                    fdiPath.lineTo(fdiRight.x, fdiRight.y);
4206                    ctx.drawPath(fdiPath, fdiPaint);
4207
4208                    fdiBounds = null;
4209
4210                }
4211                //</editor-fold>
4212
4213                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4214                ctx = null;
4215            }
4216            else if(sdi instanceof SVGSymbolInfo)
4217            {
4218                float strokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4219                if(strokeWidth < 1)
4220                    strokeWidth=1;
4221                String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
4222                String svgStrokeWidth = String.valueOf(strokeWidth);//"3";
4223
4224                ssi = (SVGSymbolInfo)sdi;
4225                StringBuilder sbSVG = new StringBuilder();
4226                sbSVG.append(ssi.getSVG());
4227                sbSVG.append(renderTextElements(arrMods,textColor,textBackgroundColor));
4228
4229                // <editor-fold defaultstate="collapsed" desc="DOM arrow">
4230                if (domBounds != null && domPoints.length == 6)
4231                {
4232                    SVGPath domPath = new SVGPath() ;
4233
4234                    domPath.moveTo(domPoints[0].x, domPoints[0].y);
4235                    if (domPoints[1] != null)
4236                    {
4237                        domPath.lineTo(domPoints[1].x, domPoints[1].y);
4238                    }
4239                    if (domPoints[2] != null)
4240                    {
4241                        domPath.lineTo(domPoints[2].x, domPoints[2].y);
4242                    }
4243                    sbSVG.append(domPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,null));
4244
4245                    domPath = new SVGPath();
4246
4247                    domPath.moveTo(domPoints[3].x, domPoints[3].y);
4248                    domPath.lineTo(domPoints[4].x, domPoints[4].y);
4249                    domPath.lineTo(domPoints[5].x, domPoints[5].y);
4250                    sbSVG.append(domPath.toSVGElement(null,0f,svgStroke,1f,1f,null));
4251
4252                    domBounds = null;
4253                    domPoints = null;
4254                }
4255                // </editor-fold>
4256
4257                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4258                if (fdiBounds != null)
4259                {
4260
4261                    /*int dpi = RendererSettings.getInstance().getDeviceDPI();
4262                    int lineLength = dpi / 96 * 6;
4263                    int lineGap = dpi / 96 * 4;
4264                    String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
4265
4266                    /// ///////////////////////////////////
4267                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4268                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4269                    //distance = distance / 14f;
4270                    int lineGap = (int)((distance / 14f) * 2);
4271                    int lineLength = (int)((distance / 14f) * 3);
4272                    String svgFDIDashArray = "" + lineLength + " " + lineGap;
4273                    /// //////////////////////////////////
4274
4275                    SVGPath fdiPath = new SVGPath();
4276                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4277                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4278                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4279                    fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
4280
4281                    fdiPath.setLineDash(svgFDIDashArray);
4282
4283                    sbSVG.append(fdiPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,"round"));
4284                    //sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray));
4285                }
4286                //</editor-fold>
4287
4288                newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
4289            }
4290
4291
4292
4293
4294            // <editor-fold defaultstate="collapsed" desc="Cleanup">
4295            //ctx = null;
4296            // </editor-fold>
4297
4298            return newsdi;
4299
4300        }
4301        else
4302        {
4303            return null;
4304        }
4305        // </editor-fold>
4306
4307    }
4308
4309    /**
4310     * Process modifiers for action points
4311     */
4312    public static SymbolDimensionInfo ProcessTGSPModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes, Color lineColor)
4313    {
4314
4315        Paint modifierFont = getFont(attributes);
4316        float[] hd = getFontHeightandDescent(modifierFont);
4317        float modifierFontHeight = hd[0];
4318        float modifierFontDescent = hd[1];
4319
4320        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
4321        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
4322        {
4323            String temp = attributes.get(MilStdAttributes.FontFamily);
4324            if(temp != null && !temp.isEmpty())
4325                modifierFontName = temp;
4326        }
4327
4328        // <editor-fold defaultstate="collapsed" desc="Variables">
4329        ImageInfo ii = null;
4330        SVGSymbolInfo ssi = null;
4331
4332        int bufferXL = 6;
4333        int bufferXR = 4;
4334        int bufferY = 2;
4335        int bufferText = 2;
4336        int centerOffset = 1; //getCenterX/Y function seems to go over by a pixel
4337        int x = 0;
4338        int y = 0;
4339        int x2 = 0;
4340        int y2 = 0;
4341
4342        //Feint Dummy Indicator variables
4343        Rect fdiBounds = null;
4344        Point fdiTop = null;
4345        Point fdiLeft = null;
4346        Point fdiRight = null;
4347
4348        int outlineOffset = RS.getTextOutlineWidth();
4349        int labelHeight = 0;
4350        int labelWidth = 0;
4351        int alpha = -1;
4352        SymbolDimensionInfo newsdi = null;
4353        
4354        Color textColor = lineColor;
4355        Color textBackgroundColor = null;
4356
4357        ArrayList<TextInfo> arrMods = new ArrayList<TextInfo>();
4358        boolean duplicate = false;
4359
4360        MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
4361
4362
4363        if (attributes.containsKey(MilStdAttributes.Alpha))
4364        {
4365            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
4366        }
4367
4368        Rect bounds = new Rect(sdi.getSymbolBounds());
4369        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
4370        Point centerPoint = new Point(sdi.getCenterPoint());
4371        Rect imageBounds = new Rect(sdi.getImageBounds());
4372
4373        centerPoint = new Point(Math.round(sdi.getCenterPoint().x), Math.round(sdi.getCenterPoint().y));
4374
4375        boolean byLabelHeight = false;
4376
4377        labelHeight = Math.round(modifierFontHeight + 0.5f);
4378        int maxHeight = (symbolBounds.height());
4379        if ((labelHeight * 3) > maxHeight)
4380        {
4381            byLabelHeight = true;
4382        }
4383
4384        int descent = (int) (modifierFontDescent + 0.5f);
4385        int yForY = -1;
4386
4387        Rect labelBounds1 = null;//text.getPixelBounds(null, 0, 0);
4388        Rect labelBounds2 = null;
4389        String strText = "";
4390        String strText1 = "";
4391        String strText2 = "";
4392        TextInfo text1 = null;
4393        TextInfo text2 = null;
4394
4395        String basicID = SymbolUtilities.getBasicSymbolID(symbolID);
4396
4397        if (outlineOffset > 2)
4398        {
4399            outlineOffset = ((outlineOffset - 1) / 2);
4400        }
4401        else
4402        {
4403            outlineOffset = 0;
4404        }
4405
4406        /*bufferXL += outlineOffset;
4407         bufferXR += outlineOffset;
4408         bufferY += outlineOffset;
4409         bufferText += outlineOffset;*/
4410        // </editor-fold>
4411        // <editor-fold defaultstate="collapsed" desc="Process Modifiers">
4412        TextInfo ti = null;
4413
4414        {
4415            if (msi.getModifiers().contains(Modifiers.N_HOSTILE) && modifiers.containsKey(Modifiers.N_HOSTILE))
4416            {
4417                strText = modifiers.get(Modifiers.N_HOSTILE);
4418                if(strText != null)
4419                {
4420                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4421        
4422                        x = bounds.left + bounds.width() + bufferXR;
4423        
4424                        if (!byLabelHeight)
4425                        {
4426                            y = ((bounds.height() / 3) * 2);//checkpoint, get box above the point
4427                            y = bounds.top + y;
4428                        }
4429                        else
4430                        {
4431                            //y = ((labelHeight + bufferText) * 3);
4432                            //y = bounds.y + y - descent;
4433                            y = bounds.top + bounds.height();
4434                        }
4435        
4436                        ti.setLocation(x, y);
4437                        arrMods.add(ti);
4438                }
4439
4440            }
4441            if (msi.getModifiers().contains(Modifiers.H_ADDITIONAL_INFO_1) && modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
4442            {
4443                strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
4444                if(strText != null)
4445                {
4446                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4447                        labelWidth = Math.round(ti.getTextBounds().width());
4448        
4449                        x = bounds.left + (int) (bounds.width() * 0.5f);
4450                        x = x - (int) (labelWidth * 0.5f);
4451                        y = bounds.top - descent;
4452        
4453                        ti.setLocation(x, y);
4454                        arrMods.add(ti);
4455                }
4456            }
4457            if (msi.getModifiers().contains(Modifiers.H1_ADDITIONAL_INFO_2) && modifiers.containsKey(Modifiers.H1_ADDITIONAL_INFO_2))
4458            {
4459                strText = modifiers.get(Modifiers.H1_ADDITIONAL_INFO_2);
4460                if(strText != null)
4461                {
4462                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4463                        labelWidth = Math.round(ti.getTextBounds().width());
4464        
4465                        x = bounds.left + (int) (bounds.width() * 0.5);
4466                        x = x - (int) (labelWidth * 0.5);
4467                    y = bounds.top + labelHeight - descent + (int) (bounds.height() * 0.07);
4468        
4469                        ti.setLocation(x, y);
4470                        arrMods.add(ti);
4471                }
4472            }
4473            if (msi.getModifiers().contains(Modifiers.A_SYMBOL_ICON))
4474            {
4475                if(modifiers.containsKey(Modifiers.A_SYMBOL_ICON))
4476                    strText = modifiers.get(Modifiers.A_SYMBOL_ICON);
4477                else if(SymbolID.getEntityCode(symbolID)==321706)//NATO Multiple Supply Class Point
4478                    strText = "ALL?";//make it clear the required 'A' value wasn't set for this symbol.
4479
4480                if(strText != null)
4481                {
4482                    ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4483                    labelWidth = Math.round(ti.getTextBounds().width());
4484
4485                    x = bounds.left + (int) (bounds.width() * 0.5);
4486                    x = x - (int) (labelWidth * 0.5);
4487                    y = bounds.top + labelHeight - descent + (int) (bounds.height() * 0.07);
4488
4489                    ti.setLocation(x, y);
4490                    arrMods.add(ti);
4491                }
4492            }
4493            if (msi.getModifiers().contains(Modifiers.W_DTG_1) && modifiers.containsKey(Modifiers.W_DTG_1))
4494            {
4495                strText = modifiers.get(Modifiers.W_DTG_1);
4496                if(strText != null)
4497                {
4498                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4499                        labelWidth = Math.round(ti.getTextBounds().width());
4500        
4501                        x = bounds.left - labelWidth - bufferXL;
4502                        y = bounds.top + labelHeight - descent;
4503        
4504                        ti.setLocation(x, y);
4505                        arrMods.add(ti);
4506                }
4507            }
4508            if (msi.getModifiers().contains(Modifiers.W1_DTG_2) && modifiers.containsKey(Modifiers.W1_DTG_2))
4509            {
4510                strText = modifiers.get(Modifiers.W1_DTG_2);
4511                if(strText != null)
4512                {
4513                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4514                        labelWidth = Math.round(ti.getTextBounds().width());
4515        
4516                        x = bounds.left - labelWidth - bufferXL;
4517        
4518                        y = ((labelHeight - descent + bufferText) * 2);
4519                        y = bounds.top + y;
4520        
4521                        ti.setLocation(x, y);
4522                        arrMods.add(ti);
4523                }
4524            }
4525            if (msi.getModifiers().contains(Modifiers.T_UNIQUE_DESIGNATION_1) && modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
4526            {
4527                strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
4528                if(strText != null)
4529                {
4530                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4531        
4532                        x = bounds.left + bounds.width() + bufferXR;
4533                        y = bounds.top + labelHeight - descent;
4534        
4535                        ti.setLocation(x, y);
4536                        arrMods.add(ti);
4537                }
4538            }
4539            if (msi.getModifiers().contains(Modifiers.T1_UNIQUE_DESIGNATION_2) && modifiers.containsKey(Modifiers.T1_UNIQUE_DESIGNATION_2))
4540            {
4541                strText = modifiers.get(Modifiers.T1_UNIQUE_DESIGNATION_2);
4542                if(strText != null)
4543                {
4544                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4545                        labelWidth = Math.round(ti.getTextBounds().width());
4546        
4547                        //points
4548                        x = bounds.left + (int) (bounds.width() * 0.5);
4549                        x = x - (int) (labelWidth * 0.5);
4550                        //y = bounds.y + (bounds.height * 0.5);
4551        
4552                        y = (int) ((bounds.height() * 0.55));//633333333
4553                        y = bounds.top + y;
4554        
4555                        ti.setLocation(x, y);
4556                        arrMods.add(ti);
4557                }
4558            }
4559            // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
4560            if (SymbolUtilities.hasFDI(symbolID))
4561            {
4562                //create feint indicator /\
4563                fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
4564                fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
4565                fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
4566
4567
4568                fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
4569                fdiBounds.union(fdiTop.x, fdiTop.y);
4570                fdiBounds.union(fdiRight.x, fdiRight.y);
4571
4572                float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4573                RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
4574
4575                ti = new TextInfo("TEST",0,0, modifierFont, modifierFontName);
4576                if (ti != null)
4577                {
4578                    int shiftY = Math.round(symbolBounds.top - ti.getTextBounds().height() - 2);
4579                    fdiLeft.offset(0, shiftY);
4580                    fdiTop.offset(0, shiftY);
4581                    fdiRight.offset(0, shiftY);
4582                    fdiBounds.offset(0, shiftY);
4583                }
4584
4585                imageBounds.union(fdiBounds);
4586
4587            }
4588            // </editor-fold>
4589        }
4590
4591        // </editor-fold>
4592        // <editor-fold defaultstate="collapsed" desc="Shift Points and Draw">
4593        Rect modifierBounds = null;
4594        if (arrMods != null && arrMods.size() > 0)
4595        {
4596
4597            //build modifier bounds/////////////////////////////////////////
4598            modifierBounds = arrMods.get(0).getTextOutlineBounds();
4599            int size = arrMods.size();
4600            TextInfo tempShape = null;
4601            for (int i = 1; i < size; i++)
4602            {
4603                tempShape = arrMods.get(i);
4604                modifierBounds.union(tempShape.getTextOutlineBounds());
4605            }
4606
4607        }
4608
4609        if(fdiBounds != null)
4610        {
4611            if(modifierBounds != null)
4612                modifierBounds.union(fdiBounds);
4613            else
4614                modifierBounds = fdiBounds;
4615        }
4616
4617        if (modifierBounds != null)
4618        {
4619
4620            imageBounds.union(modifierBounds);
4621
4622            //shift points if needed////////////////////////////////////////
4623            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4624            {
4625                int shiftX = Math.abs(imageBounds.left);
4626                int shiftY = Math.abs(imageBounds.top);
4627
4628                //shift mobility points
4629                int size = arrMods.size();
4630                TextInfo tempShape = null;
4631                for (int i = 0; i < size; i++)
4632                {
4633                    tempShape = arrMods.get(i);
4634                    tempShape.shift(shiftX, shiftY);
4635                }
4636                modifierBounds.offset(shiftX, shiftY);
4637
4638                //shift image points
4639                centerPoint.offset(shiftX, shiftY);
4640                symbolBounds.offset(shiftX, shiftY);
4641                imageBounds.offset(shiftX, shiftY);
4642
4643                //If there's an FDI
4644                if (fdiBounds != null)
4645                {
4646                    fdiBounds.offset(shiftX, shiftY);
4647                    fdiLeft.offset(shiftX, shiftY);
4648                    fdiTop.offset(shiftX, shiftY);
4649                    fdiRight.offset(shiftX, shiftY);
4650                }
4651            }
4652
4653            if (attributes.containsKey(MilStdAttributes.TextColor))
4654            {
4655                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4656                if(alpha > -1)
4657                    textColor.setAlpha(alpha);
4658            }
4659            if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4660            {
4661                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4662                if(alpha > -1)
4663                    textBackgroundColor.setAlpha(alpha);
4664            }
4665
4666            if(sdi instanceof ImageInfo)
4667            {
4668                ii = (ImageInfo) sdi;
4669                //Render modifiers//////////////////////////////////////////////////
4670                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4671                Canvas ctx = new Canvas(bmp);
4672
4673                //draw original icon with potential modifiers.
4674                ctx.drawBitmap(ii.getImage(), symbolBounds.left, symbolBounds.top, null);
4675                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4676
4677
4678                renderText(ctx, arrMods, textColor, textBackgroundColor, modifierFont);
4679
4680                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4681                if (fdiBounds != null) {
4682
4683                    Paint fdiPaint = new Paint();
4684                    fdiPaint.setAntiAlias(true);
4685                    fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
4686                    if (alpha > -1)
4687                        fdiPaint.setAlpha(alpha);
4688                    fdiPaint.setStyle(Style.STROKE);
4689
4690                    int dpi = RendererSettings.getInstance().getDeviceDPI();
4691                    int lineLength = dpi / 96 * 6;
4692                    int lineGap = dpi / 96 * 4;
4693
4694                    /// ///////////////////////////////////
4695                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4696                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4697                    //distance = distance / 14f;
4698                    lineGap = (int)((distance / 14f) * 2);
4699                    lineLength = (int)((distance / 14f) * 3);
4700                    /// //////////////////////////////////
4701
4702                    fdiPaint.setPathEffect(new DashPathEffect(new float[]
4703                            {
4704                                    lineLength, lineGap
4705                            }, 0));
4706
4707                    float fdiStrokeWidth = Math.round(dpi / 96f);
4708                    if (fdiStrokeWidth < 2)
4709                        fdiStrokeWidth = 2;
4710
4711                    fdiPaint.setStrokeCap(Cap.ROUND);
4712                    fdiPaint.setStrokeJoin(Join.MITER);
4713                    fdiPaint.setStrokeWidth(fdiStrokeWidth);
4714
4715                    Path fdiPath = new Path();
4716
4717                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4718                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4719                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4720                    fdiPath.lineTo(fdiRight.x, fdiRight.y);
4721                    ctx.drawPath(fdiPath, fdiPaint);
4722
4723                    fdiBounds = null;
4724
4725                }
4726                //</editor-fold>
4727
4728                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4729            }
4730            else if(sdi instanceof SVGSymbolInfo)
4731            {
4732                String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
4733                String svgStrokeWidth = "3";
4734                String svgAlpha = null;
4735                if(alpha > -1)
4736                    svgAlpha = String.valueOf(alpha);
4737                ssi = (SVGSymbolInfo)sdi;
4738                StringBuilder sbSVG = new StringBuilder();
4739                sbSVG.append(ssi.getSVG());
4740                sbSVG.append(renderTextElements(arrMods,textColor,textBackgroundColor));
4741
4742                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4743                if (fdiBounds != null)
4744                {
4745                    /*int dpi = RendererSettings.getInstance().getDeviceDPI();
4746                    int lineLength = dpi / 96 * 6;
4747                    int lineGap = dpi / 96 * 4;
4748                    String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
4749
4750                    /// ///////////////////////////////////
4751                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4752                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4753                    //distance = distance / 14f;
4754                    int lineGap = (int)((distance / 14f) * 2);
4755                    int lineLength = (int)((distance / 14f) * 3);
4756                    String svgFDIDashArray = "" + lineLength + " " + lineGap;
4757                    /// //////////////////////////////////
4758
4759                    SVGPath fdiPath = new SVGPath();
4760                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4761                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4762                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4763                    fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
4764
4765                    fdiPath.setLineDash(svgFDIDashArray);
4766                    sbSVG.append(fdiPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,"round"));
4767                    //sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray));
4768                }
4769                //</editor-fold>
4770
4771                newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
4772            }
4773
4774            // <editor-fold defaultstate="collapsed" desc="Cleanup">
4775            //ctx = null;
4776
4777            // </editor-fold>
4778        }
4779        // </editor-fold>
4780        return newsdi;
4781
4782    }
4783
4784    private static SymbolDimensionInfo shiftUnitPointsAndDraw(ArrayList<TextInfo> tiArray, SymbolDimensionInfo sdi, Map<String,String> attributes, Paint modifierFont)
4785    {
4786
4787        ImageInfo ii = null;
4788        SVGSymbolInfo ssi = null;
4789        SymbolDimensionInfo newsdi = null;
4790
4791        int alpha = -1;
4792
4793
4794        if (attributes != null && attributes.containsKey(MilStdAttributes.Alpha))
4795        {
4796            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
4797        }
4798
4799        Color textColor = Color.BLACK;
4800        Color textBackgroundColor = null;
4801
4802        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
4803        Point centerPoint = new Point(sdi.getCenterPoint());
4804        Rect imageBounds = new Rect(sdi.getImageBounds());
4805        Rect imageBoundsOld = new Rect(sdi.getImageBounds());
4806
4807        Rect modifierBounds = null;
4808        if (tiArray != null && tiArray.size() > 0)
4809        {
4810
4811            //build modifier bounds/////////////////////////////////////////
4812            modifierBounds = tiArray.get(0).getTextOutlineBounds();
4813            int size = tiArray.size();
4814            TextInfo tempShape = null;
4815            for (int i = 1; i < size; i++)
4816            {
4817                tempShape = tiArray.get(i);
4818                modifierBounds.union(tempShape.getTextOutlineBounds());
4819            }
4820
4821        }
4822
4823        if (modifierBounds != null)
4824        {
4825
4826            imageBounds.union(modifierBounds);
4827
4828            //shift points if needed////////////////////////////////////////
4829            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4830            {
4831                int shiftX = Math.round(Math.abs(imageBounds.left)),
4832                        shiftY = Math.round(Math.abs(imageBounds.top));
4833
4834                //shift mobility points
4835                int size = tiArray.size();
4836                TextInfo tempShape = null;
4837                for (int i = 0; i < size; i++)
4838                {
4839                    tempShape = tiArray.get(i);
4840                    tempShape.shift(shiftX, shiftY);
4841                }
4842                RectUtilities.shift(modifierBounds, shiftX, shiftY);
4843                //modifierBounds.shift(shiftX,shiftY);
4844
4845                //shift image points
4846                centerPoint.offset(shiftX, shiftY);
4847                RectUtilities.shift(symbolBounds, shiftX, shiftY);
4848                RectUtilities.shift(imageBounds, shiftX, shiftY);
4849                RectUtilities.shift(imageBoundsOld, shiftX, shiftY);
4850                /*centerPoint.shift(shiftX, shiftY);
4851                 symbolBounds.shift(shiftX, shiftY);
4852                 imageBounds.shift(shiftX, shiftY);
4853                 imageBoundsOld.shift(shiftX, shiftY);//*/
4854            }
4855
4856            if (attributes != null && attributes.containsKey(MilStdAttributes.TextColor))
4857            {
4858                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4859                if(alpha > -1)
4860                    textColor.setAlpha(alpha);
4861            }
4862            if (attributes != null && attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4863            {
4864                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4865                if(alpha > -1)
4866                    textBackgroundColor.setAlpha(alpha);
4867            }
4868
4869            if(sdi instanceof ImageInfo)
4870            {
4871                ii = (ImageInfo) sdi;
4872
4873                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4874                Canvas ctx = new Canvas(bmp);
4875
4876                //render////////////////////////////////////////////////////////
4877                //draw original icon with potential modifiers.
4878                ctx.drawBitmap(ii.getImage(), imageBoundsOld.left, imageBoundsOld.top, null);
4879                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4880
4881                renderText(ctx, tiArray, textColor, textBackgroundColor, modifierFont);
4882
4883                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4884            }
4885            else if(sdi instanceof SVGSymbolInfo)
4886            {
4887                ssi = (SVGSymbolInfo)sdi;
4888                StringBuilder sb = new StringBuilder();
4889                sb.append(ssi.getSVG());
4890                sb.append(renderTextElements(tiArray,textColor,textBackgroundColor));
4891                newsdi = new SVGSymbolInfo(sb.toString(),centerPoint,symbolBounds,imageBounds);
4892            }
4893        }
4894
4895        if(newsdi == null)
4896            newsdi = sdi;
4897
4898        return newsdi;
4899    }
4900    private static String renderTextElement(ArrayList<TextInfo> tiArray, Color color, Color backgroundColor)
4901    {
4902        StringBuilder sbSVG = new StringBuilder();
4903
4904        String svgStroke = RendererUtilities.colorToHexString(RendererUtilities.getIdealOutlineColor(color),false);
4905        if(backgroundColor != null)
4906            svgStroke = RendererUtilities.colorToHexString(backgroundColor,false);
4907
4908        String svgFill = RendererUtilities.colorToHexString(color,false);
4909        String svgStrokeWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
4910        for (TextInfo ti : tiArray) {
4911            sbSVG.append(Shape2SVG.Convert(ti, svgStroke,svgFill,svgStrokeWidth,null,null,null));
4912            sbSVG.append("\n");
4913        }
4914
4915        return sbSVG.toString();
4916    }
4917
4918    private static String renderTextElements(ArrayList<TextInfo> tiArray, Color color, Color backgroundColor)
4919    {
4920        String style = null;
4921        String name = tiArray.get(0).getFontName();//"SansSerif";
4922        if(!name.endsWith("serif"))
4923            name += ", sans-serif";
4924        String size = String.valueOf(tiArray.get(0).getFontSize());
4925        String weight = null;
4926        String anchor = null;//"start";
4927        if(tiArray.get(0).getFontStyle() == Typeface.BOLD)
4928            weight = "bold";
4929        StringBuilder sbSVG = new StringBuilder();
4930
4931        String svgStroke = RendererUtilities.colorToHexString(RendererUtilities.getIdealOutlineColor(color),false);
4932        if(backgroundColor != null)
4933            svgStroke = RendererUtilities.colorToHexString(backgroundColor,false);
4934
4935        String svgFill = RendererUtilities.colorToHexString(color,false);
4936        String svgStrokeWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
4937        sbSVG.append("\n<g");
4938        sbSVG.append(" font-family=\"").append(name).append('"');
4939        sbSVG.append(" font-size=\"").append(size).append("px\"");
4940        if(weight != null)
4941            sbSVG.append(" font-weight=\"").append(weight).append("\"");
4942        sbSVG.append(" alignment-baseline=\"alphabetic\"");//
4943        sbSVG.append(">");
4944
4945        for (TextInfo ti : tiArray) {
4946            sbSVG.append(Shape2SVG.ConvertForGroup(ti, svgStroke,svgFill,svgStrokeWidth,null,null,null));
4947            sbSVG.append("\n");
4948        }
4949        sbSVG.append("</g>\n");
4950
4951        return sbSVG.toString();
4952    }
4953    private static void renderText(Canvas ctx, ArrayList<TextInfo> tiArray, Color color, Color backgroundColor, Paint font)
4954    {
4955        ModifierRenderer.renderText(ctx, (TextInfo[]) tiArray.toArray(new TextInfo[0]), color, backgroundColor, font);
4956    }
4957
4958    /**
4959     * 
4960     * @param ctx
4961     * @param tiArray
4962     * @param color
4963     * @param backgroundColor 
4964     */
4965    public static void renderText(Canvas ctx, TextInfo[] tiArray, Color color, Color backgroundColor, Paint modifierFont)
4966    {
4967        /*for (TextInfo textInfo : tiArray) 
4968         {
4969         ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);    
4970         }*/
4971
4972        int size = tiArray.length;
4973
4974        int tbm = RS.getTextBackgroundMethod();
4975        int outlineWidth = RS.getTextOutlineWidth();
4976
4977        if (color == null)
4978        {
4979            color = Color.BLACK;
4980        }
4981
4982        Color outlineColor = null;
4983        
4984        if(backgroundColor != null)
4985            outlineColor = backgroundColor;
4986        else
4987            outlineColor = RendererUtilities.getIdealOutlineColor(color);
4988
4989        if (tbm == RendererSettings.TextBackgroundMethod_OUTLINE_QUICK)
4990        {
4991            synchronized (modifierFontMutex) {
4992                //draw text outline
4993                modifierFont.setStyle(Style.FILL);
4994                modifierFont.setStrokeWidth(RS.getTextOutlineWidth());
4995                modifierFont.setColor(outlineColor.toInt());
4996
4997                if (outlineWidth > 2)
4998                    outlineWidth = 2;
4999
5000                if (outlineWidth > 0) {
5001                    for (int i = 0; i < size; i++) {
5002                        TextInfo textInfo = tiArray[i];
5003                        if (outlineWidth > 0) {
5004                            for (int j = 1; j <= outlineWidth; j++) {
5005                                if (j == 1) {
5006                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y - j, modifierFont);
5007                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y - j, modifierFont);
5008                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y + j, modifierFont);
5009                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y + j, modifierFont);
5010
5011                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y, modifierFont);
5012                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y, modifierFont);
5013
5014                                } else {
5015                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y - j, modifierFont);
5016                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y - j, modifierFont);
5017                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y + j, modifierFont);
5018                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y + j, modifierFont);
5019
5020                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y, modifierFont);
5021                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y, modifierFont);
5022
5023                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y + j, modifierFont);
5024                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y - j, modifierFont);
5025                                }
5026
5027                            }
5028
5029                        }
5030
5031                    }
5032                }
5033                //draw text
5034                modifierFont.setColor(color.toInt());
5035
5036                for (int j = 0; j < size; j++) {
5037                    TextInfo textInfo = tiArray[j];
5038                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5039                /*Paint outline = new Paint();
5040                 outline.setStyle(Style.STROKE);
5041                 outline.setColor(Color.red.toInt());
5042                 outline.setAlpha(155);
5043                 outline.setStrokeWidth(1f);
5044                 ctx.drawRect(textInfo.getTextBounds(), outline);
5045                 outline.setColor(Color.blue.toInt());
5046                 ctx.drawRect(textInfo.getTextOutlineBounds(), outline);//*/
5047                }
5048            }
5049        }
5050        else if (tbm == RendererSettings.TextBackgroundMethod_OUTLINE)
5051        {
5052            synchronized (modifierFontMutex) {
5053                //draw text outline
5054                //draw text outline
5055                modifierFont.setStyle(Style.STROKE);
5056                modifierFont.setStrokeWidth(RS.getTextOutlineWidth());
5057                modifierFont.setColor(outlineColor.toInt());
5058                if (outlineWidth > 0) {
5059                    for (int i = 0; i < size; i++) {
5060                        TextInfo textInfo = tiArray[i];
5061                        ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5062                    }
5063                }
5064                //draw text
5065                modifierFont.setColor(color.toInt());
5066                modifierFont.setStyle(Style.FILL);
5067                for (int j = 0; j < size; j++) {
5068                    TextInfo textInfo = tiArray[j];
5069                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5070                }
5071            }
5072        }
5073        else if (tbm == RendererSettings.TextBackgroundMethod_COLORFILL)
5074        {
5075            synchronized (modifierFontMutex) {
5076                Paint rectFill = new Paint();
5077                rectFill.setStyle(Paint.Style.FILL);
5078                rectFill.setColor(outlineColor.toARGB());
5079
5080
5081                //draw rectangle
5082                for (int k = 0; k < size; k++) {
5083                    TextInfo textInfo = tiArray[k];
5084                    ctx.drawRect(textInfo.getTextOutlineBounds(), rectFill);
5085                }
5086                //draw text
5087                modifierFont.setColor(color.toInt());
5088                modifierFont.setStyle(Style.FILL);
5089                for (int j = 0; j < size; j++) {
5090                    TextInfo textInfo = tiArray[j];
5091                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5092                }
5093            }
5094        }
5095        else if (tbm == RendererSettings.TextBackgroundMethod_NONE)
5096        {
5097            synchronized (modifierFontMutex) {
5098                modifierFont.setColor(color.toInt());
5099                modifierFont.setStyle(Style.FILL);
5100                for (int j = 0; j < size; j++) {
5101                    TextInfo textInfo = tiArray[j];
5102                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5103                }
5104            }
5105        }
5106    }
5107
5108    /**
5109     *
5110     * @param symbolID
5111     * @param modifiers
5112     * @return int[] where {xposition (-1 left, 0 centered, 1 right), yposition (0 centered, 1+ goes up, 1- goes down),
5113     * centered (0-no, 1-yes)} -999 means passed modifier is not supported by this symbol
5114     */
5115    private static List<Modifier> getLabelPositionIndexes(String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
5116    {
5117        List<Modifier> mods = null;
5118        if(modifiers != null && !modifiers.isEmpty())
5119            mods = new ArrayList<>();
5120        else
5121            return null;
5122
5123        int ver = SymbolID.getVersion(symbolID);
5124        int ss = SymbolID.getSymbolSet(symbolID);
5125        int x = 0;
5126        int y = 0;
5127        boolean centered = true;
5128        int p = RendererSettings.getInstance().getSPModifierPlacement();
5129        boolean strict = (RendererSettings.getInstance().getSPModifierPlacement() == RendererSettings.ModifierPlacement_STRICT);
5130        if(attributes != null && attributes.containsKey(MilStdAttributes.ModifierPlacement))
5131        {
5132            String mp = attributes.get(MilStdAttributes.ModifierPlacement);
5133            if(mp.equals("0") || mp.equals("1") || mp.equals("2"))
5134            {
5135                p = Integer.parseInt(mp);
5136                if(p == 0)
5137                    strict = true;
5138                else
5139                    strict = false;
5140            }
5141        }
5142        String temp = null;
5143        String sep = " ";
5144        if(ss == SymbolID.SymbolSet_DismountedIndividuals) {
5145            ver = SymbolID.Version_2525E;
5146        }
5147
5148        if(ver < SymbolID.Version_2525E)
5149        {
5150            if(ss == SymbolID.SymbolSet_LandUnit ||
5151                    ss == SymbolID.SymbolSet_LandCivilianUnit_Organization)
5152            {
5153                //Do top center label
5154                x = 0;//centered
5155                y = 9;//on top of symbol
5156                if(modifiers.containsKey(Modifiers.B_ECHELON))
5157                {
5158                    temp = modifiers.get(Modifiers.B_ECHELON);
5159                    if(temp != null && !temp.isEmpty())
5160                        mods.add(new Modifier("B", temp, x, y, centered));
5161                }
5162
5163                //Do right side labels
5164                x = 1;//on right
5165                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5166                {
5167                    y = 0;//center
5168                    centered = true;//vertically centered, only matters for labels on left and right side
5169                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5170                    if(temp != null && !temp.isEmpty())
5171                        mods.add(new Modifier("H", temp, x, y, centered));
5172                }
5173                else if(!strict)
5174                {
5175                    //if no "H', bring G and M closer to the center
5176                    centered = false;
5177                }
5178
5179                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5180                {
5181                    y = 1;//above center
5182                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5183                    if(temp != null && !temp.isEmpty())
5184                        mods.add(new Modifier("G", temp, x, y, centered));
5185                }
5186
5187                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
5188                {
5189                    y = 2;
5190                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5191                        y--;
5192                    temp = "";
5193                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
5194                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
5195                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5196                        temp += modifiers.get(Modifiers.AS_COUNTRY);
5197                    temp = temp.trim();
5198                    if(temp != null && !temp.isEmpty())
5199                        mods.add(new Modifier("F AS", temp, x, y, centered));
5200                }
5201
5202                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
5203                {
5204                    y = -1;//below center
5205                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
5206                    if(temp != null && !temp.isEmpty())
5207                        mods.add(new Modifier("M", temp, x, y, centered));
5208                }
5209
5210                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5211                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
5212                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5213                {
5214                    y = -2;
5215                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
5216                        y++;
5217                    temp = "";
5218                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5219                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5220                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
5221                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
5222                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5223                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5224                    temp = temp.trim();
5225                    if(temp != null && !temp.isEmpty())
5226                        mods.add(new Modifier("J K P", temp, x, y, centered));
5227                }
5228
5229                //Do left side labels
5230                x = -1;//on left
5231                centered = false;
5232
5233                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5234                {
5235                    y = 1;
5236                    temp = "";
5237                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5238                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5239                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5240                        temp += modifiers.get(Modifiers.Y_LOCATION);
5241
5242                    temp = temp.trim();
5243                    if(temp != null && !temp.isEmpty())
5244                        mods.add(new Modifier("X Y", temp, x, y, centered));
5245                }
5246
5247                if(modifiers.containsKey(Modifiers.W_DTG_1))
5248                {
5249                    y = 2;//above center
5250                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
5251                        y--;
5252                    temp = modifiers.get(Modifiers.W_DTG_1);
5253                    if(temp != null && !temp.isEmpty())
5254                        mods.add(new Modifier("W", temp, x, y, centered));
5255                }
5256
5257                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5258                {
5259                    y = -1;//below center
5260                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5261                    if(temp != null && !temp.isEmpty())
5262                        mods.add(new Modifier("T", temp, x, y, centered));
5263                }
5264
5265                if(modifiers.containsKey(Modifiers.Z_SPEED))
5266                {
5267                    y = -2;
5268                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5269                        y++;
5270                    temp = modifiers.get(Modifiers.Z_SPEED);
5271                    if(temp != null && !temp.isEmpty())
5272                        mods.add(new Modifier(Modifiers.J_EVALUATION_RATING, temp, x, y, centered));
5273                }
5274            }
5275            else if(ss == SymbolID.SymbolSet_LandEquipment ||
5276                    ss == SymbolID.SymbolSet_SignalsIntelligence_Land)
5277            {
5278                //Do top center label
5279                x = 0;//centered
5280                y = 9;//on top of symbol
5281                if(modifiers.containsKey(Modifiers.C_QUANTITY))
5282                {
5283                    temp = modifiers.get(Modifiers.C_QUANTITY);
5284                    if(temp != null && !temp.isEmpty())
5285                        mods.add(new Modifier("C", temp, x, y, centered));
5286                }
5287
5288                //Do right side labels
5289                x = 1;//on right
5290                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
5291                {
5292                    y = 0;//center
5293                    centered = true;//vertically centered, only matters for labels on left and right side
5294                    temp = "";
5295                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5296                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
5297                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
5298                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
5299                    temp = temp.trim();
5300                    if(temp != null && !temp.isEmpty())
5301                        mods.add(new Modifier("H AF", temp, x, y, centered));
5302                }
5303                else if(!strict)
5304                {
5305                    //if no "H', bring G and M closer to the center
5306                    centered = false;
5307                }
5308
5309                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5310                {
5311                    y = 1;//above center
5312                    temp = "";
5313                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5314                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5315                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5316                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
5317                    temp = temp.trim();
5318                    if(temp != null && !temp.isEmpty())
5319                        mods.add(new Modifier("G AQ", temp, x, y, centered));
5320                }
5321
5322                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5323                {
5324                    y = 2;
5325                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
5326                        y--;
5327
5328                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5329                    if(temp != null && !temp.isEmpty())
5330                        mods.add(new Modifier("AS", temp, x, y, centered));
5331                }
5332
5333                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5334                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
5335                        modifiers.containsKey(Modifiers.N_HOSTILE) ||
5336                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5337                {
5338                    y = -1;
5339
5340                    temp = "";
5341                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5342                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5343                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
5344                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
5345                    if(modifiers.containsKey(Modifiers.N_HOSTILE))
5346                        temp += modifiers.get(Modifiers.N_HOSTILE) + sep;
5347                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5348                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5349                    temp = temp.trim();
5350                    if(temp != null && !temp.isEmpty())
5351                        mods.add(new Modifier("J L N P", temp, x, y, centered));
5352                }
5353
5354                //Do left side labels
5355                x = -1;//on left
5356
5357                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
5358                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
5359                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
5360                {
5361                    y = 0;//center
5362                    centered = true;//vertically centered, only matters for labels on left and right side
5363
5364                    temp = "";
5365                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5366                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
5367                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
5368                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
5369                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
5370                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
5371                    temp = temp.trim();
5372                    if(temp != null && !temp.isEmpty())
5373                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
5374                }
5375                else if(!strict)
5376                {
5377                    centered = false;
5378                }
5379
5380                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5381                {
5382                    y = 1;
5383                    temp = "";
5384                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5385                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5386                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5387                        temp += modifiers.get(Modifiers.Y_LOCATION);
5388
5389                    temp = temp.trim();
5390                    mods.add(new Modifier("X Y", temp, x, y, centered));
5391                }
5392
5393                if(modifiers.containsKey(Modifiers.W_DTG_1) || modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5394                {
5395                    y = 2;//above center
5396                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
5397                        y--;
5398
5399                    temp = modifiers.get(Modifiers.W_DTG_1);
5400
5401                    if(temp != null && !temp.isEmpty())
5402                        mods.add(new Modifier("W", temp, x, y, centered));
5403                }
5404
5405                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5406                {
5407                    y = -1;//below center
5408                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5409                    if(temp != null && !temp.isEmpty())
5410                        mods.add(new Modifier("T", temp, x, y, centered));
5411                }
5412
5413                if(modifiers.containsKey(Modifiers.Z_SPEED))
5414                {
5415                    y = -2;
5416                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5417                        y++;
5418                    temp = modifiers.get(Modifiers.Z_SPEED);
5419                    if(temp != null && !temp.isEmpty())
5420                        mods.add(new Modifier("Z", temp, x, y, centered));
5421                }
5422            }
5423            else if(ss == SymbolID.SymbolSet_LandInstallation)
5424            {
5425                //No top center label
5426
5427                //Do right side labels
5428                x = 1;//on right
5429
5430                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5431                {
5432                    y = 0;//center
5433                    centered = true;//vertically centered, only matters for labels on left and right side
5434                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5435
5436                    if(temp != null && !temp.isEmpty())
5437                        mods.add(new Modifier("H", temp, x, y, centered));
5438                }
5439                else if(!strict)
5440                {
5441                    centered = false;
5442                }
5443
5444                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5445                {
5446                    y = 1;//above center
5447                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5448
5449                    if(temp != null && !temp.isEmpty())
5450                        mods.add(new Modifier("G", temp, x, y, centered));
5451                }
5452
5453                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5454                {
5455                    y = 2;
5456                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5457                        y--;
5458
5459                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5460                    if(temp != null && !temp.isEmpty())
5461                        mods.add(new Modifier("AS", temp, x, y, centered));
5462                }
5463
5464                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5465                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
5466                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5467                {
5468                    y = -1;
5469
5470                    temp = "";
5471                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5472                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5473                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
5474                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
5475                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5476                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5477                    temp = temp.trim();
5478                    mods.add(new Modifier("J K P", temp, x, y, centered));
5479                }
5480
5481                //Do left side labels
5482                x = -1;//on left
5483
5484                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5485                {
5486                    y = 0;//center
5487                    centered = true;//vertically centered, only matters for labels on left and right side
5488
5489                    temp = "";
5490                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5491                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5492                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5493                        temp += modifiers.get(Modifiers.Y_LOCATION);
5494                    temp = temp.trim();
5495                    if(temp != null && !temp.isEmpty())
5496                        mods.add(new Modifier("X Y", temp, x, y, centered));
5497                }
5498                else if(!strict)
5499                {
5500                    centered = false;
5501                }
5502
5503                if(modifiers.containsKey(Modifiers.W_DTG_1))
5504                {
5505                    y = 1;//above center
5506
5507                    temp = modifiers.get(Modifiers.W_DTG_1);
5508
5509                    if(temp != null && !temp.isEmpty())
5510                        mods.add(new Modifier("W AR", temp, x, y, centered));
5511                }
5512
5513                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5514                {
5515                    y = -1;//below center
5516                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5517                    if(temp != null && !temp.isEmpty())
5518                        mods.add(new Modifier("T", temp, x, y, centered));
5519                }
5520            }
5521            else if(ss == SymbolID.SymbolSet_Air ||
5522                    ss == SymbolID.SymbolSet_AirMissile ||
5523                    ss == SymbolID.SymbolSet_SignalsIntelligence_Air)
5524            {
5525                //No top center label
5526
5527
5528                //Do right side labels
5529                x = 1;//on right
5530                centered = false;
5531
5532                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5533                {
5534                    y = 1;//above center
5535                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
5536
5537                    if(temp != null && !temp.isEmpty())
5538                        mods.add(new Modifier("P", temp, x, y, centered));
5539                }
5540
5541                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5542                {
5543                    y = 2;
5544                    if(!strict && !modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5545                        y--;
5546                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5547
5548                    if(temp != null && !temp.isEmpty())
5549                        mods.add(new Modifier("T", temp, x, y, centered));
5550                }
5551
5552                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5553                {
5554                    y = 3;
5555                    if(!strict)
5556                    {
5557                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5558                            y--;
5559                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5560                            y--;
5561                    }
5562
5563                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5564
5565                    if(temp != null && !temp.isEmpty())
5566                        mods.add(new Modifier("AS", temp, x, y, centered));
5567                }
5568
5569                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5570                {
5571                    y = -1;//below center
5572                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5573
5574                    if(temp != null && !temp.isEmpty())
5575                        mods.add(new Modifier("V", temp, x, y, centered));
5576                }
5577
5578                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5579                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5580                {
5581                    y = -2;//below center
5582                    if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5583                        y++;
5584
5585                    temp = "";
5586                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5587                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5588                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5589                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5590                    temp = temp.trim();
5591
5592                    if(temp != null && !temp.isEmpty())
5593                        mods.add(new Modifier("Z X", temp, x, y, centered));
5594                }
5595
5596                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5597                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5598                {
5599                    y = -3;
5600                    if(!strict)
5601                    {
5602                        if(!(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5603                                modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5604                            y++;
5605                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5606                            y++;
5607                    }
5608                    temp = "";
5609                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5610                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5611                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5612                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5613                    temp = temp.trim();
5614                    if(temp != null && !temp.isEmpty())
5615                        mods.add(new Modifier("G H", temp, x, y, centered));
5616                }
5617
5618                //No left side labels
5619
5620            }
5621            else if(ss == SymbolID.SymbolSet_Space ||
5622                    ss == SymbolID.SymbolSet_SpaceMissile ||
5623                    ss == SymbolID.SymbolSet_SignalsIntelligence_Space)
5624            {
5625                //No top center label
5626
5627
5628                //Do right side labels
5629                x = 1;//on right
5630                centered = false;
5631
5632                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5633                {
5634                    y = 1;//above center
5635                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5636                    if(temp != null && !temp.isEmpty())
5637                        mods.add(new Modifier("V", temp, x, y, centered));
5638                }
5639
5640                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5641                {
5642                    y = 2;
5643                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5644                        y--;
5645                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5646
5647                    if(temp != null && !temp.isEmpty())
5648                        mods.add(new Modifier("T", temp, x, y, centered));
5649                }
5650
5651                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5652                {
5653                    y = 3;
5654                    if(!strict)
5655                    {
5656                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5657                            y--;
5658                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5659                            y--;
5660                    }
5661
5662                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5663
5664                    if(temp != null && !temp.isEmpty())
5665                        mods.add(new Modifier("AS", temp, x, y, centered));
5666                }
5667
5668                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5669                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5670                {
5671                    y = -1;//below center
5672                    temp = "";
5673                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5674                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5675                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5676                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5677                    temp = temp.trim();
5678
5679                    if(temp != null && !temp.isEmpty())
5680                        mods.add(new Modifier("Z X", temp, x, y, centered));
5681                }
5682
5683                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5684                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5685                {
5686                    y = -2;
5687                    if(!strict &&
5688                            !(modifiers.containsKey(Modifiers.Z_SPEED) || modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5689                        y++;
5690                    temp = "";
5691                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5692                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5693                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5694                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5695                    temp = temp.trim();
5696                    if(temp != null && !temp.isEmpty())
5697                        mods.add(new Modifier("G H", temp, x, y, centered));
5698                }
5699
5700                //No left side labels
5701            }
5702            else if(ss == SymbolID.SymbolSet_SeaSurface ||
5703                    ss == SymbolID.SymbolSet_SignalsIntelligence_SeaSurface)
5704            {
5705                //No top center label
5706
5707
5708                //Do right side labels
5709                x = 1;//on right
5710                centered = true;
5711                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5712                {
5713                    y = 0;//center
5714                    centered = true;//vertically centered, only matters for labels on left and right side
5715                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5716                    if(temp != null && !temp.isEmpty())
5717                        mods.add(new Modifier("V", temp, x, y, centered));
5718                }
5719                else if(!strict)
5720                {
5721                    //if no "H', bring G and M closer to the center
5722                    centered = false;
5723                }
5724
5725                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5726                {
5727                    y = 1;//above center
5728                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
5729                    if(temp != null && !temp.isEmpty())
5730                        mods.add(new Modifier("P", temp, x, y, centered));
5731                }
5732
5733                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5734                {
5735                    y = 2;
5736                    if(!strict && !modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5737                        y--;
5738                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5739
5740                    if(temp != null && !temp.isEmpty())
5741                        mods.add(new Modifier("T", temp, x, y, centered));
5742                }
5743
5744                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5745                {
5746                    y = 3;
5747                    if(!strict)
5748                    {
5749                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5750                            y--;
5751                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5752                            y--;
5753                    }
5754
5755                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5756
5757                    if(temp != null && !temp.isEmpty())
5758                        mods.add(new Modifier("AS", temp, x, y, centered));
5759                }
5760
5761                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5762                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5763                {
5764                    y = -1;//below center
5765                    temp = "";
5766                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5767                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5768                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5769                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5770                    temp = temp.trim();
5771
5772                    if(temp != null && !temp.isEmpty())
5773                        mods.add(new Modifier("Z X", temp, x, y, centered));
5774                }
5775
5776                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5777                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5778                {
5779                    y = -2;
5780                    if(!strict &&
5781                            !(modifiers.containsKey(Modifiers.Z_SPEED) || modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5782                        y++;
5783                    temp = "";
5784                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5785                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5786                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5787                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5788                    temp = temp.trim();
5789                    if(temp != null && !temp.isEmpty())
5790                        mods.add(new Modifier("G H", temp, x, y, centered));
5791                }
5792
5793                //Do left side labels
5794                x = -1;
5795                centered = false;
5796                if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT) || modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5797                {
5798                    y = 3;//above center
5799                    if(!strict)
5800                        y--;
5801
5802                    temp = "";
5803                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5804                        temp = modifiers.get(Modifiers.AQ_GUARDED_UNIT) + sep;
5805                    if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5806                        temp += modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
5807                    temp = temp.trim();
5808
5809                    if(temp != null && !temp.isEmpty())
5810                        mods.add(new Modifier("AQ AR", temp, x, y, centered));
5811                }
5812            }
5813            else if(ss == SymbolID.SymbolSet_SeaSubsurface ||
5814                    ss == SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface)
5815            {
5816                //No top center label
5817
5818
5819                //Do right side labels
5820                x = 1;//on right
5821                centered = false;
5822                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5823                {
5824                    y = 1;//center
5825                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5826                    if(temp != null && !temp.isEmpty())
5827                        mods.add(new Modifier("V", temp, x, y, centered));
5828                }
5829
5830                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5831                {
5832                    y = 2;
5833                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5834                        y--;
5835                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5836
5837                    if(temp != null && !temp.isEmpty())
5838                        mods.add(new Modifier("T", temp, x, y, centered));
5839                }
5840
5841                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5842                {
5843                    y = 3;
5844                    if(!strict)
5845                    {
5846                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5847                            y--;
5848                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5849                            y--;
5850                    }
5851
5852                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5853
5854                    if(temp != null && !temp.isEmpty())
5855                        mods.add(new Modifier("AS", temp, x, y, centered));
5856                }
5857
5858                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5859                {
5860                    y = -1;//below center
5861
5862                    temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5863
5864                    if(temp != null && !temp.isEmpty())
5865                        mods.add(new Modifier("X", temp, x, y, centered));
5866                }
5867
5868                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5869                {
5870                    y = -2;
5871                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5872                        y++;
5873                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5874
5875                    if(temp != null && !temp.isEmpty())
5876                        mods.add(new Modifier("G", temp, x, y, centered));
5877                }
5878
5879                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5880                {
5881                    y = -3;//below center
5882                    if(!strict)
5883                    {
5884                        if(!modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5885                            y++;
5886                        if(!modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5887                            y++;
5888                    }
5889
5890                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5891
5892                    if(temp != null && !temp.isEmpty())
5893                        mods.add(new Modifier("H", temp, x, y, centered));
5894                }
5895
5896                //Do left side labels
5897                x = -1;
5898                centered = false;
5899                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5900                {
5901                    y = 3;//above center
5902                    if(!strict)
5903                    {
5904                        y--;
5905                    }
5906
5907                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
5908
5909                    if(temp != null && !temp.isEmpty())
5910                        mods.add(new Modifier("AR", temp, x, y, centered));
5911                }
5912
5913            }
5914            else if(ss == SymbolID.SymbolSet_Activities)
5915            {
5916                //No top center label
5917
5918                //Do right side labels
5919                x = 1;//on right
5920                centered = false;
5921
5922                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5923                {
5924                    y = 1;
5925
5926                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5927                    if(temp != null && !temp.isEmpty())
5928                        mods.add(new Modifier("G", temp, x, y, centered));
5929                }
5930
5931                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5932                {
5933                    y = 2;
5934                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5935                        y--;
5936                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5937
5938                    if(temp != null && !temp.isEmpty())
5939                        mods.add(new Modifier("AS", temp, x, y, centered));
5940                }
5941
5942                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5943                {
5944                    y = -1;//below center
5945                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5946                    if(temp != null && !temp.isEmpty())
5947                        mods.add(new Modifier("H", temp, x, y, centered));
5948                }
5949
5950                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5951                {
5952                    y = -2;
5953                    if(!strict && !modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5954                        y++;
5955                    temp = temp = modifiers.get(Modifiers.J_EVALUATION_RATING);
5956
5957                    if(temp != null && !temp.isEmpty())
5958                        mods.add(new Modifier("J", temp, x, y, centered));
5959                }
5960
5961                //Do left side labels
5962                x = -1;//on left
5963                centered = false;
5964
5965                if(modifiers.containsKey(Modifiers.Y_LOCATION))
5966                {
5967                    y = 1;
5968                    temp = modifiers.get(Modifiers.Y_LOCATION);
5969
5970                    if(temp != null && !temp.isEmpty())
5971                        mods.add(new Modifier("Y", temp, x, y, centered));
5972                }
5973
5974                if(modifiers.containsKey(Modifiers.W_DTG_1))
5975                {
5976                    y = 2;//above center
5977                    if(!strict && !modifiers.containsKey(Modifiers.Y_LOCATION))
5978                        y--;
5979                    temp = modifiers.get(Modifiers.W_DTG_1);
5980                    if(temp != null && !temp.isEmpty())
5981                        mods.add(new Modifier("W", temp, x, y, centered));
5982                }
5983
5984            }
5985            else if(ss == SymbolID.SymbolSet_CyberSpace)
5986            {
5987                //Do top center label
5988                x = 0;//centered
5989                y = 9;//on top of symbol
5990                if(modifiers.containsKey(Modifiers.B_ECHELON))
5991                {
5992                    temp = modifiers.get(Modifiers.B_ECHELON);
5993                    if(temp != null && !temp.isEmpty())
5994                        mods.add(new Modifier("B", temp, x, y, centered));
5995                }
5996
5997                //Do right side labels
5998                x = 1;//on right
5999                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6000                {
6001                    y = 0;//center
6002                    centered = true;//vertically centered, only matters for labels on left and right side
6003                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6004                    if(temp != null && !temp.isEmpty())
6005                        mods.add(new Modifier("H", temp, x, y, centered));
6006                }
6007                else if(!strict)
6008                {
6009                    //if no "H', bring G and M closer to the center
6010                    centered = false;
6011                }
6012
6013                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6014                {
6015                    y = 1;//above center
6016                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
6017                    if(temp != null && !temp.isEmpty())
6018                        mods.add(new Modifier("G", temp, x, y, centered));
6019                }
6020
6021                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
6022                {
6023                    y = 2;
6024                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6025                        y--;
6026                    temp = "";
6027                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
6028                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
6029                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6030                        temp += modifiers.get(Modifiers.AS_COUNTRY);
6031                    temp = temp.trim();
6032                    if(temp != null && !temp.isEmpty())
6033                        mods.add(new Modifier("F AS", temp, x, y, centered));
6034                }
6035
6036                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6037                {
6038                    y = -1;//below center
6039                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6040                    if(temp != null && !temp.isEmpty())
6041                        mods.add(new Modifier("M", temp, x, y, centered));
6042                }
6043
6044                if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6045                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6046                {
6047                    y = -2;
6048                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6049                        y++;
6050                    temp = "";
6051                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6052                        temp = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6053                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6054                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
6055
6056                    temp = temp.trim();
6057                    if(temp != null && !temp.isEmpty())
6058                        mods.add(new Modifier("K L", temp, x, y, centered));
6059                }
6060
6061                //Do left side labels
6062                x = -1;//on left
6063                centered = true;
6064
6065                if(modifiers.containsKey(Modifiers.Y_LOCATION))
6066                {
6067                    y = 0;
6068                    temp = modifiers.get(Modifiers.Y_LOCATION);
6069
6070                    if(temp != null && !temp.isEmpty())
6071                        mods.add(new Modifier("Y", temp, x, y, centered));
6072                }
6073                else if (!strict)
6074                {
6075                    centered = false;
6076                }
6077
6078                if(modifiers.containsKey(Modifiers.W_DTG_1))
6079                {
6080                    y = 1;//above center
6081                    temp = modifiers.get(Modifiers.W_DTG_1);
6082                    if(temp != null && !temp.isEmpty())
6083                        mods.add(new Modifier("W", temp, x, y, centered));
6084                }
6085
6086                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6087                {
6088                    y = -1;//below center
6089                    temp = "";
6090                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6091                        temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1) + sep;
6092                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6093                        temp += modifiers.get(Modifiers.V_EQUIP_TYPE);
6094
6095                    temp = temp.trim();
6096                    if(temp != null && !temp.isEmpty())
6097                        mods.add(new Modifier("T V", temp, x, y, centered));
6098                }
6099
6100            }
6101            /*else if(ver == SymbolID.SymbolSet_MineWarfare)
6102            {
6103                //no modifiers
6104            }//*/
6105            //else//SymbolSet Unknown
6106            //processUnknownTextModifiers
6107        }
6108        else// if(ver >= SymbolID.Version_2525E)
6109        {
6110            int fs = SymbolID.getFrameShape(symbolID);
6111            if(ss == SymbolID.SymbolSet_LandUnit ||
6112                    ss == SymbolID.SymbolSet_LandCivilianUnit_Organization ||
6113                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_LandUnit))
6114            {
6115                //Do top center label
6116                x = 0;//centered
6117                y = 9;//on top of symbol
6118                if(modifiers.containsKey(Modifiers.B_ECHELON))
6119                {
6120                    temp = modifiers.get(Modifiers.B_ECHELON);
6121                    if(temp != null && !temp.isEmpty())
6122                        mods.add(new Modifier("B", temp, x, y, centered));
6123                }
6124
6125                //Do right side labels
6126                x = 1;//on right
6127                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6128                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6129                {
6130                    y = 0;//center
6131                    centered = true;//vertically centered, only matters for labels on left and right side
6132                    temp = "";
6133                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6134                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6135                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6136                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6137                    temp = temp.trim();
6138                    if(temp != null && !temp.isEmpty())
6139                        mods.add(new Modifier("H AF", temp, x, y, centered));
6140                }
6141                else if(!strict)
6142                {
6143                    //if no "H', bring G and M closer to the center
6144                    centered = false;
6145                }
6146
6147                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6148                {
6149                    y = 1;//above center
6150                    temp = "";
6151                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6152                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6153                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6154                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6155                    temp = temp.trim();
6156                    if(temp != null && !temp.isEmpty())
6157                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6158                }
6159
6160                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
6161                {
6162                    y = 2;
6163                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6164                        y--;
6165                    temp = "";
6166                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
6167                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
6168                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6169                        temp += modifiers.get(Modifiers.AS_COUNTRY);
6170                    temp = temp.trim();
6171                    if(temp != null && !temp.isEmpty())
6172                        mods.add(new Modifier("F AS", temp, x, y, centered));
6173                }
6174
6175                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6176                {
6177                    y = -1;//below center
6178                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6179                    if(temp != null && !temp.isEmpty())
6180                        mods.add(new Modifier("M", temp, x, y, centered));
6181                }
6182
6183                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6184                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6185                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
6186                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6187                {
6188                    y = -2;
6189                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6190                        y++;
6191                    temp = "";
6192                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6193                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6194                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6195                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6196                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6197                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
6198                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6199                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6200                    temp = temp.trim();
6201                    if(temp != null && !temp.isEmpty())
6202                        mods.add(new Modifier("J K L P", temp, x, y, centered));
6203                }
6204
6205                //Do left side labels
6206                x = -1;//on left
6207
6208                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
6209                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
6210                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6211                {
6212                    y = 0;//center
6213                    centered = true;//vertically centered, only matters for labels on left and right side
6214
6215                    temp = "";
6216                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6217                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6218                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6219                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
6220                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6221                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6222                    temp = temp.trim();
6223                    if(temp != null && !temp.isEmpty())
6224                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
6225                }
6226                else if(!strict)
6227                {
6228                    centered = false;
6229                }
6230
6231                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6232                {
6233                    y = 1;
6234                    temp = "";
6235                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6236                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6237                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6238                        temp += modifiers.get(Modifiers.Y_LOCATION);
6239
6240                    temp = temp.trim();
6241                    mods.add(new Modifier("X Y", temp, x, y, centered));
6242                }
6243
6244                if(modifiers.containsKey(Modifiers.W_DTG_1))
6245                {
6246                    y = 2;//above center
6247                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6248                        y--;
6249
6250                    temp = modifiers.get(Modifiers.W_DTG_1);
6251
6252                    if(temp != null && !temp.isEmpty())
6253                        mods.add(new Modifier("W", temp, x, y, centered));
6254                }
6255
6256                if(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6257                {
6258                    y = -1;//below center
6259                    temp = "";
6260                    if(modifiers.containsKey(Modifiers.C_QUANTITY))
6261                        temp = modifiers.get(Modifiers.C_QUANTITY) + sep;
6262                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6263                        temp += modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6264
6265                    temp = temp.trim();
6266                    if(temp != null && !temp.isEmpty())
6267                        mods.add(new Modifier("C T", temp, x, y, centered));
6268                }
6269
6270                if(modifiers.containsKey(Modifiers.Z_SPEED))
6271                {
6272                    y = -2;
6273                    if(!strict && !(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
6274                        y++;
6275                    temp = modifiers.get(Modifiers.Z_SPEED);
6276                    if(temp != null && !temp.isEmpty())
6277                        mods.add(new Modifier("Z", temp, x, y, centered));
6278                }
6279            }
6280            else if(ss == SymbolID.SymbolSet_LandEquipment ||
6281                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_LandEquipment))
6282            {
6283                //Do top center label
6284                x = 0;//centered
6285                y = 9;//on top of symbol
6286                if(modifiers.containsKey(Modifiers.C_QUANTITY))
6287                {
6288                    temp = modifiers.get(Modifiers.C_QUANTITY);
6289                    if(temp != null && !temp.isEmpty())
6290                        mods.add(new Modifier("C", temp, x, y, centered));
6291                }
6292
6293                //Do right side labels
6294                x = 1;//on right
6295                centered = false;
6296
6297                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6298                {
6299                    y = 1;//above center
6300                    temp = "";
6301                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6302                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6303                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6304                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6305                    temp = temp.trim();
6306                    if(temp != null && !temp.isEmpty())
6307                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6308                }
6309
6310                if( modifiers.containsKey(Modifiers.AS_COUNTRY))
6311                {
6312                    y = 2;
6313                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6314                        y--;
6315                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6316
6317                    if(temp != null && !temp.isEmpty())
6318                        mods.add(new Modifier("AS", temp, x, y, centered));
6319                }
6320
6321                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6322                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6323                {
6324                    y = -1;
6325                    temp = "";
6326                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6327                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6328                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6329                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6330                    temp = temp.trim();
6331                    if(temp != null && !temp.isEmpty())
6332                        mods.add(new Modifier("H AF", temp, x, y, centered));
6333                }
6334
6335                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6336                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6337                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
6338                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6339                {
6340                    y = -2;
6341                    if(!strict && !(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6342                            modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER)))
6343                        y++;
6344                    temp = "";
6345                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6346                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6347                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6348                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6349                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6350                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
6351                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6352                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6353                    temp = temp.trim();
6354                    if(temp != null && !temp.isEmpty())
6355                        mods.add(new Modifier("J K L P", temp, x, y, centered));
6356                }
6357
6358                //Do left side labels
6359                x = -1;//on left
6360
6361                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
6362                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
6363                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6364                {
6365                    y = 0;//center
6366                    centered = true;//vertically centered, only matters for labels on left and right side
6367
6368                    temp = "";
6369                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6370                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6371                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6372                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
6373                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6374                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6375                    temp = temp.trim();
6376                    if(temp != null && !temp.isEmpty())
6377                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
6378                }
6379                else if(!strict)
6380                {
6381                    centered = false;
6382                }
6383
6384                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6385                {
6386                    y = 1;
6387                    temp = "";
6388                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6389                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6390                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6391                        temp += modifiers.get(Modifiers.Y_LOCATION);
6392
6393                    temp = temp.trim();
6394                    mods.add(new Modifier("X Y", temp, x, y, centered));
6395                }
6396
6397                if(modifiers.containsKey(Modifiers.W_DTG_1))
6398                {
6399                    y = 2;//above center
6400                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6401                        y--;
6402
6403                    temp = modifiers.get(Modifiers.W_DTG_1);
6404
6405                    if(temp != null && !temp.isEmpty())
6406                        mods.add(new Modifier("W", temp, x, y, centered));
6407                }
6408
6409                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6410                {
6411                    y = -1;//below center
6412                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6413
6414                    temp = temp.trim();
6415                    if(temp != null && !temp.isEmpty())
6416                        mods.add(new Modifier("T", temp, x, y, centered));
6417                }
6418
6419                if(modifiers.containsKey(Modifiers.Z_SPEED))
6420                {
6421                    y = -2;
6422                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6423                        y++;
6424                    temp = modifiers.get(Modifiers.Z_SPEED);
6425                    if(temp != null && !temp.isEmpty())
6426                        mods.add(new Modifier("Z", temp, x, y, centered));
6427                }
6428            }
6429            else if(ss == SymbolID.SymbolSet_LandInstallation)
6430            {
6431                //No top center label
6432
6433                //Do right side labels
6434                x = 1;//on right
6435                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6436                {
6437                    y = 0;//center
6438                    centered = true;//vertically centered, only matters for labels on left and right side
6439                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6440
6441                    if(temp != null && !temp.isEmpty())
6442                        mods.add(new Modifier("H", temp, x, y, centered));
6443                }
6444                else if(!strict)
6445                {
6446                    //if no "H', bring G and M closer to the center
6447                    centered = false;
6448                }
6449
6450                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6451                {
6452                    y = 1;//above center
6453                    temp = "";
6454                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6455                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6456                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6457                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6458                    temp = temp.trim();
6459                    if(temp != null && !temp.isEmpty())
6460                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6461                }
6462
6463                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6464                {
6465                    y = 2;
6466                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6467                        y--;
6468                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6469
6470                    if(temp != null && !temp.isEmpty())
6471                        mods.add(new Modifier("AS", temp, x, y, centered));
6472                }
6473
6474                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6475                {
6476                    y = -1;//below center
6477                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6478                    if(temp != null && !temp.isEmpty())
6479                        mods.add(new Modifier("M", temp, x, y, centered));
6480                }
6481
6482                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6483                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6484                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6485                {
6486                    y = -2;
6487                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6488                        y++;
6489                    temp = "";
6490                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6491                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6492                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6493                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6494                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6495                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6496                    temp = temp.trim();
6497                    if(temp != null && !temp.isEmpty())
6498                        mods.add(new Modifier("J K P", temp, x, y, centered));
6499                }
6500
6501                //Do left side labels
6502                x = -1;//on left
6503                centered = false;
6504
6505                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6506                {
6507                    y = 1;
6508                    temp = "";
6509                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6510                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6511                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6512                        temp += modifiers.get(Modifiers.Y_LOCATION);
6513
6514                    temp = temp.trim();
6515                    mods.add(new Modifier("X Y", temp, x, y, centered));
6516                }
6517
6518                if(modifiers.containsKey(Modifiers.W_DTG_1))
6519                {
6520                    y = 2;//above center
6521                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6522                        y--;
6523
6524                    temp = modifiers.get(Modifiers.W_DTG_1);
6525
6526                    if(temp != null && !temp.isEmpty())
6527                        mods.add(new Modifier("W", temp, x, y, centered));
6528                }
6529
6530                if(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6531                {
6532                    y = -1;//below center
6533                    temp = "";
6534                    if(modifiers.containsKey(Modifiers.C_QUANTITY))
6535                        temp = modifiers.get(Modifiers.C_QUANTITY) + sep;
6536                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6537                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6538
6539                    temp = temp.trim();
6540                    if(temp != null && !temp.isEmpty())
6541                        mods.add(new Modifier("C AE", temp, x, y, centered));
6542                }
6543
6544                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6545                {
6546                    y = -2;
6547                    if(!strict && !(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME)))
6548                        y++;
6549                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6550                    if(temp != null && !temp.isEmpty())
6551                        mods.add(new Modifier("T", temp, x, y, centered));
6552                }
6553            }
6554            else if(ss == SymbolID.SymbolSet_Space ||
6555                    ss == SymbolID.SymbolSet_SpaceMissile ||
6556                    ss == SymbolID.SymbolSet_Air ||
6557                    ss == SymbolID.SymbolSet_AirMissile ||
6558                    (ss == SymbolID.SymbolSet_SignalsIntelligence &&
6559                            (fs == SymbolID.FrameShape_Space || fs == SymbolID.FrameShape_Air)))
6560            {
6561                //No top center label
6562                x = 0;//centered
6563                y = 9;//on top of symbol
6564
6565                if(modifiers.containsKey(Modifiers.C_QUANTITY))
6566                {
6567                    temp = modifiers.get(Modifiers.C_QUANTITY);
6568                    if(temp != null && !temp.isEmpty())
6569                        mods.add(new Modifier("C", temp, x, y, centered));
6570                }
6571                else if(modifiers.containsKey(Modifiers.B_ECHELON))
6572                {
6573                    temp = modifiers.get(Modifiers.B_ECHELON);
6574                    if(temp != null && !temp.isEmpty())
6575                        mods.add(new Modifier("B", temp, x, y, centered));
6576                }
6577
6578
6579                //Do right side labels
6580                x = 1;//on right
6581                centered = true;
6582
6583                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6584                {
6585                    y = 0;//
6586                    temp = "";
6587                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6588                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6589                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6590                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6591                    temp = temp.trim();
6592
6593                    if(temp != null && !temp.isEmpty())
6594                        mods.add(new Modifier("V AF", temp, x, y, centered));
6595                }
6596                else
6597                {
6598                    centered = false;
6599                }
6600
6601                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.Y_LOCATION))
6602                {
6603                    y = 1;//above center
6604                    temp = "";
6605                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6606                        temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1) + sep;
6607                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6608                        temp += modifiers.get(Modifiers.Y_LOCATION);
6609                    temp = temp.trim();
6610
6611                    if(temp != null && !temp.isEmpty())
6612                        mods.add(new Modifier("T Y", temp, x, y, centered));
6613                }
6614
6615                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6616                {
6617                    y = 2;
6618                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6619                        y--;
6620                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6621
6622                    if(temp != null && !temp.isEmpty())
6623                        mods.add(new Modifier("AS", temp, x, y, centered));
6624                }
6625
6626                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS)  ||
6627                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)  ||
6628                        modifiers.containsKey(Modifiers.Z_SPEED))
6629                {
6630                    y = -1;//below center
6631                    temp = "";
6632                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6633                        temp = modifiers.get(Modifiers.P_IFF_SIF_AIS) + sep;
6634                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6635                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6636                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6637                        temp = modifiers.get(Modifiers.Z_SPEED);
6638
6639                    temp = temp.trim();
6640
6641                    if(temp != null && !temp.isEmpty())
6642                        mods.add(new Modifier("P X Z", temp, x, y, centered));
6643                }
6644
6645                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
6646                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6647                        modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6648                {
6649                    y = -2;//below center
6650                    if(!(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS)  ||
6651                            modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)  ||
6652                            modifiers.containsKey(Modifiers.Z_SPEED)))
6653                        y++;
6654
6655                    temp = "";
6656                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6657                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6658                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6659                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6660                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6661                        temp += modifiers.get(Modifiers.J_EVALUATION_RATING);
6662                    temp = temp.trim();
6663
6664                    if(temp != null && !temp.isEmpty())
6665                        mods.add(new Modifier("G H J", temp, x, y, centered));
6666                }
6667
6668                //No left side labels
6669                x = -1;//on right
6670                centered = true;
6671
6672                if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6673                {
6674                    y = 0;//
6675                    temp = temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE);
6676
6677                    if(temp != null && !temp.isEmpty())
6678                        mods.add(new Modifier("AD", temp, x, y, centered));
6679                }
6680                else
6681                {
6682                    centered = false;
6683                }
6684
6685                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6686                {
6687                    y = 1;//above center
6688                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6689
6690                    if(temp != null && !temp.isEmpty())
6691                        mods.add(new Modifier("AR", temp, x, y, centered));
6692                }
6693
6694                if(modifiers.containsKey(Modifiers.W_DTG_1))
6695                {
6696                    y = 2;
6697                    if(!strict && !modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6698                        y--;
6699                    temp = modifiers.get(Modifiers.W_DTG_1);
6700
6701                    if(temp != null && !temp.isEmpty())
6702                        mods.add(new Modifier("W", temp, x, y, centered));
6703                }
6704            }
6705            else if(ss == SymbolID.SymbolSet_SeaSurface ||
6706                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_SeaSurface))
6707            {
6708                //No top center label
6709
6710
6711                //Do right side labels
6712                x = 1;//on right
6713                centered = false;
6714
6715                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6716                {
6717                    y = 1;//above center
6718                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
6719
6720                    if(temp != null && !temp.isEmpty())
6721                        mods.add(new Modifier("V", temp, x, y, centered));
6722                }
6723
6724                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6725                {
6726                    y = 2;
6727                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6728                        y--;
6729                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6730
6731                    if(temp != null && !temp.isEmpty())
6732                        mods.add(new Modifier("T", temp, x, y, centered));
6733                }
6734
6735                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6736                {
6737                    y = 3;
6738                    if(!strict)
6739                    {
6740                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6741                            y--;
6742                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6743                            y--;
6744                    }
6745
6746                    temp = modifiers.get(Modifiers.AS_COUNTRY );
6747
6748                    if(temp != null && !temp.isEmpty())
6749                        mods.add(new Modifier("AS", temp, x, y, centered));
6750                }
6751
6752                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6753                {
6754                    y = -1;//below center
6755                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
6756
6757                    if(temp != null && !temp.isEmpty())
6758                        mods.add(new Modifier("P", temp, x, y, centered));
6759                }
6760
6761                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6762                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6763                {
6764                    y = -2;//below center
6765                    if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6766                        y++;
6767
6768                    temp = "";
6769                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6770                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6771                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6772                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6773                    temp = temp.trim();
6774
6775                    if(temp != null && !temp.isEmpty())
6776                        mods.add(new Modifier("G H", temp, x, y, centered));
6777                }
6778
6779                if(modifiers.containsKey(Modifiers.Y_LOCATION) ||
6780                        modifiers.containsKey(Modifiers.Z_SPEED))
6781                {
6782                    y = -3;
6783                    if(!strict)
6784                    {
6785                        if(!(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6786                                modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)))
6787                            y++;
6788                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6789                            y++;
6790                    }
6791                    temp = "";
6792                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6793                        temp = modifiers.get(Modifiers.Y_LOCATION) + sep;
6794                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6795                        temp += modifiers.get(Modifiers.Z_SPEED);
6796                    temp = temp.trim();
6797                    if(temp != null && !temp.isEmpty())
6798                        mods.add(new Modifier("Y Z", temp, x, y, centered));
6799                }
6800
6801                //No left side labels
6802                x = -1;
6803                centered = false;
6804                if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT) ||
6805                        modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6806                {
6807                    y = 2;
6808                    if(!strict)
6809                    {
6810                        y--;
6811                    }
6812                    temp = "";
6813                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6814                        temp = modifiers.get(Modifiers.AQ_GUARDED_UNIT) + sep;
6815                    if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6816                        temp += modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6817                    temp = temp.trim();
6818                    if(temp != null && !temp.isEmpty())
6819                        mods.add(new Modifier("AQ AR", temp, x, y, centered));
6820                }
6821            }
6822            else if(ss == SymbolID.SymbolSet_SeaSubsurface ||
6823                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_SeaSubsurface))
6824            {
6825                //No top center label
6826
6827
6828                //Do right side labels
6829                x = 1;//on right
6830                centered = false;
6831
6832                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6833                {
6834                    y = 1;//above center
6835                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
6836
6837                    if(temp != null && !temp.isEmpty())
6838                        mods.add(new Modifier("V", temp, x, y, centered));
6839                }
6840
6841                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6842                {
6843                    y = 2;
6844                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6845                        y--;
6846                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6847
6848                    if(temp != null && !temp.isEmpty())
6849                        mods.add(new Modifier("T", temp, x, y, centered));
6850                }
6851
6852                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6853                {
6854                    y = 3;
6855                    if(!strict)
6856                    {
6857                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6858                            y--;
6859                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6860                            y--;
6861                    }
6862
6863                    temp = modifiers.get(Modifiers.AS_COUNTRY );
6864
6865                    if(temp != null && !temp.isEmpty())
6866                        mods.add(new Modifier("AS", temp, x, y, centered));
6867                }
6868
6869                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6870                {
6871                    y = -1;//below center
6872                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
6873
6874                    if(temp != null && !temp.isEmpty())
6875                        mods.add(new Modifier("P", temp, x, y, centered));
6876                }
6877
6878                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6879                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6880                {
6881                    y = -2;//below center
6882                    if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6883                        y++;
6884
6885                    temp = "";
6886                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6887                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6888                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6889                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6890                    temp = temp.trim();
6891
6892                    if(temp != null && !temp.isEmpty())
6893                        mods.add(new Modifier("G H", temp, x, y, centered));
6894                }
6895
6896                if(modifiers.containsKey(Modifiers.Y_LOCATION) ||
6897                        modifiers.containsKey(Modifiers.Z_SPEED))
6898                {
6899                    y = -3;
6900                    if(!strict)
6901                    {
6902                        if(!(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6903                                modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)))
6904                            y++;
6905                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6906                            y++;
6907                    }
6908                    temp = "";
6909                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6910                        temp = modifiers.get(Modifiers.Y_LOCATION) + sep;
6911                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6912                        temp += modifiers.get(Modifiers.Z_SPEED);
6913                    temp = temp.trim();
6914                    if(temp != null && !temp.isEmpty())
6915                        mods.add(new Modifier("Y Z", temp, x, y, centered));
6916                }
6917
6918                //No left side labels
6919                x = -1;
6920                centered = false;
6921                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6922                {
6923                    y = 1;
6924                    temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
6925
6926                    if(temp != null && !temp.isEmpty())
6927                        mods.add(new Modifier("X", temp, x, y, centered));
6928                }
6929
6930                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6931                {
6932                    y = 2;
6933                    if(!strict && !modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6934                    {
6935                        y--;
6936                    }
6937                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6938                    temp = temp.trim();
6939                    if(temp != null && !temp.isEmpty())
6940                        mods.add(new Modifier("AR", temp, x, y, centered));
6941                }
6942            }
6943            else if(ss == SymbolID.SymbolSet_DismountedIndividuals)
6944            {
6945                //No top center label
6946
6947
6948                //Do right side labels
6949                x = 1;//on right
6950                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6951                {
6952                    y = 0;//center
6953                    centered = true;//vertically centered, only matters for labels on left and right side
6954                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6955
6956                    if(temp != null && !temp.isEmpty())
6957                        mods.add(new Modifier("H", temp, x, y, centered));
6958                }
6959                else if(!strict)
6960                {
6961                    centered = false;
6962                }
6963
6964                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6965                {
6966                    y = 1;//above center
6967                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
6968
6969                    if(temp != null && !temp.isEmpty())
6970                        mods.add(new Modifier("G", temp, x, y, centered));
6971                }
6972
6973                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6974                {
6975                    y = 2;
6976                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)))
6977                        y--;
6978                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6979
6980                    if(temp != null && !temp.isEmpty())
6981                        mods.add(new Modifier("AS", temp, x, y, centered));
6982                }
6983
6984                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6985                {
6986                    y = -1;//below center
6987                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6988                    if(temp != null && !temp.isEmpty())
6989                        mods.add(new Modifier("M", temp, x, y, centered));
6990                }
6991
6992                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6993                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6994                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6995                {
6996                    y = -2;
6997                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6998                        y++;
6999                    temp = "";
7000                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
7001                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
7002                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
7003                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
7004                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
7005                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
7006                    temp = temp.trim();
7007                    if(temp != null && !temp.isEmpty())
7008                        mods.add(new Modifier("J K P", temp, x, y, centered));
7009                }
7010
7011                //Do left side labels
7012                x = -1;//on left
7013
7014                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
7015                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
7016                {
7017                    y = 0;//center
7018                    centered = true;//vertically centered, only matters for labels on left and right side
7019
7020                    temp = "";
7021                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
7022                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
7023                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
7024                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
7025                    temp = temp.trim();
7026                    if(temp != null && !temp.isEmpty())
7027                        mods.add(new Modifier("V AF", temp, x, y, centered));
7028                }
7029                else if(!strict)
7030                {
7031                    centered = false;
7032                }
7033
7034                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
7035                {
7036                    y = 1;
7037                    temp = "";
7038                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
7039                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
7040                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
7041                        temp += modifiers.get(Modifiers.Y_LOCATION);
7042
7043                    temp = temp.trim();
7044                    mods.add(new Modifier("X Y", temp, x, y, centered));
7045                }
7046
7047                if(modifiers.containsKey(Modifiers.W_DTG_1))
7048                {
7049                    y = 2;//above center
7050                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
7051                        y--;
7052
7053                    temp = modifiers.get(Modifiers.W_DTG_1);
7054
7055                    if(temp != null && !temp.isEmpty())
7056                        mods.add(new Modifier("W", temp, x, y, centered));
7057                }
7058
7059                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7060                {
7061                    y = -1;//below center
7062                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7063
7064                    if(temp != null && !temp.isEmpty())
7065                        mods.add(new Modifier("T", temp, x, y, centered));
7066                }
7067
7068                if(modifiers.containsKey(Modifiers.Z_SPEED))
7069                {
7070                    y = -2;
7071                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
7072                        y++;
7073                    temp = modifiers.get(Modifiers.Z_SPEED);
7074                    if(temp != null && !temp.isEmpty())
7075                        mods.add(new Modifier("Z", temp, x, y, centered));
7076                }
7077            }
7078            else if(ss == SymbolID.SymbolSet_Activities)
7079            {
7080                //No top center label
7081
7082
7083                //Do right side labels
7084                x = 1;//on right
7085                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7086                {
7087                    y = 0;//center
7088                    centered = true;//vertically centered, only matters for labels on left and right side
7089                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7090
7091                    if(temp != null && !temp.isEmpty())
7092                        mods.add(new Modifier("G", temp, x, y, centered));
7093                }
7094                else if(!strict)
7095                {
7096                    centered = false;
7097                }
7098
7099                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7100                {
7101                    y = 1;//above center
7102                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7103
7104                    if(temp != null && !temp.isEmpty())
7105                        mods.add(new Modifier("T", temp, x, y, centered));
7106                }
7107
7108                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7109                {
7110                    y = 2;
7111                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
7112                        y--;
7113                    temp = modifiers.get(Modifiers.AS_COUNTRY);
7114
7115                    if(temp != null && !temp.isEmpty())
7116                        mods.add(new Modifier("AS", temp, x, y, centered));
7117                }
7118
7119                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7120                {
7121                    y = -1;//below center
7122                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7123                    if(temp != null && !temp.isEmpty())
7124                        mods.add(new Modifier("H", temp, x, y, centered));
7125                }
7126
7127                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
7128                {
7129                    y = -2;
7130                    if(!strict && !modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7131                        y++;
7132                    temp = modifiers.get(Modifiers.J_EVALUATION_RATING);
7133
7134                    if(temp != null && !temp.isEmpty())
7135                        mods.add(new Modifier("J", temp, x, y, centered));
7136                }
7137
7138                //Do left side labels
7139                x = -1;//on left
7140
7141                if(!strict)
7142                {
7143                    centered = false;
7144                }
7145
7146                if(modifiers.containsKey(Modifiers.Y_LOCATION))
7147                {
7148                    y = 1;
7149                    temp = modifiers.get(Modifiers.Y_LOCATION);
7150
7151                    if(temp != null && !temp.isEmpty())
7152                        mods.add(new Modifier("Y", temp, x, y, centered));
7153                }
7154
7155                if(modifiers.containsKey(Modifiers.W_DTG_1))
7156                {
7157                    y = 2;//above center
7158                    if(!strict && !(modifiers.containsKey(Modifiers.Y_LOCATION)))
7159                        y--;
7160
7161                    temp = modifiers.get(Modifiers.W_DTG_1);
7162
7163                    if(temp != null && !temp.isEmpty())
7164                        mods.add(new Modifier("W", temp, x, y, centered));
7165                }
7166
7167                if(modifiers.containsKey(Modifiers.C_QUANTITY))
7168                {
7169                    y = -1;//below center
7170                    temp = modifiers.get(Modifiers.C_QUANTITY);
7171
7172                    if(temp != null && !temp.isEmpty())
7173                        mods.add(new Modifier("C", temp, x, y, centered));
7174                }
7175
7176            }
7177            else if(ss == SymbolID.SymbolSet_CyberSpace ||
7178                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_Cyberspace))
7179            {
7180                //Do top center label
7181                x = 0;//centered
7182                y = 9;//on top of symbol
7183                if(modifiers.containsKey(Modifiers.B_ECHELON))
7184                {
7185                    temp = modifiers.get(Modifiers.B_ECHELON);
7186                    if(temp != null && !temp.isEmpty())
7187                        mods.add(new Modifier("B", temp, x, y, centered));
7188                }
7189
7190                //Do right side labels
7191                x = 1;//on right
7192                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7193                {
7194                    y = 0;//center
7195                    centered = true;//vertically centered, only matters for labels on left and right side
7196                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7197
7198                    if(temp != null && !temp.isEmpty())
7199                        mods.add(new Modifier("H", temp, x, y, centered));
7200                }
7201                else if(!strict)
7202                {
7203                    centered = false;
7204                }
7205
7206                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7207                {
7208                    y = 1;//above center
7209                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7210
7211                    if(temp != null && !temp.isEmpty())
7212                        mods.add(new Modifier("G", temp, x, y, centered));
7213                }
7214
7215                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
7216                {
7217                    y = 2;
7218                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)))
7219                        y--;
7220                    temp = "";
7221                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
7222                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
7223                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7224                        temp += modifiers.get(Modifiers.AS_COUNTRY);
7225                    temp = temp.trim();
7226                    if(temp != null && !temp.isEmpty())
7227                        mods.add(new Modifier("F AS", temp, x, y, centered));
7228                }
7229
7230                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7231                {
7232                    y = -1;//below center
7233                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
7234                    if(temp != null && !temp.isEmpty())
7235                        mods.add(new Modifier("M", temp, x, y, centered));
7236                }
7237
7238                if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) || modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
7239                {
7240                    y = -2;
7241                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7242                        y++;
7243                    temp = "";
7244                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
7245                        temp = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
7246                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
7247                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
7248                    temp = temp.trim();
7249                    if(temp != null && !temp.isEmpty())
7250                        mods.add(new Modifier("K L", temp, x, y, centered));
7251                }
7252
7253                //Do left side labels
7254                x=-1;
7255                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
7256                {
7257                    y = 0;//center
7258                    centered = true;//vertically centered, only matters for labels on left and right side
7259
7260                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
7261
7262                    if(temp != null && !temp.isEmpty())
7263                        mods.add(new Modifier("V", temp, x, y, centered));
7264                }
7265                else if(!strict)
7266                {
7267                    centered = false;
7268                }
7269
7270                if(modifiers.containsKey(Modifiers.Y_LOCATION))
7271                {
7272                    y = 1;
7273                    temp = modifiers.get(Modifiers.Y_LOCATION);
7274
7275                    if(temp != null && !temp.isEmpty())
7276                        mods.add(new Modifier("Y", temp, x, y, centered));
7277                }
7278
7279                if(modifiers.containsKey(Modifiers.W_DTG_1))
7280                {
7281                    y = 2;//above center
7282                    if(!strict && !(modifiers.containsKey(Modifiers.Y_LOCATION)))
7283                        y--;
7284
7285                    temp = modifiers.get(Modifiers.W_DTG_1);
7286
7287                    if(temp != null && !temp.isEmpty())
7288                        mods.add(new Modifier("W", temp, x, y, centered));
7289                }
7290
7291                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7292                {
7293                    y = -1;//below center
7294                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7295
7296                    if(temp != null && !temp.isEmpty())
7297                        mods.add(new Modifier("T", temp, x, y, centered));
7298                }
7299            }
7300            /*else if(ver == SymbolID.SymbolSet_MineWarfare)
7301            {
7302                //no modifiers
7303            }//*/
7304            //else//SymbolSet Unknown
7305            //processUnknownTextModifiers
7306        }
7307
7308        return mods;
7309    }
7310
7311
7312    /**
7313     *
7314     * @param bounds bounds of the core icon
7315     * @param labelWidth height of the label to be placed
7316     * @param location if 1, label on right side of symbol. On left if -1, center if 0.
7317     * @returns
7318     */
7319    private static double getLabelXPosition(Rect bounds, int labelWidth, int location, float modifierFontHeight)
7320    {
7321        int buffer = (int)modifierFontHeight/2;
7322
7323        double x = 0;
7324        if(location == 1)//on right
7325        {
7326            x = bounds.left + bounds.width() + buffer;
7327        }
7328        else if(location == -1)//left
7329        {
7330            x = bounds.left - labelWidth - buffer;
7331        }
7332        else if(location == 0)
7333        {
7334            x = (int)Math.round((bounds.left + (bounds.width() * 0.5f)) - (labelWidth * 0.5f));
7335        }
7336        return x;
7337    }
7338
7339    /**
7340     *
7341     * @param bounds bounds of the core icon
7342     * @param labelHeight height of the label to be placed
7343     * @param descent descent of the label to be placed
7344     * @param bufferText spacing buffer if desired
7345     * @param centered if true, there will be a center label location identified by 0
7346     * @param location positive 1, 2, 3 to be above symbol mid-point or negative values to be below
7347     * @returns y position
7348     */
7349    private static double getLabelYPosition(Rect bounds, int labelHeight, int descent, int bufferText, boolean centered, int location) {
7350        double y = 0;
7351        if (bounds != null && !bounds.isEmpty())
7352        {
7353            if(centered)
7354            {
7355                switch (location)
7356                {
7357                    case 3://3 above center
7358                        y = (bounds.height());
7359                        y = ((y * 0.5) + (labelHeight * 0.5));
7360                        y = y - ((labelHeight + bufferText) * 3);
7361                        y = bounds.top + y;
7362                        break;
7363                    case 2://2 above center
7364                        y = (bounds.height());
7365                        y = ((y * 0.5) + (labelHeight * 0.5));
7366                        y = y - ((labelHeight + bufferText) * 2);
7367                        y = bounds.top + y;
7368                        break;
7369                    case 1://1 above center
7370                        y = (bounds.height());
7371                        y = ((y * 0.5) + (labelHeight * 0.5));
7372                        y = y - ((labelHeight + bufferText));
7373                        y = bounds.top + y;
7374                        break;
7375                    case 0: //centered
7376                        y = (bounds.height());
7377                        y = ((y * 0.5) + ((labelHeight - descent) * 0.5));
7378                        y = bounds.top + y;
7379                        break;
7380                    case -1://1 below center
7381                        y = (bounds.height());
7382                        y = ((y * 0.5) + (labelHeight * 0.5));
7383                        y = y + ((labelHeight + bufferText - descent));
7384                        y = bounds.top + y;
7385                        break;
7386                    case -2://2 below center
7387                        y = (bounds.height());
7388                        y = ((y * 0.5) + (labelHeight * 0.5));
7389                        y = y + ((labelHeight + bufferText) * 2) - (descent);
7390                        y = bounds.top + y;
7391                        break;
7392                    case -3://3 below center
7393                        y = (bounds.height());
7394                        y = ((y * 0.5) + (labelHeight * 0.5));
7395                        y = y + ((labelHeight + bufferText) * 3) - (descent);
7396                        y = bounds.top + y;
7397                        break;
7398                }
7399            }
7400            else//split between top and bottom
7401            {
7402                switch (location)
7403                {
7404                    case 3:
7405                        y = (bounds.top + ((bounds.height() / 2) - descent - labelHeight*2 - bufferText));
7406                        break;
7407                    case 2:
7408                        y = (bounds.top + ((bounds.height() / 2) - descent - labelHeight - bufferText));
7409                        break;
7410                    case 1:
7411                        y = (bounds.top + ((bounds.height() / 2) - descent));
7412                        break;
7413                    case -1:
7414                        y = (bounds.top + (bounds.height() / 2) + (labelHeight - descent + bufferText));
7415                        break;
7416                    case -2:
7417                        y = (bounds.top + (bounds.height() / 2) + ((labelHeight*2 - descent + bufferText)));
7418                        break;
7419                    case -3:
7420                        y = (bounds.top + (bounds.height() / 2) + ((labelHeight*3 - descent + bufferText)));
7421                        break;
7422                }
7423            }
7424        }
7425        return y;
7426    }
7427
7428    private static boolean isCOnTop(String symbolID)
7429    {
7430        boolean onTop = false;
7431
7432        int version = SymbolID.getVersion(symbolID);
7433        int ss = SymbolID.getSymbolSet(symbolID);
7434        char frame = SymbolID.getFrameShape(symbolID);
7435
7436        if(SymbolUtilities.hasModifier(symbolID,Modifiers.C_QUANTITY)) {
7437            if (frame == SymbolID.FrameShape_Air || frame == SymbolID.FrameShape_Space)
7438                onTop = true;
7439            else if(frame == '0')
7440            {
7441                if (ss == SymbolID.SymbolSet_Air ||
7442                        ss == SymbolID.SymbolSet_AirMissile ||
7443                        ss == SymbolID.SymbolSet_Space ||
7444                        ss == SymbolID.SymbolSet_SpaceMissile ||
7445                        ss == SymbolID.SymbolSet_SignalsIntelligence_Air ||
7446                        (ss == SymbolID.SymbolSet_LandEquipment && version <= SymbolID.Version_2525Dch1)) {
7447                    onTop = true;
7448                }
7449            }
7450        }
7451        return onTop;
7452    }
7453    public static boolean hasDisplayModifiers(String symbolID, Map<String,String> modifiers)
7454    {
7455        boolean hasModifiers = false;
7456        int ss = SymbolID.getSymbolSet(symbolID);
7457        int status = SymbolID.getStatus(symbolID);
7458        int context = SymbolID.getContext(symbolID);
7459
7460        if(ss == SymbolID.SymbolSet_ControlMeasure)//check control measure
7461        {
7462            if (SymbolUtilities.isCBRNEvent(symbolID) == true && modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT))
7463            {
7464                hasModifiers = true;
7465            }
7466            else if(SymbolUtilities.hasFDI(symbolID))
7467                hasModifiers = true;
7468        }
7469        else if(ss != SymbolID.SymbolSet_Atmospheric &&
7470                ss != SymbolID.SymbolSet_Oceanographic &&
7471                ss != SymbolID.SymbolSet_MeteorologicalSpace)
7472        {//checking units
7473
7474            if(context > 0) //Exercise or Simulation
7475                hasModifiers = true;
7476
7477            //echelon or mobility,
7478            if (SymbolID.getAmplifierDescriptor(symbolID) > 0 || modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT))
7479                hasModifiers = true;
7480
7481            if(modifiers.containsKey(Modifiers.AJ_SPEED_LEADER))
7482                hasModifiers = true;
7483
7484            if(modifiers.containsKey(Modifiers.AO_ENGAGEMENT_BAR))
7485                hasModifiers = true;
7486
7487            //HQ/Taskforce
7488            if(SymbolID.getHQTFD(symbolID) > 0)
7489                hasModifiers = true;
7490
7491            if(status > 1)//Fully capable, damaged, destroyed
7492                hasModifiers = true;
7493        }//no display modifiers for single point weather
7494
7495
7496
7497        return hasModifiers;
7498    }
7499
7500    public static boolean hasTextModifiers(String symbolID, Map<String,String> modifiers)
7501    {
7502
7503        int ss = SymbolID.getSymbolSet(symbolID);
7504        int ec = SymbolID.getEntityCode(symbolID);
7505        if(ss == SymbolID.SymbolSet_Atmospheric)
7506        {
7507            switch(ec)
7508            {
7509                case 110102: //tropopause low
7510                case 110202: //tropopause high
7511                case 162200: //tropopause level ?
7512                case 162300: //freezing level ?
7513                    return true;
7514                default:
7515                        return false;
7516            }
7517        }
7518        else if(ss == SymbolID.SymbolSet_Oceanographic || ss == SymbolID.SymbolSet_MeteorologicalSpace)
7519        {
7520            return false;
7521        }
7522        else if (ss == SymbolID.SymbolSet_ControlMeasure)
7523        {
7524            MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
7525
7526            if( msi.getModifiers().size() > 0 && modifiers != null && modifiers.size() > 0)
7527                return true;
7528            else
7529                return false;
7530        }
7531        else
7532        {
7533
7534            if (SymbolUtilities.getStandardIdentityModifier(symbolID) != null)
7535            {
7536                return true;
7537            }
7538
7539            int cc = SymbolID.getCountryCode(symbolID);
7540            if (cc > 0 && !GENCLookup.getInstance().get3CharCode(cc).isEmpty())
7541            {
7542                return true;
7543            }//*/
7544
7545            else if (modifiers.size() > 0)
7546            {
7547                return true;
7548            }
7549        }
7550        return false;
7551    }
7552
7553    /**
7554     * Rerturns either the default font from RendererSettings or font based on properties
7555     * set in MilStdAttributes.
7556     * @param attributes
7557     * @return
7558     */
7559    private static Paint getFont(Map<String,String> attributes)
7560    {
7561        Paint p = null;
7562        Typeface tf = null;
7563
7564        p = RendererSettings.getInstance().getModiferFont();
7565
7566        String[] props = RendererSettings.getInstance().getModiferFontProps();
7567
7568        String ff = props[0];
7569        int fstyle = Integer.parseInt(props[1]);// modifierFont.getTypeface().getStyle();
7570        float fsize = Float.parseFloat(props[2]);// modifierFont.getTextSize();
7571        String temp = null;
7572
7573
7574        if(attributes.containsKey(MilStdAttributes.FontFamily) ||
7575                attributes.containsKey(MilStdAttributes.FontStyle) ||
7576                attributes.containsKey(MilStdAttributes.FontSize))
7577        {
7578            if(attributes.containsKey(MilStdAttributes.FontStyle))
7579            {
7580                temp = attributes.get(MilStdAttributes.FontStyle);
7581                if (temp != null && !temp.isEmpty()) {
7582                    fstyle = Integer.parseInt(temp);
7583                }
7584            }
7585            if(attributes.containsKey(MilStdAttributes.FontSize))
7586            {
7587                temp = attributes.get(MilStdAttributes.FontSize);
7588                if (temp != null && !temp.isEmpty()) {
7589                    fsize = Float.parseFloat(temp);
7590                }
7591            }
7592            if(attributes.containsKey(MilStdAttributes.FontFamily))
7593            {
7594                temp = attributes.get(MilStdAttributes.FontFamily);
7595                if (temp != null && !temp.isEmpty()) {
7596                    ff =  temp;//Typeface.create(temp,fstyle);
7597                }
7598            }
7599            tf = Typeface.create(ff,fstyle);
7600            if(tf == null)
7601                tf = Typeface.create(props[0],fstyle);
7602            if(tf == null)
7603                return null;
7604
7605            p = new Paint();
7606            p.setTextSize(fsize);
7607            p.setAntiAlias(true);
7608            p.setTypeface(tf);
7609            p.setStrokeCap(Cap.BUTT);
7610            p.setStrokeJoin(Join.MITER);
7611            p.setStrokeMiter(3f);
7612
7613            return p;
7614        }
7615        else
7616            return _modifierFont;
7617
7618    }
7619
7620    private static float[] getFontHeightandDescent(Paint font)
7621    {
7622        float[] hd = {0f,0f};
7623
7624        if(font != null) {
7625            Paint.FontMetrics fm = font.getFontMetrics();
7626            //_modifierFontHeight = fm.top + fm.bottom;
7627            hd[0] = fm.bottom - fm.top;
7628            hd[1] = fm.descent;
7629        }
7630        return hd;
7631    }
7632
7633}