001package armyc2.c5isr.renderer;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.Locale;
006import java.util.Map;
007
008import android.graphics.Bitmap;
009import android.graphics.Canvas;
010import android.graphics.DashPathEffect;
011import android.graphics.Paint;
012import android.graphics.Path;
013import android.graphics.Point;
014import android.graphics.PointF;
015import android.graphics.Rect;
016import android.graphics.RectF;
017import android.graphics.Bitmap.Config;
018import android.graphics.Paint.Cap;
019import android.graphics.Paint.Join;
020import android.graphics.Paint.Style;
021import android.graphics.Path.Direction;
022import android.graphics.Typeface;
023
024import armyc2.c5isr.renderer.utilities.Color;
025import armyc2.c5isr.renderer.utilities.ErrorLogger;
026import armyc2.c5isr.renderer.utilities.GENCLookup;
027import armyc2.c5isr.renderer.utilities.ImageInfo;
028import armyc2.c5isr.renderer.utilities.MSInfo;
029import armyc2.c5isr.renderer.utilities.MSLookup;
030import armyc2.c5isr.renderer.utilities.MilStdAttributes;
031import armyc2.c5isr.renderer.utilities.Modifier;
032import armyc2.c5isr.renderer.utilities.Modifiers;
033import armyc2.c5isr.renderer.utilities.PathUtilities;
034import armyc2.c5isr.renderer.utilities.RectUtilities;
035import armyc2.c5isr.renderer.utilities.RendererSettings;
036import armyc2.c5isr.renderer.utilities.RendererUtilities;
037import armyc2.c5isr.renderer.utilities.SVGInfo;
038import armyc2.c5isr.renderer.utilities.SVGLookup;
039import armyc2.c5isr.renderer.utilities.SVGPath;
040import armyc2.c5isr.renderer.utilities.SVGSymbolInfo;
041import armyc2.c5isr.renderer.utilities.Shape2SVG;
042import armyc2.c5isr.renderer.utilities.SymbolDimensionInfo;
043import armyc2.c5isr.renderer.utilities.SymbolID;
044import armyc2.c5isr.renderer.utilities.SymbolUtilities;
045import armyc2.c5isr.renderer.utilities.TextInfo;
046
047/**
048 * This class is used for rendering the labels/amplifiers/modifiers around the single point symbol.
049 */
050public class ModifierRenderer
051{
052
053    private static Paint _modifierFont = null;
054    private static float _modifierFontHeight = 10f;
055    private static float _modifierFontDescent = 2f;
056    private static RendererSettings RS = RendererSettings.getInstance();
057
058    private static final Object modifierFontMutex = new Object();
059    public static void setModifierFont(Paint font, float height, float descent)
060    {
061        synchronized (modifierFontMutex) {
062            _modifierFont = font;
063            _modifierFontHeight = height;
064            _modifierFontDescent = descent;
065        }
066    }
067
068    public static SymbolDimensionInfo processUnitDisplayModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Boolean hasTextModifiers, Map<String,String> attributes)
069    {
070
071        ImageInfo ii = null;
072        ImageInfo newii = null;
073        SVGSymbolInfo ssi = null;
074        SymbolDimensionInfo newsdi = null;
075        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
076        Rect imageBounds = new Rect(sdi.getImageBounds());
077        Point centerPoint = new Point(sdi.getCenterPoint());
078        Point symbolCenter = new Point(symbolBounds.centerX(), symbolBounds.centerY());
079        TextInfo tiEchelon = null;
080        TextInfo tiAM = null;
081        Rect echelonBounds = null;
082        Rect amBounds = null;
083        Color textColor = Color.BLACK;
084        Color textBackgroundColor = null;
085        float strokeWidth = 3.0f;
086        float strokeWidthNL = 3.0f;
087        Color lineColor = SymbolUtilities.getLineColorOfAffiliation(symbolID);
088        Color fillColor = SymbolUtilities.getFillColorOfAffiliation(symbolID);
089        int buffer = 0;
090        int alpha = 255;
091        //ctx = null;
092        int offsetX = 0;
093        int offsetY = 0;
094        int pixelSize = RendererSettings.getInstance().getDefaultPixelSize();
095        SVGPath svgMobilityPath = null;
096        String svgMobilityGroup = null;
097
098        Paint modifierFont = getFont(attributes);
099        float[] hd = getFontHeightandDescent(modifierFont);
100        float modifierFontHeight = hd[0];
101        float modifierFontDescent = hd[1];
102
103        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
104        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
105        {
106            String temp = attributes.get(MilStdAttributes.FontFamily);
107            if(temp != null && !temp.isEmpty())
108                modifierFontName = temp;
109        }
110
111        int ss = SymbolID.getSymbolSet(symbolID);
112
113        if (attributes.containsKey(MilStdAttributes.Alpha))
114        {
115            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
116            textColor.setAlpha(alpha);
117        }
118        if (attributes.containsKey(MilStdAttributes.TextColor))
119        {
120            textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
121            if(alpha > -1)
122                textColor.setAlpha(alpha);
123        }
124        if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
125        {
126            textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
127            if(alpha > -1)
128                textBackgroundColor.setAlpha(alpha);
129        }
130        if (attributes.containsKey(MilStdAttributes.LineColor))
131        {
132            lineColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.LineColor));
133        }
134        if (attributes.containsKey(MilStdAttributes.FillColor))
135        {
136            fillColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.FillColor));
137        }
138        if(attributes.containsKey(MilStdAttributes.PixelSize))
139        {
140            pixelSize = Integer.parseInt(attributes.get(MilStdAttributes.PixelSize));
141        }
142
143        //float fontsize = RendererSettings.getInstance().getModiferFont().getTextSize();
144
145        // <editor-fold defaultstate="collapsed" desc="Build Mobility Modifiers">
146        float strokeWidthBasedOnDPI = 1;//min//Math.max(RendererSettings.getInstance().getDeviceDPI()/210,1);//min DPI
147        strokeWidthBasedOnDPI = Math.max(pixelSize / 25f,strokeWidthBasedOnDPI);//dpi base on symbol size
148        strokeWidthBasedOnDPI = Math.min(strokeWidthBasedOnDPI,RendererSettings.getInstance().getDeviceDPI()/32f);//max dpi
149
150        RectF mobilityBounds = null;
151        int ad = SymbolID.getAmplifierDescriptor(symbolID);//echelon/mobility
152        List<Path> shapes = new ArrayList<Path>();
153        Path mobilityPath = null;
154        Path mobilityPathFill = null;
155        if (ad >= SymbolID.Mobility_WheeledLimitedCrossCountry &&
156                (SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.R_MOBILITY_INDICATOR) ||
157                 SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AG_AUX_EQUIP_INDICATOR)))
158        {
159
160            //Draw Mobility
161            int fifth = (int) ((symbolBounds.width() * 0.2) + 0.5f);
162            mobilityPath = new Path();
163            svgMobilityPath = null;
164            svgMobilityGroup = null;
165
166            int x = 0;
167            int y = 0;
168            int centerX = 0;
169            int bottomY = 0;
170            int height = 0;
171            int width = 0;
172            int middleY = 0;
173            int wheelOffset = 2;
174            int wheelSize = fifth;//10;
175            int rrHeight = fifth;//10;
176            int rrArcWidth = (int) ((fifth * 1.5) + 0.5f);//16;
177            float rad = wheelSize/2;
178
179
180            x = (int) symbolBounds.left + 1;
181            y = (int) symbolBounds.top;
182            height = Math.round(symbolBounds.height());
183            width = Math.round(symbolBounds.width()) - 3;
184            bottomY = y + height + 2;
185
186
187
188            if (ad >= SymbolID.Mobility_WheeledLimitedCrossCountry && //31, mobility starts above 30
189                    SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.R_MOBILITY_INDICATOR))
190            {
191                bottomY = y + height + 2;
192
193                //wheelSize = width / 7;
194                //rrHeight = width / 7;
195                //rrArcWidth = width / 7;
196                if (ad == SymbolID.Mobility_WheeledLimitedCrossCountry)
197                {
198                    //line
199                    PathUtilities.addLine(mobilityPath, x, bottomY, x + width, bottomY);
200
201                    //left circle
202                    PathUtilities.addEllipse(mobilityPath, x, bottomY + wheelOffset, wheelSize, wheelSize);
203
204                    //right circle
205                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
206
207                    //SVG
208                    svgMobilityGroup = "<line x1=\"" + x + "\" y1=\"" + bottomY + "\" x2=\"" + (x + width) + "\" y2=\"" + bottomY + "\" />\n";
209                    svgMobilityGroup += "<circle cx=\"" + (x + (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\"  ></circle>\n";
210                    svgMobilityGroup += "<circle cx=\"" + (x + width - (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\"  ></circle>\n";
211                }
212                else if (ad == SymbolID.Mobility_WheeledCrossCountry)
213                {
214                    //line
215                    PathUtilities.addLine(mobilityPath, x, bottomY, x + width, bottomY);
216
217                    //left circle
218                    PathUtilities.addEllipse(mobilityPath, x, bottomY + wheelOffset, wheelSize, wheelSize);
219
220                    //right circle
221                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
222
223                    //center wheel
224                    PathUtilities.addEllipse(mobilityPath, x + (width / 2) - (wheelSize / 2), bottomY + wheelOffset, wheelSize, wheelSize);
225
226                    //SVG
227                    svgMobilityGroup = "<line x1=\"" + x + "\" y1=\"" + bottomY + "\" x2=\"" + (x + width) + "\" y2=\"" + bottomY + "\" />\n";
228                    svgMobilityGroup += "<circle cx=\"" + (x + (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" stroke=\"black\" ></circle>\n";
229                    svgMobilityGroup += "<circle cx=\"" + (x + width - (wheelSize/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" stroke=\"black\" ></circle>\n";
230                    svgMobilityGroup += "<circle cx=\"" + (x + (width/2)) + "\" cy=\"" + (bottomY + wheelOffset + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" stroke=\"black\" ></circle>\n";
231                }
232                else if (ad == SymbolID.Mobility_Tracked)
233                {
234                    //round rectangle
235                    PathUtilities.addRoundedRect(mobilityPath, x, bottomY, width, rrHeight, rrHeight/2, rrHeight);
236                    svgMobilityGroup = "<rect width=\"" + width + "\" height=\"" + rrHeight + "\" x=\"" + x + "\" y=\"" + bottomY + "\" rx=\"" + rrHeight/2 + "\" ry=\"" + rrHeight + "\" />\n";
237
238                }
239                else if (ad == SymbolID.Mobility_Wheeled_Tracked)
240                {
241                    //round rectangle
242                    PathUtilities.addRoundedRect(mobilityPath, x, bottomY, width, rrHeight, wheelSize/2, rrHeight);
243                    svgMobilityGroup = "<rect width=\"" + width + "\" height=\"" + rrHeight + "\" x=\"" + x + "\" y=\"" + bottomY + "\" rx=\"" + rrHeight/2 + "\" ry=\"" + rrHeight + "\" />\n";
244
245                    //left circle
246                    PathUtilities.addEllipse(mobilityPath, x - wheelSize - wheelSize, bottomY, wheelSize, wheelSize);
247                    svgMobilityGroup += "<circle cx=\"" + (x - wheelSize - wheelSize/2) + "\" cy=\"" + (bottomY + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\"  stroke=\"black\" ></circle>\n";
248                }
249                else if (ad == SymbolID.Mobility_Towed)
250                {
251                    //line
252                    PathUtilities.addLine(mobilityPath, x + wheelSize, bottomY + (wheelSize / 2),
253                            x + width - wheelSize, bottomY + (wheelSize / 2));
254
255                    //left circle
256                    PathUtilities.addEllipse(mobilityPath, x, bottomY, wheelSize, wheelSize);
257
258                    //right circle
259                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY, wheelSize, wheelSize);
260
261                    //SVG
262                    svgMobilityGroup = "<line x1=\"" + (x + wheelSize) + "\" y1=\"" + (bottomY + (wheelSize/2) + "\" x2=\"" + (x + width - wheelSize) + "\" y2=\"" + (bottomY + (wheelSize/2))) + "\" />\n";
263                    svgMobilityGroup += "<circle cx=\"" + (x + (wheelSize/2)) + "\" cy=\"" + (bottomY + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" fill=\"none\" stroke=\"black\" ></circle>\n";
264                    svgMobilityGroup += "<circle cx=\"" + (x + width - (wheelSize/2)) + "\" cy=\"" + (bottomY + (wheelSize/2)) + "\" r=\"" + (wheelSize/2) + "\" fill=\"none\" stroke=\"black\" ></circle>\n";
265                }
266                else if (ad == SymbolID.Mobility_Rail)
267                {
268                    //line
269                    PathUtilities.addLine(mobilityPath, x, bottomY, x + width, bottomY);
270
271                    //left circle
272                    PathUtilities.addEllipse(mobilityPath, x + wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
273
274                    //left circle2
275                    PathUtilities.addEllipse(mobilityPath, x, bottomY + wheelOffset, wheelSize, wheelSize);
276
277                    //right circle
278                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
279
280                    //right circle2
281                    PathUtilities.addEllipse(mobilityPath, x + width - wheelSize - wheelSize, bottomY + wheelOffset, wheelSize, wheelSize);
282
283                    //SVG
284                    svgMobilityGroup = "<line x1=\"" + x + "\" y1=\"" + bottomY + "\" x2=\"" + (x + width) + "\" y2=\"" + bottomY + "\" />\n";
285
286                    svgMobilityGroup += "<circle cx=\"" + (x + rad) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
287                    svgMobilityGroup += "<circle cx=\"" + (x + rad + wheelSize) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
288
289                    svgMobilityGroup += "<circle cx=\"" + (x + width - rad) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
290                    svgMobilityGroup += "<circle cx=\"" + (x + width - rad - wheelSize) + "\" cy=\"" + (bottomY + wheelOffset + rad) + "\" r=\"" + rad + "\" ></circle>\n";
291
292                }
293                else if (ad == SymbolID.Mobility_OverSnow)
294                {
295                        float halfWidth = (rrArcWidth * 0.5f);
296                    mobilityPath.moveTo(x, bottomY);
297                    mobilityPath.lineTo(x + halfWidth, bottomY + halfWidth);
298                    mobilityPath.lineTo(x + width, bottomY + halfWidth);
299
300                    //SVG
301                    svgMobilityPath = new SVGPath();
302                    svgMobilityPath.moveTo(x,bottomY);
303                    svgMobilityPath.lineTo(x + halfWidth, bottomY + halfWidth);
304                    svgMobilityPath.lineTo(x + width, bottomY + halfWidth);
305
306                }
307                else if (ad == SymbolID.Mobility_Sled)
308                {
309                    mobilityPath.moveTo(x, bottomY);
310
311                    mobilityPath.cubicTo(x, bottomY, x - rrHeight, bottomY + rrHeight/2, x, bottomY + rrHeight);
312                    //mobilityPath.bezierCurveTo(x, bottomY, x-rrArcWidth, bottomY+3, x, bottomY+rrHeight);
313
314                    mobilityPath.lineTo(x + width, bottomY + rrHeight);
315
316                    mobilityPath.cubicTo(x + width, bottomY + rrHeight, x + width + rrHeight, bottomY + rrHeight/2, x + width, bottomY);
317                    //shapeMobility.curveTo(x + width, bottomY + rrHeight, x+ width + rrArcWidth, bottomY+3, x + width, bottomY);
318
319                    //SVG
320                    svgMobilityPath = new SVGPath();
321                    svgMobilityPath.moveTo(x, bottomY);
322                    svgMobilityPath.bezierCurveTo(x, bottomY, x - rrHeight, bottomY + rrHeight/2, x, bottomY + rrHeight);
323                    svgMobilityPath.lineTo(x + width, bottomY + rrHeight);
324                    svgMobilityPath.bezierCurveTo(x + width, bottomY + rrHeight, x + width + rrHeight, bottomY + rrHeight/2, x + width, bottomY);
325
326                }
327                else if (ad == SymbolID.Mobility_PackAnimals)
328                {
329                    centerX = Math.round(RectUtilities.getCenterX(symbolBounds));
330                    int angleWidth = rrHeight / 2;
331                    mobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
332                    mobilityPath.lineTo(centerX - angleWidth, bottomY);
333                    mobilityPath.lineTo(centerX - angleWidth*2, bottomY + rrHeight + 2);
334
335                    mobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
336                    mobilityPath.lineTo(centerX + angleWidth, bottomY);
337                    mobilityPath.lineTo(centerX + angleWidth*2, bottomY + rrHeight + 2);
338
339                    //SVG
340                    svgMobilityPath = new SVGPath();
341                    svgMobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
342                    svgMobilityPath.lineTo(centerX - angleWidth, bottomY);
343                    svgMobilityPath.lineTo(centerX - angleWidth*2, bottomY + rrHeight + 2);
344
345                    svgMobilityPath.moveTo(centerX, bottomY + rrHeight + 2);
346                    svgMobilityPath.lineTo(centerX + angleWidth, bottomY);
347                    svgMobilityPath.lineTo(centerX + angleWidth*2, bottomY + rrHeight + 2);
348                }
349                else if (ad == SymbolID.Mobility_Barge)
350                {
351                    centerX = Math.round(RectUtilities.getCenterX(symbolBounds));
352                    PathUtilities.addLine(mobilityPath, x + width, bottomY, x, bottomY);
353                    //var line = new SO.Line(x + width, bottomY,x, bottomY);
354
355                    float quarterX = (centerX - x) / 2;
356                    //var quarterY = (((bottomY + rrHeight) - bottomY)/2);
357
358                    mobilityPath.moveTo(x, bottomY);
359                    mobilityPath.cubicTo(x + quarterX, bottomY + rrHeight, centerX + quarterX, bottomY + rrHeight, x + width, bottomY);
360                    //shapes.push(new SO.BCurve(x, bottomY,x+quarterX, bottomY+rrHeight, centerX + quarterX, bottomY + rrHeight, x + width, bottomY));
361
362                    //SVG
363                    svgMobilityPath = new SVGPath();
364                    svgMobilityPath.moveTo(x + width, bottomY);
365                    svgMobilityPath.lineTo(x, bottomY);
366                    svgMobilityPath.moveTo(x, bottomY);
367                    svgMobilityPath.bezierCurveTo(x + quarterX, bottomY + rrHeight, centerX + quarterX, bottomY + rrHeight, x + width, bottomY);
368                }
369
370                else if (ad == SymbolID.Mobility_Amphibious)
371                {
372                    float incrementX = width / 7;
373                    middleY = (bottomY + (rrHeight / 2));
374
375                    x = Math.round(x + (incrementX / 2));
376                    float r = Math.round(incrementX / 2);
377
378                    //mobilityPath.arcTo(oval, sAngle, sAngle, moveTo);
379                    PathUtilities.arc(mobilityPath, x, middleY, r, 180, 180);
380                    PathUtilities.arc(mobilityPath, x + incrementX, middleY, r, 180, -180, false);
381                    PathUtilities.arc(mobilityPath, x + incrementX * 2, middleY, r, 180, 180, false);
382                    PathUtilities.arc(mobilityPath, x + incrementX * 3, middleY, r, 180, -180, false);
383                    PathUtilities.arc(mobilityPath, x + incrementX * 4, middleY, r, 180, 180, false);
384                    PathUtilities.arc(mobilityPath, x + incrementX * 5, middleY, r, 180, -180, false);
385                    PathUtilities.arc(mobilityPath, x + incrementX * 6, middleY, r, 180, 180, false);
386
387                    //SVG
388                    x = symbolBounds.left + 1;
389                    svgMobilityGroup = "<path d=\"M" + x + " " + middleY + " ";
390                    svgMobilityGroup += "C " + x + " " + bottomY + " " + (x + incrementX) + " " + bottomY + " " + (x + incrementX) + " " + middleY + " ";
391                    svgMobilityGroup += "C " + (x + incrementX) + " " + (bottomY + rrHeight) + " " + (x + (incrementX * 2)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX*2)) + " " + middleY + " ";
392                    svgMobilityGroup += "C " + (x + (incrementX*2))  + " " + bottomY + " " + (x + (incrementX*3)) + " " + bottomY + " " + (x + incrementX*3) + " " + middleY + " ";
393                    svgMobilityGroup += "C " + (x + (incrementX*3)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX * 4)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX*4)) + " " + middleY + " ";
394                    svgMobilityGroup += "C " + (x + (incrementX*4))  + " " + bottomY + " " + (x + (incrementX*5)) + " " + bottomY + " " + (x + incrementX*5) + " " + middleY + " ";
395                    svgMobilityGroup += "C " + (x + (incrementX*5)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX * 6)) + " " + (bottomY + rrHeight) + " " + (x + (incrementX*6)) + " " + middleY + " ";
396                    svgMobilityGroup += "C " + (x + (incrementX*6))  + " " + bottomY + " " + (x + (incrementX*7)) + " " + bottomY + " " + (x + incrementX*7) + " " + middleY + " ";
397                    svgMobilityGroup += "\"/>";
398
399
400                }
401
402                if(svgMobilityGroup != null)
403                    svgMobilityGroup = "<g stroke-width=\"" + strokeWidthBasedOnDPI + "\" fill=\"none\"" + " stroke=\"" + RendererUtilities.colorToHexString(lineColor,false) + "\"" + ">\n" + svgMobilityGroup + "</g>\n";
404
405            }
406            //Draw Towed Array Sonar
407            if ((ad == SymbolID.Mobility_ShortTowedArray || ad == SymbolID.Mobility_LongTowedArray) &&
408                    SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AG_AUX_EQUIP_INDICATOR)) {
409                int boxHeight = (int) ((rrHeight * 0.8f) + 0.5f);
410                bottomY = y + height + (boxHeight / 7);
411                mobilityPathFill = new Path();
412                offsetY = boxHeight / 7;//1;
413                centerX = Math.round(symbolBounds.left + (symbolBounds.right - symbolBounds.left) / 2);
414                int squareOffset = Math.round(boxHeight * 0.5f);
415                middleY = ((boxHeight / 2) + bottomY) + offsetY;//+1 for offset from symbol
416                if (ad == SymbolID.Mobility_ShortTowedArray) {
417                    //subtract 0.5 because lines 1 pixel thick get aliased into
418                    //a line two pixels wide.
419                    //line
420                    PathUtilities.addLine(mobilityPath, centerX - 1, bottomY - 1, centerX - 1, bottomY + offsetY + boxHeight + offsetY);
421                    //shapes.push(new SO.Line(centerX-1,bottomY-1,centerX-1, bottomY + rrHeight + 3));
422                    //shapeLines.append(new Line2D.Double(centerX,bottomY - 2,centerX, bottomY + rrHeight + 1), false);
423                    //line
424                    PathUtilities.addLine(mobilityPath, x, middleY, x + width, middleY);
425                    //shapes.push(new SO.Line(x,middleY,x + width, middleY));
426                    //shapeLines.append(new Line2D.Double(x,middleY,x + width, middleY), false);
427                    //square
428                    mobilityPathFill.addRect(PathUtilities.makeRectF(x - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
429                    //shapes.push(new SO.Rectangle(x-squareOffset, bottomY+offsetY, 5, 5));
430                    //shapeSquares.append(new Rectangle2D.Double(x-squareOffset, bottomY, 5, 5), false);
431                    //square
432                    mobilityPathFill.addRect(PathUtilities.makeRectF(Math.round(centerX - squareOffset), bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
433                    //shapes.push(new SO.Rectangle(Math.round(centerX-squareOffset), bottomY+offsetY, 5, 5));
434                    //shapeSquares.append(new Rectangle2D.Double(centerX-squareOffset, bottomY, 5, 5), false);
435                    //square
436                    mobilityPathFill.addRect(PathUtilities.makeRectF(x + width - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
437                    //shapes.push(new SO.Rectangle(x + width - squareOffset, bottomY+offsetY, 5, 5));
438                    //shapeSquares.append(new Rectangle2D.Double(x + width - squareOffset, bottomY, 5, 5), false);
439
440                    //SVG
441                    String svgColor = RendererUtilities.colorToHexString(lineColor,false);
442                    svgMobilityGroup = "<line x1=\"" + (centerX - 1) + "\" y1=\"" + (bottomY - 1) + "\" x2=\"" + (centerX - 1) + "\" y2=\"" + (bottomY + offsetY + boxHeight + offsetY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
443                    svgMobilityGroup += "<line x1=\"" + (x) + "\" y1=\"" + (middleY) + "\" x2=\"" + (x + width) + "\" y2=\"" + (middleY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
444                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
445                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (centerX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
446                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x + width - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
447
448
449                } else if (ad == SymbolID.Mobility_LongTowedArray) {
450                    int leftX = x + (centerX - x) / 2,
451                            rightX = centerX + (x + width - centerX) / 2;
452
453                    //line vertical left
454                    PathUtilities.addLine(mobilityPath, leftX, bottomY - 1, leftX, bottomY + offsetY + boxHeight + offsetY);
455                    //shapes.push(new SO.Line(leftX,bottomY - 1,leftX, bottomY + rrHeight + 3));
456                    //shapeLines.append(new Line2D.Double(leftX,bottomY - 2,leftX, bottomY + rrHeight + 1), false);
457                    //line vertical right
458                    PathUtilities.addLine(mobilityPath, rightX, bottomY - 1, rightX, bottomY + offsetY + boxHeight + offsetY);
459                    //shapes.push(new SO.Line(rightX,bottomY - 1,rightX, bottomY + rrHeight + 3));
460                    //shapeLines.append(new Line2D.Double(rightX,bottomY - 2,rightX, bottomY + rrHeight + 1), false);
461                    //line horizontal
462                    PathUtilities.addLine(mobilityPath, x, middleY, x + width, middleY);
463                    //shapes.push(new SO.Line(x,middleY,x + width, middleY));
464                    //shapeLines.append(new Line2D.Double(x,middleY,x + width, middleY), false);
465                    //square left
466                    mobilityPathFill.addRect(PathUtilities.makeRectF(x - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
467                    //shapes.push(new SO.Rectangle(x-squareOffset, bottomY+offsetY, 5, 5));
468                    //shapeSquares.append(new Rectangle2D.Double(x-squareOffset, bottomY, 5, 5), false);
469                    //square middle
470                    mobilityPathFill.addRect(PathUtilities.makeRectF(centerX - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
471                    //shapes.push(new SO.Rectangle(centerX-squareOffset, bottomY+offsetY, 5, 5));
472                    //shapeSquares.append(new Rectangle2D.Double(centerX-squareOffset, bottomY, 5, 5), false);
473                    //square right
474                    mobilityPathFill.addRect(PathUtilities.makeRectF(x + width - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
475                    //shapes.push(new SO.Rectangle(x + width - squareOffset, bottomY+offsetY, 5, 5));
476                    //shapeSquares.append(new Rectangle2D.Double(x + width - squareOffset, bottomY, 5, 5), false);
477                    //square middle left
478                    mobilityPathFill.addRect(PathUtilities.makeRectF(leftX - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
479                    //shapes.push(new SO.Rectangle(leftX - squareOffset, bottomY+offsetY, 5, 5));
480                    //shapeSquares.append(new Rectangle2D.Double(leftX - squareOffset, bottomY, 5, 5), false);
481                    //square middle right
482                    mobilityPathFill.addRect(PathUtilities.makeRectF(rightX - squareOffset, bottomY + offsetY, boxHeight, boxHeight), Direction.CW);
483                    //shapes.push(new SO.Rectangle(rightX - squareOffset, bottomY+offsetY, 5, 5));
484                    //shapeSquares.append(new Rectangle2D.Double(rightX - squareOffset, bottomY, 5, 5), false);
485
486                    //SVG
487                    String svgColor = RendererUtilities.colorToHexString(lineColor,false);
488                    svgMobilityGroup = "<line x1=\"" + (leftX) + "\" y1=\"" + (bottomY - 1) + "\" x2=\"" + (leftX) + "\" y2=\"" + (bottomY + offsetY + boxHeight + offsetY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
489                    svgMobilityGroup += "<line x1=\"" + (rightX) + "\" y1=\"" + (bottomY - 1) + "\" x2=\"" + (rightX) + "\" y2=\"" + (bottomY + offsetY + boxHeight + offsetY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
490                    svgMobilityGroup += "<line x1=\"" + (x) + "\" y1=\"" + (middleY) + "\" x2=\"" + (x + width) + "\" y2=\"" + (middleY) + "\" stroke=\"" + svgColor + "\" stroke-width=\"" + strokeWidthBasedOnDPI + "\" />\n";
491                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
492                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (centerX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
493                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (x + width - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
494                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (leftX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
495                    svgMobilityGroup += "<rect width=\"" + (boxHeight) + "\" height=\"" + (boxHeight) + "\" x=\"" + (rightX - squareOffset) + "\" y=\"" + (bottomY + offsetY) + "\" fill=\"" + svgColor + "\" stroke-width=\"0\"/>\n";
496
497                }
498                if(svgMobilityGroup != null)
499                    svgMobilityGroup = "<g stroke-width=\"" + strokeWidthBasedOnDPI + "\" fill=\"" + RendererUtilities.colorToHexString(lineColor,false) + "\"" + " stroke=\"" + RendererUtilities.colorToHexString(lineColor,false) + "\"" +  ">\n" + svgMobilityGroup + "\n</g>";
500            }
501
502            //get mobility bounds
503            if (mobilityPath != null)
504            {
505
506                //build mobility bounds
507                mobilityBounds = new RectF();
508                mobilityPath.computeBounds(mobilityBounds, true);
509
510                RectF mobilityFillBounds = new RectF();
511                if (mobilityPathFill != null)
512                {
513                    mobilityPathFill.computeBounds(mobilityFillBounds, true);
514                    mobilityBounds.union(mobilityFillBounds);
515                }
516
517                //grow by one because we use a line thickness of 2.
518                RectUtilities.grow(mobilityBounds,Math.round(strokeWidthBasedOnDPI/2));
519                //mobilityBounds.set(mobilityBounds.left - 1, mobilityBounds.top - 1, mobilityBounds.right + 1, mobilityBounds.bottom + 1);
520                imageBounds.union(RectUtilities.makeRectFromRectF(mobilityBounds));
521            }
522        }
523        // </editor-fold>
524
525        // <editor-fold defaultstate="collapsed" desc="Leadership Indicator Modifier">
526        RectF liBounds = null;
527        Path liPath = null;
528        PointF liTop = null;
529        PointF liLeft = null;
530        PointF liRight = null;
531        if(ad == SymbolID.Leadership_Individual && ss == SymbolID.SymbolSet_DismountedIndividuals &&
532                (SymbolID.getFrameShape(symbolID)==SymbolID.FrameShape_DismountedIndividuals ||
533                        SymbolID.getFrameShape(symbolID)==SymbolID.FrameShape_Unknown))
534        {
535            liPath = new Path();
536
537            int si = SymbolID.getStandardIdentity(symbolID);
538            int af = SymbolID.getAffiliation(symbolID);
539            int c = SymbolID.getContext(symbolID);
540            //int fs = SymbolID.getFrameShape(symbolID);
541            double centerOffset = 0;
542            double sideOffset = 0;
543            double left = symbolBounds.left;
544            double right = symbolBounds.left + symbolBounds.width();
545
546            if(af == SymbolID.StandardIdentity_Affiliation_Unknown || af == SymbolID.StandardIdentity_Affiliation_Pending)
547            {
548                centerOffset = (symbolBounds.height()*0.1012528735632184);
549                sideOffset = (right - left)*0.3583513488109785;
550                //left = symbolBounds.getCenterX() - ((symbolBounds.getWidth() / 2) * 0.66420458);
551                //right = symbolBounds.getCenterX() + ((symbolBounds.getWidth() / 2) * 0.66420458);
552            }
553            if(af == SymbolID.StandardIdentity_Affiliation_Neutral)
554            {
555                centerOffset = (symbolBounds.height()*0.25378787878787878);
556                sideOffset = (right - left)*0.2051402812352822;
557            }
558            if(SymbolUtilities.isReality(symbolID) || SymbolUtilities.isSimulation(symbolID))
559            {
560                if(af==SymbolID.StandardIdentity_Affiliation_Friend || af==SymbolID.StandardIdentity_Affiliation_AssumedFriend)
561                {//hexagon friend/assumed friend
562                    centerOffset = (symbolBounds.height()*0.08);
563                    sideOffset = (right - left)*0.282714524168219;//(symbolBounds.getHeight()*0.29);
564                }
565                else if(af==SymbolID.StandardIdentity_Affiliation_Hostile_Faker || af==SymbolID.StandardIdentity_Affiliation_Suspect_Joker)
566                {//diamond hostile/suspect
567
568                    left = symbolBounds.centerX() - ((symbolBounds.width() / 2) * 1.0653694149);//1.07);//1.0653694149);
569                    right = symbolBounds.centerX() + ((symbolBounds.width() / 2) * 1.0653694149);//1.07);//1.0653694149);
570
571                    centerOffset = (symbolBounds.height()*0.08);//0.0751139601139601
572                    sideOffset = (right - left)*0.4923255424955992;
573                }
574            }
575            else//Exercise
576            {
577                //hexagon
578                if(af!=SymbolID.StandardIdentity_Affiliation_Unknown ||
579                        af==SymbolID.StandardIdentity_Affiliation_Neutral)
580                {
581                    centerOffset = (symbolBounds.height()*0.08);
582                    sideOffset = (right - left)*0.282714524168219;
583                }
584            }
585
586            //create leadership indicator /\
587            liTop = new PointF(symbolBounds.centerX(), (float)(symbolBounds.top - centerOffset));
588            liLeft = new PointF((float)left, (float)(liTop.y + sideOffset));
589            liRight = new PointF((float)right, (float)(liTop.y + sideOffset));
590
591
592            liPath.moveTo(liTop.x, liTop.y);
593            liPath.lineTo(liLeft.x, liLeft.y);
594            liPath.moveTo(liTop.x, liTop.y);
595            liPath.lineTo(liRight.x, liRight.y);//*/
596
597
598            liBounds = new RectF(liLeft.x, liTop.y, liRight.x - liLeft.x, liLeft.y - liTop.y);
599
600            RectUtilities.grow(liBounds,2);
601
602            imageBounds.union(RectUtilities.makeRectFromRectF(liBounds));
603        }
604
605        // </editor-fold>
606
607        // <editor-fold defaultstate="collapsed" desc="Build Echelon">
608        //Draw Echelon
609        int intEchelon = SymbolID.getAmplifierDescriptor(symbolID);
610        String strEchelon = SymbolUtilities.getEchelonText(intEchelon);
611
612        if (strEchelon != null
613                && SymbolUtilities.hasModifier(symbolID, Modifiers.B_ECHELON))
614        {
615
616            int echelonOffset = 2,
617                    outlineOffset = RS.getTextOutlineWidth();
618
619            tiEchelon = new TextInfo(strEchelon, 0, 0, modifierFont, modifierFontName);
620            echelonBounds = tiEchelon.getTextBounds();
621
622            int y = Math.round(symbolBounds.left - echelonOffset);
623            int x = Math.round(symbolBounds.left + (symbolBounds.width() / 2)
624                    - (echelonBounds.width() / 2));
625            tiEchelon.setLocation(x, y);
626
627            //There will never be lowercase characters in an echelon so trim that fat.
628            //Remove the descent from the bounding box.
629            tiEchelon.getTextOutlineBounds();//.shiftBR(0,Math.round(-(echelonBounds.height()*0.3)));
630
631            //make echelon bounds a little more spacious for things like nearby labels and Task Force.
632            RectUtilities.grow(echelonBounds, outlineOffset);
633            //tiEchelon.getTextOutlineBounds();
634//                RectUtilities.shift(echelonBounds, x, -outlineOffset);
635            //echelonBounds.shift(0,-outlineOffset);// - Math.round(echelonOffset/2));
636            tiEchelon.setLocation(x, y - outlineOffset);
637
638            imageBounds.union(echelonBounds);
639
640        }
641        // </editor-fold>
642
643        // <editor-fold defaultstate="collapsed" desc="Build Task Force">
644        Rect tfBounds = null;
645        Rect tfRectangle = null;
646        if (SymbolUtilities.isTaskForce(symbolID) && SymbolUtilities.hasModifier(symbolID, Modifiers.D_TASK_FORCE_INDICATOR))
647        {
648
649            int height = Math.round(symbolBounds.height() / 4.0f);
650            int width = Math.round(symbolBounds.width() / 3.0f);
651
652            if(!SymbolUtilities.hasRectangleFrame(symbolID))
653            {
654                height = (int)Math.round(symbolBounds.height() / 6.0f);
655            }
656
657            tfRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
658                    (int) symbolBounds.top - height,
659                    width,
660                    height);
661
662            tfBounds = RectUtilities.makeRect(tfRectangle.left + -1,
663                    tfRectangle.top - 1,
664                    tfRectangle.width() + 2,
665                    tfRectangle.height() + 2);
666
667            if (echelonBounds != null)
668            {
669                /*tfRectangle = new Rect(echelonBounds.left,
670                        echelonBounds.top,// + outlineOffset,
671                        echelonBounds.right,
672                        symbolBounds.top-1);
673                tfBounds = new Rect(tfRectangle);*/
674
675                int tfx = tfRectangle.left;
676                int tfw = tfRectangle.width();
677                int tfy = tfRectangle.top;
678                int tfh = tfRectangle.height();
679
680                if(echelonBounds.width() > tfRectangle.width())
681                {
682                    tfx = symbolBounds.left + symbolBounds.width()/2 - (echelonBounds.width()/2) - 1;
683                    tfw = echelonBounds.width()+2;
684                }
685                if(echelonBounds.height() > tfRectangle.height())
686                {
687                    tfy = echelonBounds.top-1;
688                    tfh = echelonBounds.height()+2;
689
690                }
691                tfRectangle = RectUtilities.makeRect((int)tfx,
692                        tfy,// + outlineOffset,
693                        tfw,
694                        tfh);
695
696
697                tfBounds = RectUtilities.makeRect((tfRectangle.left - 1),
698                        (tfRectangle.top - 1),
699                        (tfRectangle.width() + 2),
700                        (tfRectangle.height() + 2));
701            }
702
703            imageBounds.union(tfBounds);
704        }
705        // </editor-fold>
706
707        // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
708        Rect fdiBounds = null;
709        Point fdiTop = null;
710        Point fdiLeft = null;
711        Point fdiRight = null;
712
713
714        if (SymbolUtilities.hasFDI(symbolID)
715                && SymbolUtilities.canSymbolHaveModifier(symbolID, Modifiers.AB_FEINT_DUMMY_INDICATOR))
716        {
717            //create feint indicator /\
718            fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
719            fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
720            fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
721
722
723            fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
724            fdiBounds.union(fdiTop.x, fdiTop.y);
725            fdiBounds.union(fdiRight.x, fdiRight.y);
726
727            float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
728            RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
729
730            if (echelonBounds != null)
731            {
732                int shiftY = Math.round(symbolBounds.top - echelonBounds.height() - 2);
733                fdiLeft.offset(0, shiftY);
734                fdiTop.offset(0, shiftY);
735                fdiRight.offset(0, shiftY);
736                fdiBounds.offset(0, shiftY);
737            }
738
739            imageBounds.union(fdiBounds);
740
741        }
742        // </editor-fold>
743
744        //Using SVG files for installation indicator now
745        // <editor-fold defaultstate="collapsed" desc="Build Installation">
746        /*//Using SVG files for the installation indicator
747        Rect instRectangle = null;
748        Rect instBounds = null;
749        if (SymbolUtilities.hasInstallationModifier(symbolID)
750                && SymbolUtilitiesD.canSymbolHaveModifier(symbolID, Modifiers.AC_INSTALLATION))
751        {//the actual installation symbols have the modifier
752            //built in.  everything else, we have to draw it.
753            //
754            ////get indicator dimensions////////////////////////////////
755            int width;
756            int height;
757            char affiliation = SymbolUtilities.getAffiliation(symbolID);
758
759            if (affiliation == 'F'
760                    || affiliation == 'A'
761                    || affiliation == 'D'
762                    || affiliation == 'M'
763                    || affiliation == 'J'
764                    || affiliation == 'K')
765            {
766                //4th height, 3rd width
767                height = Math.round(symbolBounds.height() / 4);
768                width = Math.round(symbolBounds.width() / 3);
769            }
770            else if (affiliation == 'H' || affiliation == 'S')//hostile,suspect
771            {
772                //6th height, 3rd width
773                height = Math.round(symbolBounds.height() / 6);
774                width = Math.round(symbolBounds.width() / 3);
775            }
776            else if (affiliation == 'N' || affiliation == 'L')//neutral,exercise neutral
777            {
778                //6th height, 3rd width
779                height = Math.round(symbolBounds.height() / 6);
780                width = Math.round(symbolBounds.width() / 3);
781            }
782            else if (affiliation == 'P'
783                    || affiliation == 'U'
784                    || affiliation == 'G'
785                    || affiliation == 'W')
786            {
787                //6th height, 3rd width
788                height = Math.round(symbolBounds.height() / 6);
789                width = Math.round(symbolBounds.width() / 3);
790            }
791            else
792            {
793                //6th height, 3rd width
794                height = Math.round(symbolBounds.height() / 6);
795                width = Math.round(symbolBounds.width() / 3);
796            }
797
798//                    if(width * 3 < symbolBounds.width())
799//                        width++;
800            //set installation position/////////////////////////////////
801            //set position of indicator
802            if (affiliation == 'F'
803                    || affiliation == 'A'
804                    || affiliation == 'D'
805                    || affiliation == 'M'
806                    || affiliation == 'J'
807                    || affiliation == 'K'
808                    || affiliation == 'N'
809                    || affiliation == 'L')
810            {
811                instRectangle = RectUtilities.makeRect((int) (symbolBounds.left + width),
812                        (int) (symbolBounds.top - height),
813                        width,
814                        height);
815            }
816            else if (affiliation == 'H' || affiliation == 'S')//hostile,suspect
817            {
818                instRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
819                        Math.round((int) symbolBounds.top - (height * 0.15f)),
820                        width,
821                        height);
822            }
823            else if (affiliation == 'P'
824                    || affiliation == 'U'
825                    || affiliation == 'G'
826                    || affiliation == 'W')
827            {
828                instRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
829                        Math.round(symbolBounds.top - (height * 0.3f)),
830                        width,
831                        height);
832            }
833            else
834            {
835                instRectangle = RectUtilities.makeRect((int) symbolBounds.left + width,
836                        Math.round(symbolBounds.top - (height * 0.3f)),
837                        width,
838                        height);
839            }
840
841            //generate installation bounds//////////////////////////////
842            instBounds = new Rect(instRectangle.left + -1,
843                    instRectangle.top - 1,
844                    instRectangle.width() + 2,
845                    instRectangle.height() + 2);
846
847            imageBounds.union(instBounds);
848
849        }//*/
850        // </editor-fold>
851
852        // <editor-fold defaultstate="collapsed" desc="Build Engagement Bar (AO)">
853        //A:BBB-CC
854        String strAO = null;
855        Rect ebRectangle = null;
856        Rect ebBounds = null;
857        Rect ebTextBounds = null;
858        TextInfo ebText = null;
859
860        int ebTop = 0;
861        int ebLeft = 0;
862        int ebWidth = 0;
863        int ebHeight = 0;
864        Color ebColor = null;//SymbolUtilities.getFillColorOfAffiliation(symbolID);
865
866        if(attributes.containsKey(MilStdAttributes.EngagementBarColor))
867            ebColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.EngagementBarColor));
868        else
869            ebColor = fillColor;
870
871        if(SymbolUtilities.hasModifier(symbolID, Modifiers.AO_ENGAGEMENT_BAR) &&
872                modifiers.containsKey(Modifiers.AO_ENGAGEMENT_BAR))
873            strAO = modifiers.get(Modifiers.AO_ENGAGEMENT_BAR);
874        if(strAO != null)
875        {
876            ebText = new TextInfo(strAO, 0, 0, modifierFont, modifierFontName);
877            ebTextBounds = ebText.getTextBounds();
878            ebHeight = ebTextBounds.height() + 4;
879
880            int barOffset = Math.max(RendererSettings.getInstance().getDeviceDPI()/32, 4);
881
882            if(fdiBounds != null)//set bar above FDI if present
883            {
884                ebTop = fdiBounds.top - ebHeight - barOffset;
885            }
886            else if(tfBounds != null)//set bar above TF if present
887            {
888                ebTop = tfBounds.top - ebHeight - barOffset;
889            }
890            else if(echelonBounds != null)//set bar above echelon if present
891            {
892                ebTop = echelonBounds.top - ebHeight - barOffset;
893            }
894            else if((isCOnTop(symbolID) && modifiers.containsKey(Modifiers.C_QUANTITY)) ||
895                        SymbolID.getContext(symbolID) == SymbolID.StandardIdentity_Context_Exercise ||
896                        SymbolID.getContext(symbolID) == SymbolID.StandardIdentity_Context_Simulation)
897            {
898                ebTop = symbolBounds.top - (int)(ebHeight*2.5f);
899            }
900            else if(ss == SymbolID.SymbolSet_LandInstallation)
901            {
902                ebTop = symbolBounds.top - ebHeight - (barOffset * 2);
903            }
904            else//position above symbol
905            {
906                ebTop = symbolBounds.top - ebHeight - barOffset;
907            }
908
909            //if text wider than symbol, extend the bar.
910            if(ebTextBounds.width() > symbolBounds.width())
911            {
912                ebWidth = ebTextBounds.width() + 4;
913                ebLeft = symbolCenter.x - (ebWidth/2);
914            }
915            else
916            {
917                ebLeft = symbolBounds.left + (int)Math.ceil(strokeWidthBasedOnDPI/2f);//1;//leave room for outline
918                ebWidth = symbolBounds.width() - (int)Math.ceil(strokeWidthBasedOnDPI);//2;//leave room for outline
919            }
920
921            //set text location within the bar
922            ebText.setLocation(symbolCenter.x - (ebTextBounds.width()/2), ebTop + ebHeight - ((ebHeight - ebTextBounds.height()) / 2));
923
924            ebRectangle = RectUtilities.makeRect(ebLeft,ebTop,ebWidth,ebHeight);
925            ebBounds = new Rect(ebRectangle);
926            RectUtilities.grow(ebBounds,(int)Math.ceil(strokeWidthBasedOnDPI/2f));
927
928            imageBounds.union(ebBounds);
929        }
930
931
932        // </editor-fold>
933
934        // <editor-fold defaultstate="collapsed" desc="Build Affiliation Modifier">
935        String affiliationModifier = null;
936        if (RS.getDrawAffiliationModifierAsLabel() == false)
937        {
938            affiliationModifier = SymbolUtilities.getStandardIdentityModifier(symbolID);
939        }
940        if (affiliationModifier != null)
941        {
942
943            int amOffset = 2;
944            int outlineOffset = RS.getTextOutlineWidth();
945
946            tiAM = new TextInfo(affiliationModifier, 0, 0, modifierFont, modifierFontName);
947            amBounds = tiAM.getTextBounds();
948
949            int x, y;
950
951            if (echelonBounds != null
952                    && ((echelonBounds.left + echelonBounds.width() > symbolBounds.left + symbolBounds.width())))
953            {
954                y = Math.round(symbolBounds.top - amOffset);
955                x = echelonBounds.left + echelonBounds.width();
956            }
957            else
958            {
959                y = Math.round(symbolBounds.top - amOffset);
960                x = Math.round(symbolBounds.left + symbolBounds.width());
961            }
962            tiAM.setLocation(x, y);
963
964            //adjust for outline.
965            RectUtilities.grow(amBounds, outlineOffset);
966            RectUtilities.shift(amBounds, 0, -outlineOffset);
967            tiAM.setLocation(x, y - outlineOffset);
968
969            imageBounds.union(amBounds);
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        if(mods != null) {
3124            for (int i = 0; i < mods.size(); i++) {
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
3142        // </editor-fold>
3143
3144        //Shift Points and Draw
3145        newsdi = shiftUnitPointsAndDraw(tiArray,sdi,attributes, modifierFont);
3146
3147        // <editor-fold defaultstate="collapsed" desc="Cleanup">
3148        tiArray = null;
3149        tiTemp = null;
3150        //tempShape = null;
3151        //ctx = null;
3152        //buffer = null;
3153        // </editor-fold>
3154
3155        return newsdi;
3156    }
3157
3158    public static SymbolDimensionInfo ProcessTGSPWithSpecialModifierLayout(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes, Color lineColor)
3159    {
3160        Paint modifierFont = getFont(attributes);
3161        float[] hd = getFontHeightandDescent(modifierFont);
3162        float modifierFontHeight = hd[0];
3163        float modifierFontDescent = hd[1];
3164
3165        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
3166        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
3167        {
3168            String temp = attributes.get(MilStdAttributes.FontFamily);
3169            if(temp != null && !temp.isEmpty())
3170                modifierFontName = temp;
3171        }
3172
3173        ImageInfo ii = null;
3174        SVGSymbolInfo ssi = null;
3175
3176        int bufferXL = 6;
3177        int bufferXR = 4;
3178        int bufferY = 2;
3179        int bufferText = 2;
3180        int centerOffset = 1; //getCenterX/Y function seems to go over by a pixel
3181        int x = 0;
3182        int y = 0;
3183        int x2 = 0;
3184        int y2 = 0;
3185
3186        int outlineOffset = RS.getTextOutlineWidth();
3187        int labelHeight = 0;
3188        int labelWidth = 0;
3189        int alpha = -1;
3190        SymbolDimensionInfo newsdi = null;
3191        Color textColor = lineColor;
3192        Color textBackgroundColor = null;
3193        int ss = SymbolID.getSymbolSet(symbolID);
3194        int ec = SymbolID.getEntityCode(symbolID);
3195        int e = SymbolID.getEntity(symbolID);
3196        int et = SymbolID.getEntityType(symbolID);
3197        int est = SymbolID.getEntitySubtype(symbolID);
3198
3199        //Feint Dummy Indicator variables
3200        Rect fdiBounds = null;
3201        Point fdiTop = null;
3202        Point fdiLeft = null;
3203        Point fdiRight = null;
3204
3205        ArrayList<TextInfo> arrMods = new ArrayList<TextInfo>();
3206        boolean duplicate = false;
3207
3208        Rect bounds = new Rect(sdi.getSymbolBounds());
3209        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
3210        Point centerPoint = new Point(sdi.getCenterPoint());
3211        Rect imageBounds = new Rect(sdi.getImageBounds());
3212
3213        if (attributes.containsKey(MilStdAttributes.Alpha))
3214        {
3215            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
3216            textColor.setAlpha(alpha);
3217        }
3218
3219        centerPoint = new Point(Math.round(sdi.getCenterPoint().x), Math.round(sdi.getCenterPoint().y));
3220
3221        boolean byLabelHeight = false;
3222        labelHeight = (int) (modifierFontHeight + 0.5f);
3223
3224        int maxHeight = (symbolBounds.height());
3225        if ((labelHeight * 3) > maxHeight)
3226        {
3227            byLabelHeight = true;
3228        }
3229
3230        int descent = (int) (modifierFontDescent + 0.5f);
3231        int yForY = -1;
3232
3233        Rect labelBounds1 = null;//text.getPixelBounds(null, 0, 0);
3234        Rect labelBounds2 = null;
3235        String strText = "";
3236        String strText1 = "";
3237        String strText2 = "";
3238        TextInfo text1 = null;
3239        TextInfo text2 = null;
3240
3241
3242        if (outlineOffset > 2)
3243        {
3244            outlineOffset = ((outlineOffset - 1) / 2);
3245        }
3246        else
3247        {
3248            outlineOffset = 0;
3249        }
3250
3251
3252        // <editor-fold defaultstate="collapsed" desc="Process Special Modifiers">
3253        TextInfo ti = null;
3254        if (SymbolUtilities.isCBRNEvent(symbolID))//chemical
3255        {
3256            if ((labelHeight * 3) > bounds.height())
3257            {
3258                byLabelHeight = true;
3259            }
3260        }
3261
3262        if(ss == SymbolID.SymbolSet_ControlMeasure) {
3263            if (ec == 130500 //contact point
3264                    || ec == 130700) //decision point
3265            {
3266                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3267                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3268                    if (strText != null) {
3269                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3270                        labelWidth = Math.round(ti.getTextBounds().width());
3271                        //One modifier symbols and modifier goes in center
3272                        x = bounds.left + (int) (bounds.width() * 0.5f);
3273                        x = x - (int) (labelWidth * 0.5f);
3274                        y = bounds.top + (int) (bounds.height() * 0.4f);
3275                        y = y + (int) (labelHeight * 0.5f);
3276
3277                        ti.setLocation(Math.round(x), Math.round(y));
3278                        arrMods.add(ti);
3279                    }
3280                }
3281            } else if (ec == 212800)//harbor
3282            {
3283                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3284                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3285                    if (strText != null) {
3286                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3287                        labelWidth = Math.round(ti.getTextBounds().width());
3288                        //One modifier symbols and modifier goes in center
3289                        x = bounds.left + (int) (bounds.width() * 0.5f);
3290                        x = x - (int) (labelWidth * 0.5f);
3291                        y = bounds.top + (int) (bounds.height() * 0.5f);
3292                        y = y + (int) (labelHeight * 0.5f);
3293
3294                        ti.setLocation(Math.round(x), Math.round(y));
3295                        arrMods.add(ti);
3296                    }
3297                }
3298            } else if (ec == 131300)//point of interest
3299            {
3300                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3301                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3302                    if (strText != null) {
3303                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3304                        labelWidth = Math.round(ti.getTextBounds().width());
3305                        //One modifier symbols, top third & center
3306                        x = bounds.left + (int) (bounds.width() * 0.5f);
3307                        x = x - (int) (labelWidth * 0.5f);
3308                        y = bounds.top + (int) (bounds.height() * 0.25f);
3309                        y = y + (int) (labelHeight * 0.5f);
3310
3311                        ti.setLocation(Math.round(x), Math.round(y));
3312                        arrMods.add(ti);
3313                    }
3314                }
3315            } else if (ec == 131800//waypoint
3316                    || ec == 240900)//fire support station
3317            {
3318                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3319                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3320                    if (strText != null) {
3321                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3322
3323                        //One modifier symbols and modifier goes right of center
3324                        if (ec == 131800)
3325                            x = bounds.left + (int) (bounds.width() * 0.75f);
3326                        else
3327                            x = bounds.left + (bounds.width());
3328                        y = bounds.top + (int) (bounds.height() * 0.5f);
3329                        y = y + (int) ((labelHeight - descent) * 0.5f);
3330
3331                        ti.setLocation(Math.round(x), Math.round(y));
3332                        arrMods.add(ti);
3333                    }
3334                }
3335            }
3336            else if (ec == 131900)//Airfield (AEGIS Only)
3337            {
3338                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3339                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3340                    if (strText != null) {
3341                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3342
3343                        //One modifier symbols and modifier goes right of symbol
3344
3345                        x = bounds.left + (bounds.width() + bufferXR);
3346
3347                        y = bounds.top + (int) (bounds.height() * 0.5f);
3348                        y = y + (int) ((labelHeight - descent) * 0.5f);
3349
3350                        ti.setLocation(Math.round(x), Math.round(y));
3351                        arrMods.add(ti);
3352                    }
3353                }
3354            }
3355            else if (ec == 180100 //Air Control point
3356                    || ec == 180200) //Communications Check point
3357            {
3358                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3359                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3360                    if (strText != null) {
3361                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3362                        labelWidth = ti.getTextBounds().width();
3363                        //One modifier symbols and modifier goes just below of center
3364                        x = bounds.left + (int) (bounds.width() * 0.5);
3365                        x = x - (int) (labelWidth * 0.5);
3366                        y = bounds.top + (int) (bounds.height() * 0.5f);
3367                        y = y + (int) (((bounds.height() * 0.5f) - labelHeight) / 2) + labelHeight - descent;
3368
3369                        ti.setLocation(Math.round(x), Math.round(y));
3370                        arrMods.add(ti);
3371                    }
3372                }
3373            } else if (ec == 160300 || //T (target reference point)
3374                    ec == 132000 || //T (Target Handover)
3375                    ec == 240601 || //ap,ap1,x,h (Point/Single Target)
3376                    ec == 240602) //ap (nuclear target)
3377            { //Targets with special modifier positions
3378                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)
3379                        && ec == 240601)//H //point single target
3380                {
3381                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3382                    if (strText != null) {
3383                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3384
3385                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3386                        y = bounds.top + (int) (bounds.height() * 0.75f);
3387                        y = y + (int) (labelHeight * 0.5f);
3388
3389                        ti.setLocation(Math.round(x), Math.round(y));
3390                        arrMods.add(ti);
3391                    }
3392                }
3393                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)
3394                        && ec == 240601)//X point or single target
3395                {
3396                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3397                    if (strText != null) {
3398                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3399                        labelWidth = Math.round(ti.getTextBounds().width());
3400                        x = RectUtilities.getCenterX(bounds) - (int) (bounds.width() * 0.15f);
3401                        x = x - (labelWidth);
3402                        y = bounds.top + (int) (bounds.height() * 0.75f);
3403                        y = y + (int) (labelHeight * 0.5f);
3404
3405                        ti.setLocation(Math.round(x), Math.round(y));
3406                        arrMods.add(ti);
3407                    }
3408                }
3409                strText = null;
3410                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) && (ec == 160300 || ec == 132000)) {
3411                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3412                    if (strText != null) {
3413                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3414
3415                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3416                        y = bounds.top + (int) (bounds.height() * 0.25f);
3417                        y = y + (int) (labelHeight * 0.5f);
3418
3419                        ti.setLocation(Math.round(x), Math.round(y));
3420                        arrMods.add(ti);
3421                    }
3422                }
3423                if (ec == 240601 || ec == 240602)
3424                {
3425                    if (modifiers.containsKey(Modifiers.AP_TARGET_NUMBER)) {
3426                        strText = modifiers.get(Modifiers.AP_TARGET_NUMBER);
3427                    }
3428                    if (ec == 240601 && modifiers.containsKey(Modifiers.AP1_TARGET_NUMBER_EXTENSION)) {
3429                        if (strText != null)
3430                            strText = strText + "  " + modifiers.get(Modifiers.AP1_TARGET_NUMBER_EXTENSION);
3431                        else
3432                            strText = modifiers.get(Modifiers.AP1_TARGET_NUMBER_EXTENSION);
3433                    }
3434                    if (strText != null) {
3435                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3436
3437                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3438                        y = bounds.top + (int) (bounds.height() * 0.25f);
3439                        y = y + (int) (labelHeight * 0.5f);
3440
3441                        ti.setLocation(Math.round(x), Math.round(y));
3442                        arrMods.add(ti);
3443                    }
3444                }
3445            }
3446            else if (ec == 132100)//Key Terrain
3447            {
3448                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3449                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3450                    if (strText != null) {
3451                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3452
3453                        //One modifier symbols and modifier goes right of symbol
3454
3455                        x = bounds.left + (int)(bounds.width() * 0.5) + bufferXL;
3456
3457                        y = bounds.top + (int) (bounds.height() * 0.5f);
3458                        y = y + (int) ((labelHeight - descent) * 0.5f);
3459
3460                        ti.setLocation(Math.round(x), Math.round(y));
3461                        arrMods.add(ti);
3462                    }
3463                }
3464            }
3465            else if(ec == 182600)//Isolated Personnel Location
3466            {
3467                if (modifiers.containsKey(Modifiers.C_QUANTITY)) {
3468                    strText = modifiers.get(Modifiers.C_QUANTITY);
3469                    if (strText != null) {
3470                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3471                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3472                        //subset of NBC, just nuclear
3473                        x = (int)(bounds.left + (bounds.width() * 0.5));
3474                        x = x - (int) (labelWidth * 0.5);
3475                        y = (int)bounds.top - descent;
3476                        ti.setLocation(Math.round(x), Math.round(y));
3477                        arrMods.add(ti);
3478                    }
3479                }
3480                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3481                    strText = modifiers.get(Modifiers.W_DTG_1);
3482                    if (strText != null) {
3483                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3484                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3485
3486                        x = (int)bounds.left - labelWidth - bufferXL;
3487                        if (!byLabelHeight) {
3488                            y = (int)bounds.top + labelHeight - descent;
3489                        } else {
3490                            //y = bounds.y + ((bounds.getHeight * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3491                            y = (int)(bounds.top + ((bounds.height() * 0.5) - ((labelHeight - descent) * 0.5) + (-descent - bufferText)));
3492                        }
3493
3494                        ti.setLocation(Math.round(x), Math.round(y));
3495                        arrMods.add(ti);
3496                    }
3497                }
3498                if (modifiers.containsKey(Modifiers.W1_DTG_2)) {
3499                    strText = modifiers.get(Modifiers.W1_DTG_2);
3500                    if (strText != null) {
3501                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3502                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3503
3504                        x = (int)bounds.left - labelWidth - bufferXL;
3505                        if (!byLabelHeight) {
3506                            y = (int)bounds.top + labelHeight - descent;
3507                        } else {
3508                            //y = bounds.y + ((bounds.getHeight * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3509                            y = (int)(bounds.top + ((bounds.height() * 0.5) - (((labelHeight * 2) - descent) * 0.5) + (-descent - bufferText)));
3510                        }
3511
3512                        ti.setLocation(Math.round(x), Math.round(y));
3513                        arrMods.add(ti);
3514                    }
3515                }
3516            }
3517            else if (SymbolUtilities.isCBRNEvent(symbolID)) //CBRN
3518            {
3519                if (modifiers.containsKey(Modifiers.N_HOSTILE)) {
3520                    strText = modifiers.get(Modifiers.N_HOSTILE);
3521                    if (strText != null) {
3522                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3523
3524                        x = bounds.left + bounds.width() + bufferXR;
3525
3526                        if (!byLabelHeight) {
3527                            y = bounds.top + bounds.height();
3528                        } else {
3529                            y = bounds.top + (int) ((bounds.height() * 0.5f) + ((labelHeight - descent) * 0.5) + (labelHeight - descent + bufferText));
3530                        }
3531
3532                        ti.setLocation(Math.round(x), Math.round(y));
3533                        arrMods.add(ti);
3534                    }
3535
3536                }
3537                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3538                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3539                    if (strText != null) {
3540                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3541
3542                        x = bounds.left + bounds.width() + bufferXR;
3543                        if (!byLabelHeight) {
3544                            y = bounds.top + labelHeight - descent;
3545                        } else {
3546                            //y = bounds.y + ((bounds.height * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3547                            y = bounds.top + (int) ((bounds.height() * 0.5f) - ((labelHeight - descent) * 0.5) + (-descent - bufferText));
3548                        }
3549
3550                        ti.setLocation(Math.round(x), Math.round(y));
3551                        arrMods.add(ti);
3552                    }
3553                }
3554                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3555                    strText = modifiers.get(Modifiers.W_DTG_1);
3556                    if (strText != null) {
3557                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3558                        labelWidth = Math.round(ti.getTextBounds().width());
3559
3560                        x = bounds.left - labelWidth - bufferXL;
3561                        if (!byLabelHeight) {
3562                            y = bounds.top + labelHeight - descent;
3563                        } else {
3564                            //y = bounds.y + ((bounds.height * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3565                            y = bounds.top + (int) ((bounds.height() * 0.5) - ((labelHeight - descent) * 0.5) + (-descent - bufferText));
3566                        }
3567
3568                        ti.setLocation(Math.round(x), Math.round(y));
3569                        arrMods.add(ti);
3570                    }
3571                }
3572                if ((ec == 281500 || ec == 281600) && modifiers.containsKey(Modifiers.V_EQUIP_TYPE)) {//nuclear event or nuclear fallout producing event
3573                    strText = modifiers.get(Modifiers.V_EQUIP_TYPE);
3574                    if (strText != null) {
3575                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3576
3577                        //subset of nbc, just nuclear
3578                        labelWidth = Math.round(ti.getTextBounds().width());
3579                        x = bounds.left - labelWidth - bufferXL;
3580                        y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5));//((bounds.height / 2) - (labelHeight/2));
3581
3582                        ti.setLocation(Math.round(x), Math.round(y));
3583                        arrMods.add(ti);
3584                    }
3585                }
3586                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3587                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3588                    if (strText != null) {
3589                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3590                        labelWidth = Math.round(ti.getTextBounds().width());
3591                        x = bounds.left - labelWidth - bufferXL;
3592                        if (!byLabelHeight) {
3593                            y = bounds.top + bounds.height();
3594                        } else {
3595                            //y = bounds.y + ((bounds.height * 0.5) + ((labelHeight-descent) * 0.5) + (labelHeight + bufferText));
3596                            y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5) + (labelHeight - descent + bufferText));
3597                        }
3598                        ti.setLocation(Math.round(x), Math.round(y));
3599                        arrMods.add(ti);
3600                    }
3601                }
3602                if (modifiers.containsKey(Modifiers.Y_LOCATION)) {
3603                    strText = modifiers.get(Modifiers.Y_LOCATION);
3604                    if (strText != null) {
3605                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3606                        labelWidth = Math.round(ti.getTextBounds().width());
3607                        //just NBC
3608                        //x = bounds.left + (bounds.width() * 0.5);
3609                        //x = x - (labelWidth * 0.5);
3610                        x = bounds.left + (int) (bounds.width() * 0.5f);
3611                        x = x - (int) (labelWidth * 0.5f);
3612
3613                        if (!byLabelHeight) {
3614                            y = bounds.top + bounds.height() + labelHeight - descent + bufferY;
3615                        } else {
3616                            y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5) + ((labelHeight + bufferText) * 2) - descent);
3617
3618                        }
3619                        yForY = y + descent; //so we know where to start the DOM arrow.
3620                        ti.setLocation(Math.round(x), Math.round(y));
3621                        arrMods.add(ti);
3622                    }
3623
3624                }
3625                if (modifiers.containsKey(Modifiers.C_QUANTITY)) {
3626                    strText = modifiers.get(Modifiers.C_QUANTITY);
3627                    if (strText != null) {
3628                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3629                        labelWidth = Math.round(ti.getTextBounds().width());
3630                        //subset of NBC, just nuclear
3631                        x = bounds.left + (int) (bounds.width() * 0.5);
3632                        x = x - (int) (labelWidth * 0.5);
3633                        y = bounds.top - descent;
3634                        ti.setLocation(Math.round(x), Math.round(y));
3635                        arrMods.add(ti);
3636                    }
3637
3638                }
3639            }
3640            else if (ec == 270701)//static depiction
3641            {
3642                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3643                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3644                    if (strText != null) {
3645                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3646                        labelWidth = Math.round(ti.getTextBounds().width());
3647                        x = bounds.left + (int) (bounds.width() * 0.5);
3648                        x = x - (int) (labelWidth * 0.5);
3649                        y = bounds.top - descent;// + (bounds.height * 0.5);
3650                        //y = y + (labelHeight * 0.5);
3651
3652                        ti.setLocation(Math.round(x), Math.round(y));
3653                        arrMods.add(ti);
3654                    }
3655
3656                }
3657                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3658                    strText = modifiers.get(Modifiers.W_DTG_1);
3659                    if (strText != null) {
3660                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3661                        labelWidth = Math.round(ti.getTextBounds().width());
3662                        x = bounds.left + (int) (bounds.width() * 0.5);
3663                        x = x - (int) (labelWidth * 0.5);
3664                        y = bounds.top + (bounds.height());
3665                        y = y + (labelHeight);
3666
3667                        ti.setLocation(Math.round(x), Math.round(y));
3668                        arrMods.add(ti);
3669                    }
3670                }
3671                if (modifiers.containsKey(Modifiers.N_HOSTILE)) {
3672                    strText = modifiers.get(Modifiers.N_HOSTILE);
3673                    if (strText != null) {
3674                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3675                        TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3676                        labelWidth = Math.round(ti.getTextBounds().width());
3677                        x = bounds.left + (bounds.width()) + bufferXR;//right
3678                        //x = x + labelWidth;//- (labelBounds.width * 0.75);
3679
3680                        duplicate = true;
3681
3682                        x2 = bounds.left;//left
3683                        x2 = x2 - labelWidth - bufferXL;// - (labelBounds.width * 0.25);
3684
3685                        y = bounds.top + (int) (bounds.height() * 0.5);//center
3686                        y = y + (int) ((labelHeight - descent) * 0.5);
3687
3688                        y2 = y;
3689
3690                        ti.setLocation(Math.round(x), Math.round(y));
3691                        ti2.setLocation(Math.round(x2), Math.round(y2));
3692                        arrMods.add(ti);
3693                        arrMods.add(ti2);
3694                    }
3695                }
3696
3697            }
3698            else if(e == 21 && et == 35)//sonobuoys
3699            {
3700                //H sitting on center of circle to the right
3701                //T above H
3702                centerPoint = SymbolUtilities.getCMSymbolAnchorPoint(symbolID,RectUtilities.makeRectFFromRect(bounds));
3703                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3704                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3705                    if (strText != null) {
3706                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3707                        TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3708                        labelWidth = Math.round(ti.getTextBounds().width());
3709                        x = bounds.left + (bounds.width()) + bufferXR;//right
3710                        y = centerPoint.y;
3711
3712                        ti.setLocation(Math.round(x), Math.round(y));
3713                        arrMods.add(ti);
3714                    }
3715                }
3716                if (est == 0 || est == 1 || est == 4 || est == 7 || est == 8 || est == 15) {
3717                    if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3718                        strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3719                        if (strText != null) {
3720                            ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3721                            TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3722                            labelWidth = Math.round(ti.getTextBounds().width());
3723                            x = bounds.left + (bounds.width()) + bufferXR;//right
3724                            y = centerPoint.y - labelHeight;
3725
3726                            ti.setLocation(Math.round(x), Math.round(y));
3727                            arrMods.add(ti);
3728                        }
3729                    }
3730                }
3731            }
3732            else if(ec == 282001 || //tower, low
3733                    ec == 282002)   //tower, high
3734            {
3735                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) {
3736                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3737                    if (strText != null) {
3738                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3739                        labelWidth = Math.round(ti.getTextBounds().width());
3740                        x = bounds.left + (int) (bounds.width() * 0.7);
3741                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3742                        //y = y + (labelHeight * 0.5);
3743
3744                        ti.setLocation(Math.round(x), Math.round(y));
3745                        arrMods.add(ti);
3746                    }
3747
3748                }
3749            }
3750            else if(ec == 180600)//TACAN
3751            {
3752                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3753                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3754                    if (strText != null) {
3755                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3756                        labelWidth = Math.round(ti.getTextBounds().width());
3757                        x = bounds.left + bounds.width() + bufferXR;
3758                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3759                        //y = y + (labelHeight * 0.5);
3760
3761                        ti.setLocation(Math.round(x), Math.round(y));
3762                        arrMods.add(ti);
3763                    }
3764
3765                }
3766            }
3767            else if(ec == 210300)//Defended Asset
3768            {
3769                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3770                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3771                    if (strText != null) {
3772                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3773                        labelWidth = Math.round(ti.getTextBounds().width());
3774                        x = bounds.left - labelWidth - bufferXL;
3775                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3776                        //y = y + (labelHeight * 0.5);
3777
3778                        ti.setLocation(Math.round(x), Math.round(y));
3779                        arrMods.add(ti);
3780                    }
3781
3782                }
3783            }
3784            else if(ec == 210600)//Air Detonation
3785            {
3786                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) {
3787                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3788                    if (strText != null) {
3789                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3790                        labelWidth = Math.round(ti.getTextBounds().width());
3791                        x = bounds.left + (bounds.width() + bufferXR);
3792                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3793                        //y = y + (labelHeight * 0.5);
3794
3795                        ti.setLocation(Math.round(x), Math.round(y));
3796                        arrMods.add(ti);
3797                    }
3798
3799                }
3800            }
3801            else if(ec == 210800)//Impact Point
3802            {
3803                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3804                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3805                    if (strText != null) {
3806                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3807                        labelWidth = Math.round(ti.getTextBounds().width());
3808                        x = bounds.left + (int) (bounds.width() * 0.65f);
3809//                  x = x - (labelBounds.width * 0.5);
3810                        y = bounds.top + (int) (bounds.height() * 0.25f);
3811                        y = y + (int) (labelHeight * 0.5f);
3812                        //y = y + (labelHeight * 0.5);
3813
3814                        ti.setLocation(Math.round(x), Math.round(y));
3815                        arrMods.add(ti);
3816                    }
3817
3818                }
3819            }
3820            else if(ec == 211000)//Launched Torpedo
3821            {
3822                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3823                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3824                    if (strText != null) {
3825                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3826                        labelWidth = Math.round(ti.getTextBounds().width());
3827                        x = (int)(bounds.left + (bounds.width() * 0.5) - (labelWidth/2));
3828                        y = bounds.top - bufferY;
3829
3830                        ti.setLocation(Math.round(x), Math.round(y));
3831                        arrMods.add(ti);
3832                    }
3833
3834                }
3835            }
3836            else if(ec == 214900 || ec == 215600)//General Sea SubSurface Station & General Sea Surface Station
3837            {
3838                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3839                    strText = modifiers.get(Modifiers.W_DTG_1);
3840                    if (strText != null) {
3841                        ti = new TextInfo(strText + " - ", 0, 0, modifierFont, modifierFontName);
3842                        x = bounds.left + (bounds.width() + bufferXR);
3843                        y = bounds.top + labelHeight;
3844
3845                        ti.setLocation(Math.round(x), Math.round(y));
3846                        arrMods.add(ti);
3847                    }
3848
3849                }
3850                if (modifiers.containsKey(Modifiers.W1_DTG_2)) {
3851                    strText = modifiers.get(Modifiers.W1_DTG_2);
3852                    if (strText != null) {
3853                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3854                        x = bounds.left + (bounds.width() + bufferXR);
3855                        y = bounds.top + (labelHeight * 2);
3856
3857                        ti.setLocation(Math.round(x), Math.round(y));
3858                        arrMods.add(ti);
3859                    }
3860
3861                }
3862                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3863                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3864                    if (strText != null) {
3865                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3866                        x = bounds.left + (bounds.width() + bufferXR);
3867                        y = bounds.top + (labelHeight * 3);
3868
3869                        ti.setLocation(Math.round(x), Math.round(y));
3870                        arrMods.add(ti);
3871                    }
3872
3873                }
3874            }
3875            else if(ec == 217000)//Shore Control Station
3876            {
3877                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3878                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3879                    if (strText != null) {
3880                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3881                        labelWidth = Math.round(ti.getTextBounds().width());
3882                        x = (int)(bounds.left + (bounds.width() * 0.5) - (labelWidth/2));
3883                        y = bounds.top + bounds.height() + labelHeight + bufferY;
3884
3885                        ti.setLocation(Math.round(x), Math.round(y));
3886                        arrMods.add(ti);
3887                    }
3888
3889                }
3890            }
3891            else if(ec == 250600)//Known Point
3892            {
3893                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3894                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3895                    if (strText != null) {
3896                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3897                        labelWidth = Math.round(ti.getTextBounds().width());
3898                        x = bounds.left + (bounds.width() + bufferXR);
3899//                  x = x - (labelBounds.width * 0.5);
3900                        y = bounds.top + (int) (bounds.height() * 0.25f);
3901                        y = y + (int) (labelHeight * 0.5f);
3902                        //y = y + (labelHeight * 0.5);
3903
3904                        ti.setLocation(Math.round(x), Math.round(y));
3905                        arrMods.add(ti);
3906                    }
3907
3908                }
3909            }
3910        }
3911        else if(ss == SymbolID.SymbolSet_Atmospheric)
3912        {
3913            String modX = null;
3914            if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
3915                modX = (modifiers.get(Modifiers.X_ALTITUDE_DEPTH));
3916
3917            if(ec == 162300)//Freezing Level
3918            {
3919                strText = "0" + (char)(176) + ":";
3920                if(modX != null)
3921                    strText += modX;
3922                else
3923                    strText += "?";
3924
3925                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3926                labelWidth = Math.round(ti.getTextBounds().width());
3927                //One modifier symbols and modifier goes in center
3928                x = bounds.left + (int) (bounds.width() * 0.5f);
3929                x = x - (int) (labelWidth * 0.5f);
3930                y = bounds.top + (int) (bounds.height() * 0.5f);
3931                y = y + (int) ((labelHeight - modifierFontDescent) * 0.5f);
3932
3933                ti.setLocation(Math.round(x), Math.round(y));
3934                arrMods.add(ti);
3935            }
3936            else if(ec == 162200)//tropopause Level
3937            {
3938                strText = "X?";
3939                if(modX != null)
3940                    strText = modX;
3941
3942                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3943                labelWidth = Math.round(ti.getTextBounds().width());
3944                //One modifier symbols and modifier goes in center
3945                x = bounds.left + (int) (bounds.width() * 0.5f);
3946                x = x - (int) (labelWidth * 0.5f);
3947                y = bounds.top + (int) (bounds.height() * 0.5f);
3948                y = y + (int) ((labelHeight - modifierFontDescent) * 0.5f);
3949
3950                ti.setLocation(Math.round(x), Math.round(y));
3951                arrMods.add(ti);
3952            }
3953            else if(ec == 110102)//tropopause Low
3954            {
3955                strText = "X?";
3956                if(modX != null)
3957                    strText = modX;
3958
3959                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3960                labelWidth = Math.round(ti.getTextBounds().width());
3961                //One modifier symbols and modifier goes in center
3962                x = bounds.left + (int) (bounds.width() * 0.5f);
3963                x = x - (int) (labelWidth * 0.5f);
3964                y = bounds.top + (int) (bounds.height() * 0.5f);
3965                y = y - descent;
3966
3967                ti.setLocation(Math.round(x), Math.round(y));
3968                arrMods.add(ti);
3969            }
3970            else if(ec == 110202)//tropopause High
3971            {
3972                strText = "X?";
3973                if(modX != null)
3974                    strText = modX;
3975
3976                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3977                labelWidth = Math.round(ti.getTextBounds().width());
3978                //One modifier symbols and modifier goes in center
3979                x = bounds.left + (int) (bounds.width() * 0.5f);
3980                x = x - (int) (labelWidth * 0.5f);
3981                y = bounds.top + (int) (bounds.height() * 0.5f);
3982                //y = y + (int) ((labelHeight * 0.5f) + (labelHeight/2));
3983                y = y + (int) (((labelHeight * 0.5f) - (labelHeight/2)) + labelHeight - descent);
3984
3985                ti.setLocation(Math.round(x), Math.round(y));
3986                arrMods.add(ti);
3987            }
3988        }
3989        // </editor-fold>
3990
3991        // <editor-fold defaultstate="collapsed" desc="DOM Arrow">
3992        Point[] domPoints = null;
3993        Rect domBounds = null;
3994
3995        if (modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT) &&
3996                SymbolUtilities.isCBRNEvent(symbolID))//CBRN events
3997        {
3998            strText = modifiers.get(Modifiers.Q_DIRECTION_OF_MOVEMENT);
3999            if(strText != null && SymbolUtilities.isNumber(strText))
4000            {
4001                    float q = Float.parseFloat(strText);
4002                    Rect tempBounds = new Rect(bounds);
4003                    tempBounds.union(RectUtilities.getCenterX(bounds), yForY);
4004        
4005                    domPoints = createDOMArrowPoints(symbolID, tempBounds, sdi.getCenterPoint(), q, false, modifierFontHeight);
4006        
4007                    domBounds = RectUtilities.makeRect(domPoints[0].x, domPoints[0].y, 1, 1);
4008        
4009                    Point temp = null;
4010                    for (int i = 1; i < 6; i++)
4011                    {
4012                        temp = domPoints[i];
4013                        if (temp != null)
4014                        {
4015                            domBounds.union(temp.x, temp.y);
4016                        }
4017                    }
4018                    imageBounds.union(domBounds);
4019            }
4020        }
4021        // </editor-fold>
4022
4023        // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
4024        if (SymbolUtilities.hasFDI(symbolID))
4025        {
4026            //create feint indicator /\
4027            fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
4028            fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
4029            fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
4030
4031
4032            fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
4033            fdiBounds.union(fdiTop.x, fdiTop.y);
4034            fdiBounds.union(fdiRight.x, fdiRight.y);
4035
4036            float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4037            RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
4038
4039            ti = new TextInfo("TEST",0,0, modifierFont, modifierFontName);
4040            if (ti != null && SymbolUtilities.isCBRNEvent(symbolID))
4041            {
4042                int shiftY = Math.round(symbolBounds.top - ti.getTextBounds().height() - 2);
4043                fdiLeft.offset(0, shiftY);
4044                fdiTop.offset(0, shiftY);
4045                fdiRight.offset(0, shiftY);
4046                fdiBounds.offset(0, shiftY);
4047            }
4048
4049            imageBounds.union(fdiBounds);
4050
4051        }
4052        // </editor-fold>
4053
4054        // <editor-fold defaultstate="collapsed" desc="Shift Points and Draw">
4055        Rect modifierBounds = null;
4056        if (arrMods != null && arrMods.size() > 0)
4057        {
4058
4059            //build modifier bounds/////////////////////////////////////////
4060            modifierBounds = arrMods.get(0).getTextOutlineBounds();
4061            int size = arrMods.size();
4062            TextInfo tempShape = null;
4063            for (int i = 1; i < size; i++)
4064            {
4065                tempShape = arrMods.get(i);
4066                modifierBounds.union(tempShape.getTextOutlineBounds());
4067            }
4068
4069        }
4070
4071        if (modifierBounds != null || domBounds != null || fdiBounds != null)
4072        {
4073
4074            if (modifierBounds != null)
4075            {
4076                imageBounds.union(modifierBounds);
4077            }
4078            if (domBounds != null)
4079            {
4080                imageBounds.union(domBounds);
4081            }
4082            if (fdiBounds != null)
4083            {
4084                imageBounds.union(fdiBounds);
4085            }
4086
4087            //shift points if needed////////////////////////////////////////
4088            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4089            {
4090                int shiftX = Math.abs(imageBounds.left);
4091                int shiftY = Math.abs(imageBounds.top);
4092
4093                //shift mobility points
4094                int size = arrMods.size();
4095                TextInfo tempShape = null;
4096                for (int i = 0; i < size; i++)
4097                {
4098                    tempShape = arrMods.get(i);
4099                    tempShape.shift(shiftX, shiftY);
4100                }
4101                if(modifierBounds != null)
4102                    modifierBounds.offset(shiftX, shiftY);
4103
4104                if (domBounds != null)
4105                {
4106                    for (int i = 0; i < 6; i++)
4107                    {
4108                        Point temp = domPoints[i];
4109                        if (temp != null)
4110                        {
4111                            temp.offset(shiftX, shiftY);
4112                        }
4113                    }
4114                    domBounds.offset(shiftX, shiftY);
4115                }
4116
4117                //If there's an FDI
4118                if (fdiBounds != null)
4119                {
4120                    fdiBounds.offset(shiftX, shiftY);
4121                    fdiLeft.offset(shiftX, shiftY);
4122                    fdiTop.offset(shiftX, shiftY);
4123                    fdiRight.offset(shiftX, shiftY);
4124                }
4125
4126                //shift image points
4127                centerPoint.offset(shiftX, shiftY);
4128                symbolBounds.offset(shiftX, shiftY);
4129                imageBounds.offset(shiftX, shiftY);
4130            }
4131
4132
4133            if (attributes.containsKey(MilStdAttributes.TextColor))
4134            {
4135                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4136                if(alpha > -1)
4137                    textColor.setAlpha(alpha);
4138            }
4139            if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4140            {
4141                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4142                if(alpha > -1)
4143                    textBackgroundColor.setAlpha(alpha);
4144            }
4145
4146            if(sdi instanceof ImageInfo) {
4147                ii = (ImageInfo)sdi;
4148                //Render modifiers//////////////////////////////////////////////////
4149                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4150                Canvas ctx = new Canvas(bmp);
4151
4152                //render////////////////////////////////////////////////////////
4153                //draw original icon with potential modifiers.
4154                ctx.drawBitmap(ii.getImage(), symbolBounds.left, symbolBounds.top, null);
4155                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4156
4157
4158                renderText(ctx, arrMods, textColor, textBackgroundColor, modifierFont);
4159
4160                //draw DOM arrow
4161                if (domBounds != null)
4162                {
4163                    drawDOMArrow(ctx, domPoints, alpha, lineColor);
4164                }
4165
4166                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4167                if (fdiBounds != null) {
4168
4169                    Paint fdiPaint = new Paint();
4170                    fdiPaint.setAntiAlias(true);
4171                    fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
4172                    if (alpha > -1)
4173                        fdiPaint.setAlpha(alpha);
4174                    fdiPaint.setStyle(Style.STROKE);
4175
4176                    int dpi = RendererSettings.getInstance().getDeviceDPI();
4177                    int lineLength = dpi / 96 * 6;
4178                    int lineGap = dpi / 96 * 4;
4179
4180                    /// ///////////////////////////////////
4181                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4182                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4183                    //distance = distance / 14f;
4184                    lineGap = (int)((distance / 14f) * 2);
4185                    lineLength = (int)((distance / 14f) * 3);
4186                    /// //////////////////////////////////
4187
4188                    fdiPaint.setPathEffect(new DashPathEffect(new float[]
4189                            {
4190                                    lineLength, lineGap
4191                            }, 0));
4192
4193                    float fdiStrokeWidth = Math.round(dpi / 96f);
4194                    if (fdiStrokeWidth < 2)
4195                        fdiStrokeWidth = 2;
4196
4197                    fdiPaint.setStrokeCap(Cap.ROUND);
4198                    fdiPaint.setStrokeJoin(Join.MITER);
4199                    fdiPaint.setStrokeWidth(fdiStrokeWidth);
4200
4201                    Path fdiPath = new Path();
4202
4203                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4204                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4205                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4206                    fdiPath.lineTo(fdiRight.x, fdiRight.y);
4207                    ctx.drawPath(fdiPath, fdiPaint);
4208
4209                    fdiBounds = null;
4210
4211                }
4212                //</editor-fold>
4213
4214                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4215                ctx = null;
4216            }
4217            else if(sdi instanceof SVGSymbolInfo)
4218            {
4219                float strokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4220                if(strokeWidth < 1)
4221                    strokeWidth=1;
4222                String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
4223                String svgStrokeWidth = String.valueOf(strokeWidth);//"3";
4224
4225                ssi = (SVGSymbolInfo)sdi;
4226                StringBuilder sbSVG = new StringBuilder();
4227                sbSVG.append(ssi.getSVG());
4228                sbSVG.append(renderTextElements(arrMods,textColor,textBackgroundColor));
4229
4230                // <editor-fold defaultstate="collapsed" desc="DOM arrow">
4231                if (domBounds != null && domPoints.length == 6)
4232                {
4233                    SVGPath domPath = new SVGPath() ;
4234
4235                    domPath.moveTo(domPoints[0].x, domPoints[0].y);
4236                    if (domPoints[1] != null)
4237                    {
4238                        domPath.lineTo(domPoints[1].x, domPoints[1].y);
4239                    }
4240                    if (domPoints[2] != null)
4241                    {
4242                        domPath.lineTo(domPoints[2].x, domPoints[2].y);
4243                    }
4244                    sbSVG.append(domPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,null));
4245
4246                    domPath = new SVGPath();
4247
4248                    domPath.moveTo(domPoints[3].x, domPoints[3].y);
4249                    domPath.lineTo(domPoints[4].x, domPoints[4].y);
4250                    domPath.lineTo(domPoints[5].x, domPoints[5].y);
4251                    sbSVG.append(domPath.toSVGElement(null,0f,svgStroke,1f,1f,null));
4252
4253                    domBounds = null;
4254                    domPoints = null;
4255                }
4256                // </editor-fold>
4257
4258                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4259                if (fdiBounds != null)
4260                {
4261
4262                    /*int dpi = RendererSettings.getInstance().getDeviceDPI();
4263                    int lineLength = dpi / 96 * 6;
4264                    int lineGap = dpi / 96 * 4;
4265                    String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
4266
4267                    /// ///////////////////////////////////
4268                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4269                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4270                    //distance = distance / 14f;
4271                    int lineGap = (int)((distance / 14f) * 2);
4272                    int lineLength = (int)((distance / 14f) * 3);
4273                    String svgFDIDashArray = "" + lineLength + " " + lineGap;
4274                    /// //////////////////////////////////
4275
4276                    SVGPath fdiPath = new SVGPath();
4277                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4278                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4279                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4280                    fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
4281
4282                    fdiPath.setLineDash(svgFDIDashArray);
4283
4284                    sbSVG.append(fdiPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,"round"));
4285                    //sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray));
4286                }
4287                //</editor-fold>
4288
4289                newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
4290            }
4291
4292
4293
4294
4295            // <editor-fold defaultstate="collapsed" desc="Cleanup">
4296            //ctx = null;
4297            // </editor-fold>
4298
4299            return newsdi;
4300
4301        }
4302        else
4303        {
4304            return null;
4305        }
4306        // </editor-fold>
4307
4308    }
4309
4310    /**
4311     * Process modifiers for action points
4312     */
4313    public static SymbolDimensionInfo ProcessTGSPModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes, Color lineColor)
4314    {
4315
4316        Paint modifierFont = getFont(attributes);
4317        float[] hd = getFontHeightandDescent(modifierFont);
4318        float modifierFontHeight = hd[0];
4319        float modifierFontDescent = hd[1];
4320
4321        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
4322        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
4323        {
4324            String temp = attributes.get(MilStdAttributes.FontFamily);
4325            if(temp != null && !temp.isEmpty())
4326                modifierFontName = temp;
4327        }
4328
4329        // <editor-fold defaultstate="collapsed" desc="Variables">
4330        ImageInfo ii = null;
4331        SVGSymbolInfo ssi = null;
4332
4333        int bufferXL = 6;
4334        int bufferXR = 4;
4335        int bufferY = 2;
4336        int bufferText = 2;
4337        int centerOffset = 1; //getCenterX/Y function seems to go over by a pixel
4338        int x = 0;
4339        int y = 0;
4340        int x2 = 0;
4341        int y2 = 0;
4342
4343        //Feint Dummy Indicator variables
4344        Rect fdiBounds = null;
4345        Point fdiTop = null;
4346        Point fdiLeft = null;
4347        Point fdiRight = null;
4348
4349        int outlineOffset = RS.getTextOutlineWidth();
4350        int labelHeight = 0;
4351        int labelWidth = 0;
4352        int alpha = -1;
4353        SymbolDimensionInfo newsdi = null;
4354        
4355        Color textColor = lineColor;
4356        Color textBackgroundColor = null;
4357
4358        ArrayList<TextInfo> arrMods = new ArrayList<TextInfo>();
4359        boolean duplicate = false;
4360
4361        MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
4362
4363
4364        if (attributes.containsKey(MilStdAttributes.Alpha))
4365        {
4366            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
4367        }
4368
4369        Rect bounds = new Rect(sdi.getSymbolBounds());
4370        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
4371        Point centerPoint = new Point(sdi.getCenterPoint());
4372        Rect imageBounds = new Rect(sdi.getImageBounds());
4373
4374        centerPoint = new Point(Math.round(sdi.getCenterPoint().x), Math.round(sdi.getCenterPoint().y));
4375
4376        boolean byLabelHeight = false;
4377
4378        labelHeight = Math.round(modifierFontHeight + 0.5f);
4379        int maxHeight = (symbolBounds.height());
4380        if ((labelHeight * 3) > maxHeight)
4381        {
4382            byLabelHeight = true;
4383        }
4384
4385        int descent = (int) (modifierFontDescent + 0.5f);
4386        int yForY = -1;
4387
4388        Rect labelBounds1 = null;//text.getPixelBounds(null, 0, 0);
4389        Rect labelBounds2 = null;
4390        String strText = "";
4391        String strText1 = "";
4392        String strText2 = "";
4393        TextInfo text1 = null;
4394        TextInfo text2 = null;
4395
4396        String basicID = SymbolUtilities.getBasicSymbolID(symbolID);
4397
4398        if (outlineOffset > 2)
4399        {
4400            outlineOffset = ((outlineOffset - 1) / 2);
4401        }
4402        else
4403        {
4404            outlineOffset = 0;
4405        }
4406
4407        /*bufferXL += outlineOffset;
4408         bufferXR += outlineOffset;
4409         bufferY += outlineOffset;
4410         bufferText += outlineOffset;*/
4411        // </editor-fold>
4412        // <editor-fold defaultstate="collapsed" desc="Process Modifiers">
4413        TextInfo ti = null;
4414
4415        {
4416            if (msi.getModifiers().contains(Modifiers.N_HOSTILE) && modifiers.containsKey(Modifiers.N_HOSTILE))
4417            {
4418                strText = modifiers.get(Modifiers.N_HOSTILE);
4419                if(strText != null)
4420                {
4421                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4422        
4423                        x = bounds.left + bounds.width() + bufferXR;
4424        
4425                        if (!byLabelHeight)
4426                        {
4427                            y = ((bounds.height() / 3) * 2);//checkpoint, get box above the point
4428                            y = bounds.top + y;
4429                        }
4430                        else
4431                        {
4432                            //y = ((labelHeight + bufferText) * 3);
4433                            //y = bounds.y + y - descent;
4434                            y = bounds.top + bounds.height();
4435                        }
4436        
4437                        ti.setLocation(x, y);
4438                        arrMods.add(ti);
4439                }
4440
4441            }
4442            if (msi.getModifiers().contains(Modifiers.H_ADDITIONAL_INFO_1) && modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
4443            {
4444                strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
4445                if(strText != null)
4446                {
4447                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4448                        labelWidth = Math.round(ti.getTextBounds().width());
4449        
4450                        x = bounds.left + (int) (bounds.width() * 0.5f);
4451                        x = x - (int) (labelWidth * 0.5f);
4452                        y = bounds.top - descent;
4453        
4454                        ti.setLocation(x, y);
4455                        arrMods.add(ti);
4456                }
4457            }
4458            if (msi.getModifiers().contains(Modifiers.H1_ADDITIONAL_INFO_2) && modifiers.containsKey(Modifiers.H1_ADDITIONAL_INFO_2))
4459            {
4460                strText = modifiers.get(Modifiers.H1_ADDITIONAL_INFO_2);
4461                if(strText != null)
4462                {
4463                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4464                        labelWidth = Math.round(ti.getTextBounds().width());
4465        
4466                        x = bounds.left + (int) (bounds.width() * 0.5);
4467                        x = x - (int) (labelWidth * 0.5);
4468                    y = bounds.top + labelHeight - descent + (int) (bounds.height() * 0.07);
4469        
4470                        ti.setLocation(x, y);
4471                        arrMods.add(ti);
4472                }
4473            }
4474            if (msi.getModifiers().contains(Modifiers.A_SYMBOL_ICON))
4475            {
4476                if(modifiers.containsKey(Modifiers.A_SYMBOL_ICON))
4477                    strText = modifiers.get(Modifiers.A_SYMBOL_ICON);
4478                else if(SymbolID.getEntityCode(symbolID)==321706)//NATO Multiple Supply Class Point
4479                    strText = "ALL?";//make it clear the required 'A' value wasn't set for this symbol.
4480
4481                if(strText != null)
4482                {
4483                    ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4484                    labelWidth = Math.round(ti.getTextBounds().width());
4485
4486                    x = bounds.left + (int) (bounds.width() * 0.5);
4487                    x = x - (int) (labelWidth * 0.5);
4488                    y = bounds.top + labelHeight - descent + (int) (bounds.height() * 0.07);
4489
4490                    ti.setLocation(x, y);
4491                    arrMods.add(ti);
4492                }
4493            }
4494            if (msi.getModifiers().contains(Modifiers.W_DTG_1) && modifiers.containsKey(Modifiers.W_DTG_1))
4495            {
4496                strText = modifiers.get(Modifiers.W_DTG_1);
4497                if(strText != null)
4498                {
4499                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4500                        labelWidth = Math.round(ti.getTextBounds().width());
4501        
4502                        x = bounds.left - labelWidth - bufferXL;
4503                        y = bounds.top + labelHeight - descent;
4504        
4505                        ti.setLocation(x, y);
4506                        arrMods.add(ti);
4507                }
4508            }
4509            if (msi.getModifiers().contains(Modifiers.W1_DTG_2) && modifiers.containsKey(Modifiers.W1_DTG_2))
4510            {
4511                strText = modifiers.get(Modifiers.W1_DTG_2);
4512                if(strText != null)
4513                {
4514                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4515                        labelWidth = Math.round(ti.getTextBounds().width());
4516        
4517                        x = bounds.left - labelWidth - bufferXL;
4518        
4519                        y = ((labelHeight - descent + bufferText) * 2);
4520                        y = bounds.top + y;
4521        
4522                        ti.setLocation(x, y);
4523                        arrMods.add(ti);
4524                }
4525            }
4526            if (msi.getModifiers().contains(Modifiers.T_UNIQUE_DESIGNATION_1) && modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
4527            {
4528                strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
4529                if(strText != null)
4530                {
4531                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4532        
4533                        x = bounds.left + bounds.width() + bufferXR;
4534                        y = bounds.top + labelHeight - descent;
4535        
4536                        ti.setLocation(x, y);
4537                        arrMods.add(ti);
4538                }
4539            }
4540            if (msi.getModifiers().contains(Modifiers.T1_UNIQUE_DESIGNATION_2) && modifiers.containsKey(Modifiers.T1_UNIQUE_DESIGNATION_2))
4541            {
4542                strText = modifiers.get(Modifiers.T1_UNIQUE_DESIGNATION_2);
4543                if(strText != null)
4544                {
4545                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4546                        labelWidth = Math.round(ti.getTextBounds().width());
4547        
4548                        //points
4549                        x = bounds.left + (int) (bounds.width() * 0.5);
4550                        x = x - (int) (labelWidth * 0.5);
4551                        //y = bounds.y + (bounds.height * 0.5);
4552        
4553                        y = (int) ((bounds.height() * 0.55));//633333333
4554                        y = bounds.top + y;
4555        
4556                        ti.setLocation(x, y);
4557                        arrMods.add(ti);
4558                }
4559            }
4560            // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
4561            if (SymbolUtilities.hasFDI(symbolID))
4562            {
4563                //create feint indicator /\
4564                fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
4565                fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
4566                fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
4567
4568
4569                fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
4570                fdiBounds.union(fdiTop.x, fdiTop.y);
4571                fdiBounds.union(fdiRight.x, fdiRight.y);
4572
4573                float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4574                RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
4575
4576                ti = new TextInfo("TEST",0,0, modifierFont, modifierFontName);
4577                if (ti != null)
4578                {
4579                    int shiftY = Math.round(symbolBounds.top - ti.getTextBounds().height() - 2);
4580                    fdiLeft.offset(0, shiftY);
4581                    fdiTop.offset(0, shiftY);
4582                    fdiRight.offset(0, shiftY);
4583                    fdiBounds.offset(0, shiftY);
4584                }
4585
4586                imageBounds.union(fdiBounds);
4587
4588            }
4589            // </editor-fold>
4590        }
4591
4592        // </editor-fold>
4593        // <editor-fold defaultstate="collapsed" desc="Shift Points and Draw">
4594        Rect modifierBounds = null;
4595        if (arrMods != null && arrMods.size() > 0)
4596        {
4597
4598            //build modifier bounds/////////////////////////////////////////
4599            modifierBounds = arrMods.get(0).getTextOutlineBounds();
4600            int size = arrMods.size();
4601            TextInfo tempShape = null;
4602            for (int i = 1; i < size; i++)
4603            {
4604                tempShape = arrMods.get(i);
4605                modifierBounds.union(tempShape.getTextOutlineBounds());
4606            }
4607
4608        }
4609
4610        if(fdiBounds != null)
4611        {
4612            if(modifierBounds != null)
4613                modifierBounds.union(fdiBounds);
4614            else
4615                modifierBounds = fdiBounds;
4616        }
4617
4618        if (modifierBounds != null)
4619        {
4620
4621            imageBounds.union(modifierBounds);
4622
4623            //shift points if needed////////////////////////////////////////
4624            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4625            {
4626                int shiftX = Math.abs(imageBounds.left);
4627                int shiftY = Math.abs(imageBounds.top);
4628
4629                //shift mobility points
4630                int size = arrMods.size();
4631                TextInfo tempShape = null;
4632                for (int i = 0; i < size; i++)
4633                {
4634                    tempShape = arrMods.get(i);
4635                    tempShape.shift(shiftX, shiftY);
4636                }
4637                modifierBounds.offset(shiftX, shiftY);
4638
4639                //shift image points
4640                centerPoint.offset(shiftX, shiftY);
4641                symbolBounds.offset(shiftX, shiftY);
4642                imageBounds.offset(shiftX, shiftY);
4643
4644                //If there's an FDI
4645                if (fdiBounds != null)
4646                {
4647                    fdiBounds.offset(shiftX, shiftY);
4648                    fdiLeft.offset(shiftX, shiftY);
4649                    fdiTop.offset(shiftX, shiftY);
4650                    fdiRight.offset(shiftX, shiftY);
4651                }
4652            }
4653
4654            if (attributes.containsKey(MilStdAttributes.TextColor))
4655            {
4656                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4657                if(alpha > -1)
4658                    textColor.setAlpha(alpha);
4659            }
4660            if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4661            {
4662                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4663                if(alpha > -1)
4664                    textBackgroundColor.setAlpha(alpha);
4665            }
4666
4667            if(sdi instanceof ImageInfo)
4668            {
4669                ii = (ImageInfo) sdi;
4670                //Render modifiers//////////////////////////////////////////////////
4671                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4672                Canvas ctx = new Canvas(bmp);
4673
4674                //draw original icon with potential modifiers.
4675                ctx.drawBitmap(ii.getImage(), symbolBounds.left, symbolBounds.top, null);
4676                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4677
4678
4679                renderText(ctx, arrMods, textColor, textBackgroundColor, modifierFont);
4680
4681                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4682                if (fdiBounds != null) {
4683
4684                    Paint fdiPaint = new Paint();
4685                    fdiPaint.setAntiAlias(true);
4686                    fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
4687                    if (alpha > -1)
4688                        fdiPaint.setAlpha(alpha);
4689                    fdiPaint.setStyle(Style.STROKE);
4690
4691                    int dpi = RendererSettings.getInstance().getDeviceDPI();
4692                    int lineLength = dpi / 96 * 6;
4693                    int lineGap = dpi / 96 * 4;
4694
4695                    /// ///////////////////////////////////
4696                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4697                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4698                    //distance = distance / 14f;
4699                    lineGap = (int)((distance / 14f) * 2);
4700                    lineLength = (int)((distance / 14f) * 3);
4701                    /// //////////////////////////////////
4702
4703                    fdiPaint.setPathEffect(new DashPathEffect(new float[]
4704                            {
4705                                    lineLength, lineGap
4706                            }, 0));
4707
4708                    float fdiStrokeWidth = Math.round(dpi / 96f);
4709                    if (fdiStrokeWidth < 2)
4710                        fdiStrokeWidth = 2;
4711
4712                    fdiPaint.setStrokeCap(Cap.ROUND);
4713                    fdiPaint.setStrokeJoin(Join.MITER);
4714                    fdiPaint.setStrokeWidth(fdiStrokeWidth);
4715
4716                    Path fdiPath = new Path();
4717
4718                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4719                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4720                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4721                    fdiPath.lineTo(fdiRight.x, fdiRight.y);
4722                    ctx.drawPath(fdiPath, fdiPaint);
4723
4724                    fdiBounds = null;
4725
4726                }
4727                //</editor-fold>
4728
4729                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4730            }
4731            else if(sdi instanceof SVGSymbolInfo)
4732            {
4733                String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
4734                String svgStrokeWidth = "3";
4735                String svgAlpha = null;
4736                if(alpha > -1)
4737                    svgAlpha = String.valueOf(alpha);
4738                ssi = (SVGSymbolInfo)sdi;
4739                StringBuilder sbSVG = new StringBuilder();
4740                sbSVG.append(ssi.getSVG());
4741                sbSVG.append(renderTextElements(arrMods,textColor,textBackgroundColor));
4742
4743                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4744                if (fdiBounds != null)
4745                {
4746                    /*int dpi = RendererSettings.getInstance().getDeviceDPI();
4747                    int lineLength = dpi / 96 * 6;
4748                    int lineGap = dpi / 96 * 4;
4749                    String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
4750
4751                    /// ///////////////////////////////////
4752                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4753                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4754                    //distance = distance / 14f;
4755                    int lineGap = (int)((distance / 14f) * 2);
4756                    int lineLength = (int)((distance / 14f) * 3);
4757                    String svgFDIDashArray = "" + lineLength + " " + lineGap;
4758                    /// //////////////////////////////////
4759
4760                    SVGPath fdiPath = new SVGPath();
4761                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4762                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4763                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4764                    fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
4765
4766                    fdiPath.setLineDash(svgFDIDashArray);
4767                    sbSVG.append(fdiPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,"round"));
4768                    //sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray));
4769                }
4770                //</editor-fold>
4771
4772                newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
4773            }
4774
4775            // <editor-fold defaultstate="collapsed" desc="Cleanup">
4776            //ctx = null;
4777
4778            // </editor-fold>
4779        }
4780        // </editor-fold>
4781        return newsdi;
4782
4783    }
4784
4785    private static SymbolDimensionInfo shiftUnitPointsAndDraw(ArrayList<TextInfo> tiArray, SymbolDimensionInfo sdi, Map<String,String> attributes, Paint modifierFont)
4786    {
4787
4788        ImageInfo ii = null;
4789        SVGSymbolInfo ssi = null;
4790        SymbolDimensionInfo newsdi = null;
4791
4792        int alpha = -1;
4793
4794
4795        if (attributes != null && attributes.containsKey(MilStdAttributes.Alpha))
4796        {
4797            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
4798        }
4799
4800        Color textColor = Color.BLACK;
4801        Color textBackgroundColor = null;
4802
4803        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
4804        Point centerPoint = new Point(sdi.getCenterPoint());
4805        Rect imageBounds = new Rect(sdi.getImageBounds());
4806        Rect imageBoundsOld = new Rect(sdi.getImageBounds());
4807
4808        Rect modifierBounds = null;
4809        if (tiArray != null && tiArray.size() > 0)
4810        {
4811
4812            //build modifier bounds/////////////////////////////////////////
4813            modifierBounds = tiArray.get(0).getTextOutlineBounds();
4814            int size = tiArray.size();
4815            TextInfo tempShape = null;
4816            for (int i = 1; i < size; i++)
4817            {
4818                tempShape = tiArray.get(i);
4819                modifierBounds.union(tempShape.getTextOutlineBounds());
4820            }
4821
4822        }
4823
4824        if (modifierBounds != null)
4825        {
4826
4827            imageBounds.union(modifierBounds);
4828
4829            //shift points if needed////////////////////////////////////////
4830            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4831            {
4832                int shiftX = Math.round(Math.abs(imageBounds.left)),
4833                        shiftY = Math.round(Math.abs(imageBounds.top));
4834
4835                //shift mobility points
4836                int size = tiArray.size();
4837                TextInfo tempShape = null;
4838                for (int i = 0; i < size; i++)
4839                {
4840                    tempShape = tiArray.get(i);
4841                    tempShape.shift(shiftX, shiftY);
4842                }
4843                RectUtilities.shift(modifierBounds, shiftX, shiftY);
4844                //modifierBounds.shift(shiftX,shiftY);
4845
4846                //shift image points
4847                centerPoint.offset(shiftX, shiftY);
4848                RectUtilities.shift(symbolBounds, shiftX, shiftY);
4849                RectUtilities.shift(imageBounds, shiftX, shiftY);
4850                RectUtilities.shift(imageBoundsOld, shiftX, shiftY);
4851                /*centerPoint.shift(shiftX, shiftY);
4852                 symbolBounds.shift(shiftX, shiftY);
4853                 imageBounds.shift(shiftX, shiftY);
4854                 imageBoundsOld.shift(shiftX, shiftY);//*/
4855            }
4856
4857            if (attributes != null && attributes.containsKey(MilStdAttributes.TextColor))
4858            {
4859                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4860                if(alpha > -1)
4861                    textColor.setAlpha(alpha);
4862            }
4863            if (attributes != null && attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4864            {
4865                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4866                if(alpha > -1)
4867                    textBackgroundColor.setAlpha(alpha);
4868            }
4869
4870            if(sdi instanceof ImageInfo)
4871            {
4872                ii = (ImageInfo) sdi;
4873
4874                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4875                Canvas ctx = new Canvas(bmp);
4876
4877                //render////////////////////////////////////////////////////////
4878                //draw original icon with potential modifiers.
4879                ctx.drawBitmap(ii.getImage(), imageBoundsOld.left, imageBoundsOld.top, null);
4880                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4881
4882                renderText(ctx, tiArray, textColor, textBackgroundColor, modifierFont);
4883
4884                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4885            }
4886            else if(sdi instanceof SVGSymbolInfo)
4887            {
4888                ssi = (SVGSymbolInfo)sdi;
4889                StringBuilder sb = new StringBuilder();
4890                sb.append(ssi.getSVG());
4891                sb.append(renderTextElements(tiArray,textColor,textBackgroundColor));
4892                newsdi = new SVGSymbolInfo(sb.toString(),centerPoint,symbolBounds,imageBounds);
4893            }
4894        }
4895
4896        if(newsdi == null)
4897            newsdi = sdi;
4898
4899        return newsdi;
4900    }
4901    private static String renderTextElement(ArrayList<TextInfo> tiArray, Color color, Color backgroundColor)
4902    {
4903        StringBuilder sbSVG = new StringBuilder();
4904
4905        String svgStroke = RendererUtilities.colorToHexString(RendererUtilities.getIdealOutlineColor(color),false);
4906        if(backgroundColor != null)
4907            svgStroke = RendererUtilities.colorToHexString(backgroundColor,false);
4908
4909        String svgFill = RendererUtilities.colorToHexString(color,false);
4910        String svgStrokeWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
4911        for (TextInfo ti : tiArray) {
4912            sbSVG.append(Shape2SVG.Convert(ti, svgStroke,svgFill,svgStrokeWidth,null,null,null));
4913            sbSVG.append("\n");
4914        }
4915
4916        return sbSVG.toString();
4917    }
4918
4919    private static String renderTextElements(ArrayList<TextInfo> tiArray, Color color, Color backgroundColor)
4920    {
4921        String style = null;
4922        String name = tiArray.get(0).getFontName();//"SansSerif";
4923        if(!name.endsWith("serif"))
4924            name += ", sans-serif";
4925        String size = String.valueOf(tiArray.get(0).getFontSize());
4926        String weight = null;
4927        String anchor = null;//"start";
4928        if(tiArray.get(0).getFontStyle() == Typeface.BOLD)
4929            weight = "bold";
4930        StringBuilder sbSVG = new StringBuilder();
4931
4932        String svgStroke = RendererUtilities.colorToHexString(RendererUtilities.getIdealOutlineColor(color),false);
4933        if(backgroundColor != null)
4934            svgStroke = RendererUtilities.colorToHexString(backgroundColor,false);
4935
4936        String svgFill = RendererUtilities.colorToHexString(color,false);
4937        String svgStrokeWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
4938        sbSVG.append("\n<g");
4939        sbSVG.append(" font-family=\"").append(name).append('"');
4940        sbSVG.append(" font-size=\"").append(size).append("px\"");
4941        if(weight != null)
4942            sbSVG.append(" font-weight=\"").append(weight).append("\"");
4943        sbSVG.append(" alignment-baseline=\"alphabetic\"");//
4944        sbSVG.append(">");
4945
4946        for (TextInfo ti : tiArray) {
4947            sbSVG.append(Shape2SVG.ConvertForGroup(ti, svgStroke,svgFill,svgStrokeWidth,null,null,null));
4948            sbSVG.append("\n");
4949        }
4950        sbSVG.append("</g>\n");
4951
4952        return sbSVG.toString();
4953    }
4954    private static void renderText(Canvas ctx, ArrayList<TextInfo> tiArray, Color color, Color backgroundColor, Paint font)
4955    {
4956        ModifierRenderer.renderText(ctx, (TextInfo[]) tiArray.toArray(new TextInfo[0]), color, backgroundColor, font);
4957    }
4958
4959    /**
4960     * 
4961     * @param ctx
4962     * @param tiArray
4963     * @param color
4964     * @param backgroundColor 
4965     */
4966    public static void renderText(Canvas ctx, TextInfo[] tiArray, Color color, Color backgroundColor, Paint modifierFont)
4967    {
4968        /*for (TextInfo textInfo : tiArray) 
4969         {
4970         ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);    
4971         }*/
4972
4973        int size = tiArray.length;
4974
4975        int tbm = RS.getTextBackgroundMethod();
4976        int outlineWidth = RS.getTextOutlineWidth();
4977
4978        if (color == null)
4979        {
4980            color = Color.BLACK;
4981        }
4982
4983        Color outlineColor = null;
4984        
4985        if(backgroundColor != null)
4986            outlineColor = backgroundColor;
4987        else
4988            outlineColor = RendererUtilities.getIdealOutlineColor(color);
4989
4990        if (tbm == RendererSettings.TextBackgroundMethod_OUTLINE_QUICK)
4991        {
4992            synchronized (modifierFontMutex) {
4993                //draw text outline
4994                modifierFont.setStyle(Style.FILL);
4995                modifierFont.setStrokeWidth(RS.getTextOutlineWidth());
4996                modifierFont.setColor(outlineColor.toInt());
4997
4998                if (outlineWidth > 2)
4999                    outlineWidth = 2;
5000
5001                if (outlineWidth > 0) {
5002                    for (int i = 0; i < size; i++) {
5003                        TextInfo textInfo = tiArray[i];
5004                        if (outlineWidth > 0) {
5005                            for (int j = 1; j <= outlineWidth; j++) {
5006                                if (j == 1) {
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                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y + j, modifierFont);
5011
5012                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y, modifierFont);
5013                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y, modifierFont);
5014
5015                                } else {
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                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y + j, modifierFont);
5020
5021                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y, modifierFont);
5022                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y, modifierFont);
5023
5024                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y + j, modifierFont);
5025                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y - j, modifierFont);
5026                                }
5027
5028                            }
5029
5030                        }
5031
5032                    }
5033                }
5034                //draw text
5035                modifierFont.setColor(color.toInt());
5036
5037                for (int j = 0; j < size; j++) {
5038                    TextInfo textInfo = tiArray[j];
5039                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5040                /*Paint outline = new Paint();
5041                 outline.setStyle(Style.STROKE);
5042                 outline.setColor(Color.red.toInt());
5043                 outline.setAlpha(155);
5044                 outline.setStrokeWidth(1f);
5045                 ctx.drawRect(textInfo.getTextBounds(), outline);
5046                 outline.setColor(Color.blue.toInt());
5047                 ctx.drawRect(textInfo.getTextOutlineBounds(), outline);//*/
5048                }
5049            }
5050        }
5051        else if (tbm == RendererSettings.TextBackgroundMethod_OUTLINE)
5052        {
5053            synchronized (modifierFontMutex) {
5054                //draw text outline
5055                //draw text outline
5056                modifierFont.setStyle(Style.STROKE);
5057                modifierFont.setStrokeWidth(RS.getTextOutlineWidth());
5058                modifierFont.setColor(outlineColor.toInt());
5059                if (outlineWidth > 0) {
5060                    for (int i = 0; i < size; i++) {
5061                        TextInfo textInfo = tiArray[i];
5062                        ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5063                    }
5064                }
5065                //draw text
5066                modifierFont.setColor(color.toInt());
5067                modifierFont.setStyle(Style.FILL);
5068                for (int j = 0; j < size; j++) {
5069                    TextInfo textInfo = tiArray[j];
5070                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5071                }
5072            }
5073        }
5074        else if (tbm == RendererSettings.TextBackgroundMethod_COLORFILL)
5075        {
5076            synchronized (modifierFontMutex) {
5077                Paint rectFill = new Paint();
5078                rectFill.setStyle(Paint.Style.FILL);
5079                rectFill.setColor(outlineColor.toARGB());
5080
5081
5082                //draw rectangle
5083                for (int k = 0; k < size; k++) {
5084                    TextInfo textInfo = tiArray[k];
5085                    ctx.drawRect(textInfo.getTextOutlineBounds(), rectFill);
5086                }
5087                //draw text
5088                modifierFont.setColor(color.toInt());
5089                modifierFont.setStyle(Style.FILL);
5090                for (int j = 0; j < size; j++) {
5091                    TextInfo textInfo = tiArray[j];
5092                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5093                }
5094            }
5095        }
5096        else if (tbm == RendererSettings.TextBackgroundMethod_NONE)
5097        {
5098            synchronized (modifierFontMutex) {
5099                modifierFont.setColor(color.toInt());
5100                modifierFont.setStyle(Style.FILL);
5101                for (int j = 0; j < size; j++) {
5102                    TextInfo textInfo = tiArray[j];
5103                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5104                }
5105            }
5106        }
5107    }
5108
5109    /**
5110     *
5111     * @param symbolID
5112     * @param modifiers
5113     * @return int[] where {xposition (-1 left, 0 centered, 1 right), yposition (0 centered, 1+ goes up, 1- goes down),
5114     * centered (0-no, 1-yes)} -999 means passed modifier is not supported by this symbol
5115     */
5116    private static List<Modifier> getLabelPositionIndexes(String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
5117    {
5118        List<Modifier> mods = null;
5119        if(modifiers != null && !modifiers.isEmpty())
5120            mods = new ArrayList<>();
5121        else
5122            return null;
5123
5124        int ver = SymbolID.getVersion(symbolID);
5125        int ss = SymbolID.getSymbolSet(symbolID);
5126        int x = 0;
5127        int y = 0;
5128        boolean centered = true;
5129        int p = RendererSettings.getInstance().getSPModifierPlacement();
5130        boolean strict = (RendererSettings.getInstance().getSPModifierPlacement() == RendererSettings.ModifierPlacement_STRICT);
5131        if(attributes != null && attributes.containsKey(MilStdAttributes.ModifierPlacement))
5132        {
5133            String mp = attributes.get(MilStdAttributes.ModifierPlacement);
5134            if(mp.equals("0") || mp.equals("1") || mp.equals("2"))
5135            {
5136                p = Integer.parseInt(mp);
5137                if(p == 0)
5138                    strict = true;
5139                else
5140                    strict = false;
5141            }
5142        }
5143        String temp = null;
5144        String sep = " ";
5145        if(ss == SymbolID.SymbolSet_DismountedIndividuals) {
5146            ver = SymbolID.Version_2525E;
5147        }
5148
5149        if(ver < SymbolID.Version_2525E)
5150        {
5151            if(ss == SymbolID.SymbolSet_LandUnit ||
5152                    ss == SymbolID.SymbolSet_LandCivilianUnit_Organization)
5153            {
5154
5155                //Only Command & Control has AA; ec.equals("110000").  Always in the middle of the unit.
5156                if(modifiers.containsKey(Modifiers.AA_SPECIAL_C2_HQ))
5157                {
5158                    temp = modifiers.get(Modifiers.AA_SPECIAL_C2_HQ);
5159                    if(temp != null && !temp.isEmpty())
5160                        mods.add(new Modifier("AA", temp, 0, 0, true));
5161                }
5162
5163                //Do top center label
5164                x = 0;//centered
5165                y = 9;//on top of symbol
5166                if(modifiers.containsKey(Modifiers.B_ECHELON))
5167                {
5168                    temp = modifiers.get(Modifiers.B_ECHELON);
5169                    if(temp != null && !temp.isEmpty())
5170                        mods.add(new Modifier("B", temp, x, y, centered));
5171                }
5172
5173                //Do right side labels
5174                x = 1;//on right
5175                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5176                {
5177                    y = 0;//center
5178                    centered = true;//vertically centered, only matters for labels on left and right side
5179                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5180                    if(temp != null && !temp.isEmpty())
5181                        mods.add(new Modifier("H", temp, x, y, centered));
5182                }
5183                else if(!strict)
5184                {
5185                    //if no "H', bring G and M closer to the center
5186                    centered = false;
5187                }
5188
5189                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5190                {
5191                    y = 1;//above center
5192                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5193                    if(temp != null && !temp.isEmpty())
5194                        mods.add(new Modifier("G", temp, x, y, centered));
5195                }
5196
5197                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
5198                {
5199                    y = 2;
5200                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5201                        y--;
5202                    temp = "";
5203                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
5204                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
5205                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5206                        temp += modifiers.get(Modifiers.AS_COUNTRY);
5207                    temp = temp.trim();
5208                    if(temp != null && !temp.isEmpty())
5209                        mods.add(new Modifier("F AS", temp, x, y, centered));
5210                }
5211
5212                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
5213                {
5214                    y = -1;//below center
5215                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
5216                    if(temp != null && !temp.isEmpty())
5217                        mods.add(new Modifier("M", temp, x, y, centered));
5218                }
5219
5220                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5221                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
5222                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5223                {
5224                    y = -2;
5225                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
5226                        y++;
5227                    temp = "";
5228                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5229                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5230                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
5231                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
5232                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5233                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5234                    temp = temp.trim();
5235                    if(temp != null && !temp.isEmpty())
5236                        mods.add(new Modifier("J K P", temp, x, y, centered));
5237                }
5238
5239                //Do left side labels
5240                x = -1;//on left
5241                centered = false;
5242
5243                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5244                {
5245                    y = 1;
5246                    temp = "";
5247                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5248                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5249                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5250                        temp += modifiers.get(Modifiers.Y_LOCATION);
5251
5252                    temp = temp.trim();
5253                    if(temp != null && !temp.isEmpty())
5254                        mods.add(new Modifier("X Y", temp, x, y, centered));
5255                }
5256
5257                if(modifiers.containsKey(Modifiers.W_DTG_1))
5258                {
5259                    y = 2;//above center
5260                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
5261                        y--;
5262                    temp = modifiers.get(Modifiers.W_DTG_1);
5263                    if(temp != null && !temp.isEmpty())
5264                        mods.add(new Modifier("W", temp, x, y, centered));
5265                }
5266
5267                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5268                {
5269                    y = -1;//below center
5270                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5271                    if(temp != null && !temp.isEmpty())
5272                        mods.add(new Modifier("T", temp, x, y, centered));
5273                }
5274
5275                if(modifiers.containsKey(Modifiers.Z_SPEED))
5276                {
5277                    y = -2;
5278                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5279                        y++;
5280                    temp = modifiers.get(Modifiers.Z_SPEED);
5281                    if(temp != null && !temp.isEmpty())
5282                        mods.add(new Modifier(Modifiers.J_EVALUATION_RATING, temp, x, y, centered));
5283                }
5284            }
5285            else if(ss == SymbolID.SymbolSet_LandEquipment ||
5286                    ss == SymbolID.SymbolSet_SignalsIntelligence_Land)
5287            {
5288                //Do top center label
5289                x = 0;//centered
5290                y = 9;//on top of symbol
5291                if(modifiers.containsKey(Modifiers.C_QUANTITY))
5292                {
5293                    temp = modifiers.get(Modifiers.C_QUANTITY);
5294                    if(temp != null && !temp.isEmpty())
5295                        mods.add(new Modifier("C", temp, x, y, centered));
5296                }
5297
5298                //Do right side labels
5299                x = 1;//on right
5300                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
5301                {
5302                    y = 0;//center
5303                    centered = true;//vertically centered, only matters for labels on left and right side
5304                    temp = "";
5305                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5306                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
5307                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
5308                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
5309                    temp = temp.trim();
5310                    if(temp != null && !temp.isEmpty())
5311                        mods.add(new Modifier("H AF", temp, x, y, centered));
5312                }
5313                else if(!strict)
5314                {
5315                    //if no "H', bring G and M closer to the center
5316                    centered = false;
5317                }
5318
5319                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5320                {
5321                    y = 1;//above center
5322                    temp = "";
5323                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5324                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5325                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5326                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
5327                    temp = temp.trim();
5328                    if(temp != null && !temp.isEmpty())
5329                        mods.add(new Modifier("G AQ", temp, x, y, centered));
5330                }
5331
5332                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5333                {
5334                    y = 2;
5335                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
5336                        y--;
5337
5338                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5339                    if(temp != null && !temp.isEmpty())
5340                        mods.add(new Modifier("AS", temp, x, y, centered));
5341                }
5342
5343                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5344                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
5345                        modifiers.containsKey(Modifiers.N_HOSTILE) ||
5346                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5347                {
5348                    y = -1;
5349
5350                    temp = "";
5351                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5352                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5353                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
5354                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
5355                    if(modifiers.containsKey(Modifiers.N_HOSTILE))
5356                        temp += modifiers.get(Modifiers.N_HOSTILE) + sep;
5357                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5358                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5359                    temp = temp.trim();
5360                    if(temp != null && !temp.isEmpty())
5361                        mods.add(new Modifier("J L N P", temp, x, y, centered));
5362                }
5363
5364                //Do left side labels
5365                x = -1;//on left
5366
5367                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
5368                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
5369                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
5370                {
5371                    y = 0;//center
5372                    centered = true;//vertically centered, only matters for labels on left and right side
5373
5374                    temp = "";
5375                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5376                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
5377                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
5378                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
5379                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
5380                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
5381                    temp = temp.trim();
5382                    if(temp != null && !temp.isEmpty())
5383                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
5384                }
5385                else if(!strict)
5386                {
5387                    centered = false;
5388                }
5389
5390                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5391                {
5392                    y = 1;
5393                    temp = "";
5394                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5395                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5396                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5397                        temp += modifiers.get(Modifiers.Y_LOCATION);
5398
5399                    temp = temp.trim();
5400                    mods.add(new Modifier("X Y", temp, x, y, centered));
5401                }
5402
5403                if(modifiers.containsKey(Modifiers.W_DTG_1) || modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5404                {
5405                    y = 2;//above center
5406                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
5407                        y--;
5408
5409                    temp = modifiers.get(Modifiers.W_DTG_1);
5410
5411                    if(temp != null && !temp.isEmpty())
5412                        mods.add(new Modifier("W", temp, x, y, centered));
5413                }
5414
5415                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5416                {
5417                    y = -1;//below center
5418                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5419                    if(temp != null && !temp.isEmpty())
5420                        mods.add(new Modifier("T", temp, x, y, centered));
5421                }
5422
5423                if(modifiers.containsKey(Modifiers.Z_SPEED))
5424                {
5425                    y = -2;
5426                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5427                        y++;
5428                    temp = modifiers.get(Modifiers.Z_SPEED);
5429                    if(temp != null && !temp.isEmpty())
5430                        mods.add(new Modifier("Z", temp, x, y, centered));
5431                }
5432            }
5433            else if(ss == SymbolID.SymbolSet_LandInstallation)
5434            {
5435                //No top center label
5436
5437                //Do right side labels
5438                x = 1;//on right
5439
5440                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5441                {
5442                    y = 0;//center
5443                    centered = true;//vertically centered, only matters for labels on left and right side
5444                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5445
5446                    if(temp != null && !temp.isEmpty())
5447                        mods.add(new Modifier("H", temp, x, y, centered));
5448                }
5449                else if(!strict)
5450                {
5451                    centered = false;
5452                }
5453
5454                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5455                {
5456                    y = 1;//above center
5457                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5458
5459                    if(temp != null && !temp.isEmpty())
5460                        mods.add(new Modifier("G", temp, x, y, centered));
5461                }
5462
5463                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5464                {
5465                    y = 2;
5466                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5467                        y--;
5468
5469                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5470                    if(temp != null && !temp.isEmpty())
5471                        mods.add(new Modifier("AS", temp, x, y, centered));
5472                }
5473
5474                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5475                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
5476                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5477                {
5478                    y = -1;
5479
5480                    temp = "";
5481                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5482                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5483                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
5484                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
5485                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5486                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5487                    temp = temp.trim();
5488                    mods.add(new Modifier("J K P", temp, x, y, centered));
5489                }
5490
5491                //Do left side labels
5492                x = -1;//on left
5493
5494                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5495                {
5496                    y = 0;//center
5497                    centered = true;//vertically centered, only matters for labels on left and right side
5498
5499                    temp = "";
5500                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5501                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5502                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5503                        temp += modifiers.get(Modifiers.Y_LOCATION);
5504                    temp = temp.trim();
5505                    if(temp != null && !temp.isEmpty())
5506                        mods.add(new Modifier("X Y", temp, x, y, centered));
5507                }
5508                else if(!strict)
5509                {
5510                    centered = false;
5511                }
5512
5513                if(modifiers.containsKey(Modifiers.W_DTG_1))
5514                {
5515                    y = 1;//above center
5516
5517                    temp = modifiers.get(Modifiers.W_DTG_1);
5518
5519                    if(temp != null && !temp.isEmpty())
5520                        mods.add(new Modifier("W AR", temp, x, y, centered));
5521                }
5522
5523                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5524                {
5525                    y = -1;//below center
5526                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5527                    if(temp != null && !temp.isEmpty())
5528                        mods.add(new Modifier("T", temp, x, y, centered));
5529                }
5530            }
5531            else if(ss == SymbolID.SymbolSet_Air ||
5532                    ss == SymbolID.SymbolSet_AirMissile ||
5533                    ss == SymbolID.SymbolSet_SignalsIntelligence_Air)
5534            {
5535                //No top center label
5536
5537
5538                //Do right side labels
5539                x = 1;//on right
5540                centered = false;
5541
5542                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5543                {
5544                    y = 1;//above center
5545                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
5546
5547                    if(temp != null && !temp.isEmpty())
5548                        mods.add(new Modifier("P", temp, x, y, centered));
5549                }
5550
5551                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5552                {
5553                    y = 2;
5554                    if(!strict && !modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5555                        y--;
5556                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5557
5558                    if(temp != null && !temp.isEmpty())
5559                        mods.add(new Modifier("T", temp, x, y, centered));
5560                }
5561
5562                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5563                {
5564                    y = 3;
5565                    if(!strict)
5566                    {
5567                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5568                            y--;
5569                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5570                            y--;
5571                    }
5572
5573                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5574
5575                    if(temp != null && !temp.isEmpty())
5576                        mods.add(new Modifier("AS", temp, x, y, centered));
5577                }
5578
5579                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5580                {
5581                    y = -1;//below center
5582                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5583
5584                    if(temp != null && !temp.isEmpty())
5585                        mods.add(new Modifier("V", temp, x, y, centered));
5586                }
5587
5588                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5589                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5590                {
5591                    y = -2;//below center
5592                    if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5593                        y++;
5594
5595                    temp = "";
5596                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5597                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5598                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5599                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5600                    temp = temp.trim();
5601
5602                    if(temp != null && !temp.isEmpty())
5603                        mods.add(new Modifier("Z X", temp, x, y, centered));
5604                }
5605
5606                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5607                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5608                {
5609                    y = -3;
5610                    if(!strict)
5611                    {
5612                        if(!(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5613                                modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5614                            y++;
5615                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5616                            y++;
5617                    }
5618                    temp = "";
5619                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5620                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5621                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5622                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5623                    temp = temp.trim();
5624                    if(temp != null && !temp.isEmpty())
5625                        mods.add(new Modifier("G H", temp, x, y, centered));
5626                }
5627
5628                //No left side labels
5629
5630            }
5631            else if(ss == SymbolID.SymbolSet_Space ||
5632                    ss == SymbolID.SymbolSet_SpaceMissile ||
5633                    ss == SymbolID.SymbolSet_SignalsIntelligence_Space)
5634            {
5635                //No top center label
5636
5637
5638                //Do right side labels
5639                x = 1;//on right
5640                centered = false;
5641
5642                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5643                {
5644                    y = 1;//above center
5645                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5646                    if(temp != null && !temp.isEmpty())
5647                        mods.add(new Modifier("V", temp, x, y, centered));
5648                }
5649
5650                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5651                {
5652                    y = 2;
5653                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5654                        y--;
5655                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5656
5657                    if(temp != null && !temp.isEmpty())
5658                        mods.add(new Modifier("T", temp, x, y, centered));
5659                }
5660
5661                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5662                {
5663                    y = 3;
5664                    if(!strict)
5665                    {
5666                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5667                            y--;
5668                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5669                            y--;
5670                    }
5671
5672                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5673
5674                    if(temp != null && !temp.isEmpty())
5675                        mods.add(new Modifier("AS", temp, x, y, centered));
5676                }
5677
5678                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5679                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5680                {
5681                    y = -1;//below center
5682                    temp = "";
5683                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5684                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5685                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5686                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5687                    temp = temp.trim();
5688
5689                    if(temp != null && !temp.isEmpty())
5690                        mods.add(new Modifier("Z X", temp, x, y, centered));
5691                }
5692
5693                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5694                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5695                {
5696                    y = -2;
5697                    if(!strict &&
5698                            !(modifiers.containsKey(Modifiers.Z_SPEED) || modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5699                        y++;
5700                    temp = "";
5701                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5702                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5703                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5704                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5705                    temp = temp.trim();
5706                    if(temp != null && !temp.isEmpty())
5707                        mods.add(new Modifier("G H", temp, x, y, centered));
5708                }
5709
5710                //No left side labels
5711            }
5712            else if(ss == SymbolID.SymbolSet_SeaSurface ||
5713                    ss == SymbolID.SymbolSet_SignalsIntelligence_SeaSurface)
5714            {
5715                //No top center label
5716
5717
5718                //Do right side labels
5719                x = 1;//on right
5720                centered = true;
5721                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5722                {
5723                    y = 0;//center
5724                    centered = true;//vertically centered, only matters for labels on left and right side
5725                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5726                    if(temp != null && !temp.isEmpty())
5727                        mods.add(new Modifier("V", temp, x, y, centered));
5728                }
5729                else if(!strict)
5730                {
5731                    //if no "H', bring G and M closer to the center
5732                    centered = false;
5733                }
5734
5735                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5736                {
5737                    y = 1;//above center
5738                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
5739                    if(temp != null && !temp.isEmpty())
5740                        mods.add(new Modifier("P", temp, x, y, centered));
5741                }
5742
5743                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5744                {
5745                    y = 2;
5746                    if(!strict && !modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5747                        y--;
5748                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5749
5750                    if(temp != null && !temp.isEmpty())
5751                        mods.add(new Modifier("T", temp, x, y, centered));
5752                }
5753
5754                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5755                {
5756                    y = 3;
5757                    if(!strict)
5758                    {
5759                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5760                            y--;
5761                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5762                            y--;
5763                    }
5764
5765                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5766
5767                    if(temp != null && !temp.isEmpty())
5768                        mods.add(new Modifier("AS", temp, x, y, centered));
5769                }
5770
5771                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5772                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5773                {
5774                    y = -1;//below center
5775                    temp = "";
5776                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5777                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5778                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5779                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5780                    temp = temp.trim();
5781
5782                    if(temp != null && !temp.isEmpty())
5783                        mods.add(new Modifier("Z X", temp, x, y, centered));
5784                }
5785
5786                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5787                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5788                {
5789                    y = -2;
5790                    if(!strict &&
5791                            !(modifiers.containsKey(Modifiers.Z_SPEED) || modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5792                        y++;
5793                    temp = "";
5794                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5795                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5796                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5797                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5798                    temp = temp.trim();
5799                    if(temp != null && !temp.isEmpty())
5800                        mods.add(new Modifier("G H", temp, x, y, centered));
5801                }
5802
5803                //Do left side labels
5804                x = -1;
5805                centered = false;
5806                if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT) || modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5807                {
5808                    y = 3;//above center
5809                    if(!strict)
5810                        y--;
5811
5812                    temp = "";
5813                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5814                        temp = modifiers.get(Modifiers.AQ_GUARDED_UNIT) + sep;
5815                    if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5816                        temp += modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
5817                    temp = temp.trim();
5818
5819                    if(temp != null && !temp.isEmpty())
5820                        mods.add(new Modifier("AQ AR", temp, x, y, centered));
5821                }
5822            }
5823            else if(ss == SymbolID.SymbolSet_SeaSubsurface ||
5824                    ss == SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface)
5825            {
5826                //No top center label
5827
5828
5829                //Do right side labels
5830                x = 1;//on right
5831                centered = false;
5832                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5833                {
5834                    y = 1;//center
5835                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5836                    if(temp != null && !temp.isEmpty())
5837                        mods.add(new Modifier("V", temp, x, y, centered));
5838                }
5839
5840                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5841                {
5842                    y = 2;
5843                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5844                        y--;
5845                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5846
5847                    if(temp != null && !temp.isEmpty())
5848                        mods.add(new Modifier("T", temp, x, y, centered));
5849                }
5850
5851                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5852                {
5853                    y = 3;
5854                    if(!strict)
5855                    {
5856                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5857                            y--;
5858                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5859                            y--;
5860                    }
5861
5862                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5863
5864                    if(temp != null && !temp.isEmpty())
5865                        mods.add(new Modifier("AS", temp, x, y, centered));
5866                }
5867
5868                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5869                {
5870                    y = -1;//below center
5871
5872                    temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5873
5874                    if(temp != null && !temp.isEmpty())
5875                        mods.add(new Modifier("X", temp, x, y, centered));
5876                }
5877
5878                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5879                {
5880                    y = -2;
5881                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5882                        y++;
5883                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5884
5885                    if(temp != null && !temp.isEmpty())
5886                        mods.add(new Modifier("G", temp, x, y, centered));
5887                }
5888
5889                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5890                {
5891                    y = -3;//below center
5892                    if(!strict)
5893                    {
5894                        if(!modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5895                            y++;
5896                        if(!modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5897                            y++;
5898                    }
5899
5900                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5901
5902                    if(temp != null && !temp.isEmpty())
5903                        mods.add(new Modifier("H", temp, x, y, centered));
5904                }
5905
5906                //Do left side labels
5907                x = -1;
5908                centered = false;
5909                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5910                {
5911                    y = 3;//above center
5912                    if(!strict)
5913                    {
5914                        y--;
5915                    }
5916
5917                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
5918
5919                    if(temp != null && !temp.isEmpty())
5920                        mods.add(new Modifier("AR", temp, x, y, centered));
5921                }
5922
5923            }
5924            else if(ss == SymbolID.SymbolSet_Activities)
5925            {
5926                //No top center label
5927
5928                //Do right side labels
5929                x = 1;//on right
5930                centered = false;
5931
5932                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5933                {
5934                    y = 1;
5935
5936                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5937                    if(temp != null && !temp.isEmpty())
5938                        mods.add(new Modifier("G", temp, x, y, centered));
5939                }
5940
5941                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5942                {
5943                    y = 2;
5944                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5945                        y--;
5946                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5947
5948                    if(temp != null && !temp.isEmpty())
5949                        mods.add(new Modifier("AS", temp, x, y, centered));
5950                }
5951
5952                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5953                {
5954                    y = -1;//below center
5955                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5956                    if(temp != null && !temp.isEmpty())
5957                        mods.add(new Modifier("H", temp, x, y, centered));
5958                }
5959
5960                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5961                {
5962                    y = -2;
5963                    if(!strict && !modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5964                        y++;
5965                    temp = temp = modifiers.get(Modifiers.J_EVALUATION_RATING);
5966
5967                    if(temp != null && !temp.isEmpty())
5968                        mods.add(new Modifier("J", temp, x, y, centered));
5969                }
5970
5971                //Do left side labels
5972                x = -1;//on left
5973                centered = false;
5974
5975                if(modifiers.containsKey(Modifiers.Y_LOCATION))
5976                {
5977                    y = 1;
5978                    temp = modifiers.get(Modifiers.Y_LOCATION);
5979
5980                    if(temp != null && !temp.isEmpty())
5981                        mods.add(new Modifier("Y", temp, x, y, centered));
5982                }
5983
5984                if(modifiers.containsKey(Modifiers.W_DTG_1))
5985                {
5986                    y = 2;//above center
5987                    if(!strict && !modifiers.containsKey(Modifiers.Y_LOCATION))
5988                        y--;
5989                    temp = modifiers.get(Modifiers.W_DTG_1);
5990                    if(temp != null && !temp.isEmpty())
5991                        mods.add(new Modifier("W", temp, x, y, centered));
5992                }
5993
5994            }
5995            else if(ss == SymbolID.SymbolSet_CyberSpace)
5996            {
5997                //Do top center label
5998                x = 0;//centered
5999                y = 9;//on top of symbol
6000                if(modifiers.containsKey(Modifiers.B_ECHELON))
6001                {
6002                    temp = modifiers.get(Modifiers.B_ECHELON);
6003                    if(temp != null && !temp.isEmpty())
6004                        mods.add(new Modifier("B", temp, x, y, centered));
6005                }
6006
6007                //Do right side labels
6008                x = 1;//on right
6009                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6010                {
6011                    y = 0;//center
6012                    centered = true;//vertically centered, only matters for labels on left and right side
6013                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6014                    if(temp != null && !temp.isEmpty())
6015                        mods.add(new Modifier("H", temp, x, y, centered));
6016                }
6017                else if(!strict)
6018                {
6019                    //if no "H', bring G and M closer to the center
6020                    centered = false;
6021                }
6022
6023                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6024                {
6025                    y = 1;//above center
6026                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
6027                    if(temp != null && !temp.isEmpty())
6028                        mods.add(new Modifier("G", temp, x, y, centered));
6029                }
6030
6031                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
6032                {
6033                    y = 2;
6034                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6035                        y--;
6036                    temp = "";
6037                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
6038                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
6039                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6040                        temp += modifiers.get(Modifiers.AS_COUNTRY);
6041                    temp = temp.trim();
6042                    if(temp != null && !temp.isEmpty())
6043                        mods.add(new Modifier("F AS", temp, x, y, centered));
6044                }
6045
6046                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6047                {
6048                    y = -1;//below center
6049                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6050                    if(temp != null && !temp.isEmpty())
6051                        mods.add(new Modifier("M", temp, x, y, centered));
6052                }
6053
6054                if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6055                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6056                {
6057                    y = -2;
6058                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6059                        y++;
6060                    temp = "";
6061                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6062                        temp = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6063                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6064                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
6065
6066                    temp = temp.trim();
6067                    if(temp != null && !temp.isEmpty())
6068                        mods.add(new Modifier("K L", temp, x, y, centered));
6069                }
6070
6071                //Do left side labels
6072                x = -1;//on left
6073                centered = true;
6074
6075                if(modifiers.containsKey(Modifiers.Y_LOCATION))
6076                {
6077                    y = 0;
6078                    temp = modifiers.get(Modifiers.Y_LOCATION);
6079
6080                    if(temp != null && !temp.isEmpty())
6081                        mods.add(new Modifier("Y", temp, x, y, centered));
6082                }
6083                else if (!strict)
6084                {
6085                    centered = false;
6086                }
6087
6088                if(modifiers.containsKey(Modifiers.W_DTG_1))
6089                {
6090                    y = 1;//above center
6091                    temp = modifiers.get(Modifiers.W_DTG_1);
6092                    if(temp != null && !temp.isEmpty())
6093                        mods.add(new Modifier("W", temp, x, y, centered));
6094                }
6095
6096                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6097                {
6098                    y = -1;//below center
6099                    temp = "";
6100                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6101                        temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1) + sep;
6102                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6103                        temp += modifiers.get(Modifiers.V_EQUIP_TYPE);
6104
6105                    temp = temp.trim();
6106                    if(temp != null && !temp.isEmpty())
6107                        mods.add(new Modifier("T V", temp, x, y, centered));
6108                }
6109
6110            }
6111            /*else if(ver == SymbolID.SymbolSet_MineWarfare)
6112            {
6113                //no modifiers
6114            }//*/
6115            //else//SymbolSet Unknown
6116            //processUnknownTextModifiers
6117        }
6118        else// if(ver >= SymbolID.Version_2525E)
6119        {
6120            int fs = SymbolID.getFrameShape(symbolID);
6121            if(ss == SymbolID.SymbolSet_LandUnit ||
6122                    ss == SymbolID.SymbolSet_LandCivilianUnit_Organization ||
6123                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_LandUnit))
6124            {
6125
6126                //Only Command & Control has AA; ec.equals("110000").  Always in the middle of the unit.
6127                if(modifiers.containsKey(Modifiers.AA_SPECIAL_C2_HQ))
6128                {
6129                    temp = modifiers.get(Modifiers.AA_SPECIAL_C2_HQ);
6130                    if(temp != null && !temp.isEmpty())
6131                        mods.add(new Modifier("AA", temp, 0, 0, true));
6132                }
6133                
6134                //Do top center label
6135                x = 0;//centered
6136                y = 9;//on top of symbol
6137                if(modifiers.containsKey(Modifiers.B_ECHELON))
6138                {
6139                    temp = modifiers.get(Modifiers.B_ECHELON);
6140                    if(temp != null && !temp.isEmpty())
6141                        mods.add(new Modifier("B", temp, x, y, centered));
6142                }
6143
6144                //Do right side labels
6145                x = 1;//on right
6146                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6147                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6148                {
6149                    y = 0;//center
6150                    centered = true;//vertically centered, only matters for labels on left and right side
6151                    temp = "";
6152                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6153                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6154                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6155                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6156                    temp = temp.trim();
6157                    if(temp != null && !temp.isEmpty())
6158                        mods.add(new Modifier("H AF", temp, x, y, centered));
6159                }
6160                else if(!strict)
6161                {
6162                    //if no "H', bring G and M closer to the center
6163                    centered = false;
6164                }
6165
6166                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6167                {
6168                    y = 1;//above center
6169                    temp = "";
6170                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6171                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6172                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6173                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6174                    temp = temp.trim();
6175                    if(temp != null && !temp.isEmpty())
6176                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6177                }
6178
6179                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
6180                {
6181                    y = 2;
6182                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6183                        y--;
6184                    temp = "";
6185                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
6186                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
6187                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6188                        temp += modifiers.get(Modifiers.AS_COUNTRY);
6189                    temp = temp.trim();
6190                    if(temp != null && !temp.isEmpty())
6191                        mods.add(new Modifier("F AS", temp, x, y, centered));
6192                }
6193
6194                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6195                {
6196                    y = -1;//below center
6197                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6198                    if(temp != null && !temp.isEmpty())
6199                        mods.add(new Modifier("M", temp, x, y, centered));
6200                }
6201
6202                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6203                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6204                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
6205                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6206                {
6207                    y = -2;
6208                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6209                        y++;
6210                    temp = "";
6211                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6212                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6213                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6214                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6215                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6216                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
6217                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6218                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6219                    temp = temp.trim();
6220                    if(temp != null && !temp.isEmpty())
6221                        mods.add(new Modifier("J K L P", temp, x, y, centered));
6222                }
6223
6224                //Do left side labels
6225                x = -1;//on left
6226
6227                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
6228                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
6229                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6230                {
6231                    y = 0;//center
6232                    centered = true;//vertically centered, only matters for labels on left and right side
6233
6234                    temp = "";
6235                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6236                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6237                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6238                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
6239                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6240                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6241                    temp = temp.trim();
6242                    if(temp != null && !temp.isEmpty())
6243                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
6244                }
6245                else if(!strict)
6246                {
6247                    centered = false;
6248                }
6249
6250                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6251                {
6252                    y = 1;
6253                    temp = "";
6254                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6255                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6256                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6257                        temp += modifiers.get(Modifiers.Y_LOCATION);
6258
6259                    temp = temp.trim();
6260                    mods.add(new Modifier("X Y", temp, x, y, centered));
6261                }
6262
6263                if(modifiers.containsKey(Modifiers.W_DTG_1))
6264                {
6265                    y = 2;//above center
6266                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6267                        y--;
6268
6269                    temp = modifiers.get(Modifiers.W_DTG_1);
6270
6271                    if(temp != null && !temp.isEmpty())
6272                        mods.add(new Modifier("W", temp, x, y, centered));
6273                }
6274
6275                if(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6276                {
6277                    y = -1;//below center
6278                    temp = "";
6279                    if(modifiers.containsKey(Modifiers.C_QUANTITY))
6280                        temp = modifiers.get(Modifiers.C_QUANTITY) + sep;
6281                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6282                        temp += modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6283
6284                    temp = temp.trim();
6285                    if(temp != null && !temp.isEmpty())
6286                        mods.add(new Modifier("C T", temp, x, y, centered));
6287                }
6288
6289                if(modifiers.containsKey(Modifiers.Z_SPEED))
6290                {
6291                    y = -2;
6292                    if(!strict && !(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
6293                        y++;
6294                    temp = modifiers.get(Modifiers.Z_SPEED);
6295                    if(temp != null && !temp.isEmpty())
6296                        mods.add(new Modifier("Z", temp, x, y, centered));
6297                }
6298            }
6299            else if(ss == SymbolID.SymbolSet_LandEquipment ||
6300                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_LandEquipment))
6301            {
6302                //Do top center label
6303                x = 0;//centered
6304                y = 9;//on top of symbol
6305                if(modifiers.containsKey(Modifiers.C_QUANTITY))
6306                {
6307                    temp = modifiers.get(Modifiers.C_QUANTITY);
6308                    if(temp != null && !temp.isEmpty())
6309                        mods.add(new Modifier("C", temp, x, y, centered));
6310                }
6311
6312                //Do right side labels
6313                x = 1;//on right
6314                centered = false;
6315
6316                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6317                {
6318                    y = 1;//above center
6319                    temp = "";
6320                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6321                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6322                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6323                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6324                    temp = temp.trim();
6325                    if(temp != null && !temp.isEmpty())
6326                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6327                }
6328
6329                if( modifiers.containsKey(Modifiers.AS_COUNTRY))
6330                {
6331                    y = 2;
6332                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6333                        y--;
6334                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6335
6336                    if(temp != null && !temp.isEmpty())
6337                        mods.add(new Modifier("AS", temp, x, y, centered));
6338                }
6339
6340                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6341                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6342                {
6343                    y = -1;
6344                    temp = "";
6345                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6346                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6347                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6348                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6349                    temp = temp.trim();
6350                    if(temp != null && !temp.isEmpty())
6351                        mods.add(new Modifier("H AF", temp, x, y, centered));
6352                }
6353
6354                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6355                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6356                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
6357                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6358                {
6359                    y = -2;
6360                    if(!strict && !(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6361                            modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER)))
6362                        y++;
6363                    temp = "";
6364                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6365                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6366                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6367                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6368                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6369                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
6370                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6371                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6372                    temp = temp.trim();
6373                    if(temp != null && !temp.isEmpty())
6374                        mods.add(new Modifier("J K L P", temp, x, y, centered));
6375                }
6376
6377                //Do left side labels
6378                x = -1;//on left
6379
6380                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
6381                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
6382                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6383                {
6384                    y = 0;//center
6385                    centered = true;//vertically centered, only matters for labels on left and right side
6386
6387                    temp = "";
6388                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6389                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6390                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6391                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
6392                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6393                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6394                    temp = temp.trim();
6395                    if(temp != null && !temp.isEmpty())
6396                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
6397                }
6398                else if(!strict)
6399                {
6400                    centered = false;
6401                }
6402
6403                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6404                {
6405                    y = 1;
6406                    temp = "";
6407                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6408                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6409                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6410                        temp += modifiers.get(Modifiers.Y_LOCATION);
6411
6412                    temp = temp.trim();
6413                    mods.add(new Modifier("X Y", temp, x, y, centered));
6414                }
6415
6416                if(modifiers.containsKey(Modifiers.W_DTG_1))
6417                {
6418                    y = 2;//above center
6419                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6420                        y--;
6421
6422                    temp = modifiers.get(Modifiers.W_DTG_1);
6423
6424                    if(temp != null && !temp.isEmpty())
6425                        mods.add(new Modifier("W", temp, x, y, centered));
6426                }
6427
6428                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6429                {
6430                    y = -1;//below center
6431                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6432
6433                    temp = temp.trim();
6434                    if(temp != null && !temp.isEmpty())
6435                        mods.add(new Modifier("T", temp, x, y, centered));
6436                }
6437
6438                if(modifiers.containsKey(Modifiers.Z_SPEED))
6439                {
6440                    y = -2;
6441                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6442                        y++;
6443                    temp = modifiers.get(Modifiers.Z_SPEED);
6444                    if(temp != null && !temp.isEmpty())
6445                        mods.add(new Modifier("Z", temp, x, y, centered));
6446                }
6447            }
6448            else if(ss == SymbolID.SymbolSet_LandInstallation)
6449            {
6450                //No top center label
6451
6452                //Do right side labels
6453                x = 1;//on right
6454                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6455                {
6456                    y = 0;//center
6457                    centered = true;//vertically centered, only matters for labels on left and right side
6458                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6459
6460                    if(temp != null && !temp.isEmpty())
6461                        mods.add(new Modifier("H", temp, x, y, centered));
6462                }
6463                else if(!strict)
6464                {
6465                    //if no "H', bring G and M closer to the center
6466                    centered = false;
6467                }
6468
6469                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6470                {
6471                    y = 1;//above center
6472                    temp = "";
6473                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6474                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6475                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6476                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6477                    temp = temp.trim();
6478                    if(temp != null && !temp.isEmpty())
6479                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6480                }
6481
6482                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6483                {
6484                    y = 2;
6485                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6486                        y--;
6487                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6488
6489                    if(temp != null && !temp.isEmpty())
6490                        mods.add(new Modifier("AS", temp, x, y, centered));
6491                }
6492
6493                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6494                {
6495                    y = -1;//below center
6496                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6497                    if(temp != null && !temp.isEmpty())
6498                        mods.add(new Modifier("M", temp, x, y, centered));
6499                }
6500
6501                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6502                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6503                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6504                {
6505                    y = -2;
6506                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6507                        y++;
6508                    temp = "";
6509                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6510                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6511                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6512                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6513                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6514                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6515                    temp = temp.trim();
6516                    if(temp != null && !temp.isEmpty())
6517                        mods.add(new Modifier("J K P", temp, x, y, centered));
6518                }
6519
6520                //Do left side labels
6521                x = -1;//on left
6522                centered = false;
6523
6524                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6525                {
6526                    y = 1;
6527                    temp = "";
6528                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6529                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6530                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6531                        temp += modifiers.get(Modifiers.Y_LOCATION);
6532
6533                    temp = temp.trim();
6534                    mods.add(new Modifier("X Y", temp, x, y, centered));
6535                }
6536
6537                if(modifiers.containsKey(Modifiers.W_DTG_1))
6538                {
6539                    y = 2;//above center
6540                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6541                        y--;
6542
6543                    temp = modifiers.get(Modifiers.W_DTG_1);
6544
6545                    if(temp != null && !temp.isEmpty())
6546                        mods.add(new Modifier("W", temp, x, y, centered));
6547                }
6548
6549                if(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6550                {
6551                    y = -1;//below center
6552                    temp = "";
6553                    if(modifiers.containsKey(Modifiers.C_QUANTITY))
6554                        temp = modifiers.get(Modifiers.C_QUANTITY) + sep;
6555                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6556                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6557
6558                    temp = temp.trim();
6559                    if(temp != null && !temp.isEmpty())
6560                        mods.add(new Modifier("C AE", temp, x, y, centered));
6561                }
6562
6563                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6564                {
6565                    y = -2;
6566                    if(!strict && !(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME)))
6567                        y++;
6568                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6569                    if(temp != null && !temp.isEmpty())
6570                        mods.add(new Modifier("T", temp, x, y, centered));
6571                }
6572            }
6573            else if(ss == SymbolID.SymbolSet_Space ||
6574                    ss == SymbolID.SymbolSet_SpaceMissile ||
6575                    ss == SymbolID.SymbolSet_Air ||
6576                    ss == SymbolID.SymbolSet_AirMissile ||
6577                    (ss == SymbolID.SymbolSet_SignalsIntelligence &&
6578                            (fs == SymbolID.FrameShape_Space || fs == SymbolID.FrameShape_Air)))
6579            {
6580                //No top center label
6581                x = 0;//centered
6582                y = 9;//on top of symbol
6583
6584                if(modifiers.containsKey(Modifiers.C_QUANTITY))
6585                {
6586                    temp = modifiers.get(Modifiers.C_QUANTITY);
6587                    if(temp != null && !temp.isEmpty())
6588                        mods.add(new Modifier("C", temp, x, y, centered));
6589                }
6590                else if(modifiers.containsKey(Modifiers.B_ECHELON))
6591                {
6592                    temp = modifiers.get(Modifiers.B_ECHELON);
6593                    if(temp != null && !temp.isEmpty())
6594                        mods.add(new Modifier("B", temp, x, y, centered));
6595                }
6596
6597
6598                //Do right side labels
6599                x = 1;//on right
6600                centered = true;
6601
6602                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6603                {
6604                    y = 0;//
6605                    temp = "";
6606                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6607                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6608                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6609                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6610                    temp = temp.trim();
6611
6612                    if(temp != null && !temp.isEmpty())
6613                        mods.add(new Modifier("V AF", temp, x, y, centered));
6614                }
6615                else
6616                {
6617                    centered = false;
6618                }
6619
6620                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.Y_LOCATION))
6621                {
6622                    y = 1;//above center
6623                    temp = "";
6624                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6625                        temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1) + sep;
6626                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6627                        temp += modifiers.get(Modifiers.Y_LOCATION);
6628                    temp = temp.trim();
6629
6630                    if(temp != null && !temp.isEmpty())
6631                        mods.add(new Modifier("T Y", temp, x, y, centered));
6632                }
6633
6634                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6635                {
6636                    y = 2;
6637                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6638                        y--;
6639                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6640
6641                    if(temp != null && !temp.isEmpty())
6642                        mods.add(new Modifier("AS", temp, x, y, centered));
6643                }
6644
6645                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS)  ||
6646                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)  ||
6647                        modifiers.containsKey(Modifiers.Z_SPEED))
6648                {
6649                    y = -1;//below center
6650                    temp = "";
6651                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6652                        temp = modifiers.get(Modifiers.P_IFF_SIF_AIS) + sep;
6653                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6654                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6655                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6656                        temp = modifiers.get(Modifiers.Z_SPEED);
6657
6658                    temp = temp.trim();
6659
6660                    if(temp != null && !temp.isEmpty())
6661                        mods.add(new Modifier("P X Z", temp, x, y, centered));
6662                }
6663
6664                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
6665                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6666                        modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6667                {
6668                    y = -2;//below center
6669                    if(!(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS)  ||
6670                            modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)  ||
6671                            modifiers.containsKey(Modifiers.Z_SPEED)))
6672                        y++;
6673
6674                    temp = "";
6675                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6676                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6677                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6678                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6679                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6680                        temp += modifiers.get(Modifiers.J_EVALUATION_RATING);
6681                    temp = temp.trim();
6682
6683                    if(temp != null && !temp.isEmpty())
6684                        mods.add(new Modifier("G H J", temp, x, y, centered));
6685                }
6686
6687                //No left side labels
6688                x = -1;//on right
6689                centered = true;
6690
6691                if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6692                {
6693                    y = 0;//
6694                    temp = temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE);
6695
6696                    if(temp != null && !temp.isEmpty())
6697                        mods.add(new Modifier("AD", temp, x, y, centered));
6698                }
6699                else
6700                {
6701                    centered = false;
6702                }
6703
6704                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6705                {
6706                    y = 1;//above center
6707                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6708
6709                    if(temp != null && !temp.isEmpty())
6710                        mods.add(new Modifier("AR", temp, x, y, centered));
6711                }
6712
6713                if(modifiers.containsKey(Modifiers.W_DTG_1))
6714                {
6715                    y = 2;
6716                    if(!strict && !modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6717                        y--;
6718                    temp = modifiers.get(Modifiers.W_DTG_1);
6719
6720                    if(temp != null && !temp.isEmpty())
6721                        mods.add(new Modifier("W", temp, x, y, centered));
6722                }
6723            }
6724            else if(ss == SymbolID.SymbolSet_SeaSurface ||
6725                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_SeaSurface))
6726            {
6727                //No top center label
6728
6729
6730                //Do right side labels
6731                x = 1;//on right
6732                centered = false;
6733
6734                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6735                {
6736                    y = 1;//above center
6737                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
6738
6739                    if(temp != null && !temp.isEmpty())
6740                        mods.add(new Modifier("V", temp, x, y, centered));
6741                }
6742
6743                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6744                {
6745                    y = 2;
6746                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6747                        y--;
6748                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6749
6750                    if(temp != null && !temp.isEmpty())
6751                        mods.add(new Modifier("T", temp, x, y, centered));
6752                }
6753
6754                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6755                {
6756                    y = 3;
6757                    if(!strict)
6758                    {
6759                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6760                            y--;
6761                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6762                            y--;
6763                    }
6764
6765                    temp = modifiers.get(Modifiers.AS_COUNTRY );
6766
6767                    if(temp != null && !temp.isEmpty())
6768                        mods.add(new Modifier("AS", temp, x, y, centered));
6769                }
6770
6771                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6772                {
6773                    y = -1;//below center
6774                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
6775
6776                    if(temp != null && !temp.isEmpty())
6777                        mods.add(new Modifier("P", temp, x, y, centered));
6778                }
6779
6780                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6781                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6782                {
6783                    y = -2;//below center
6784                    if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6785                        y++;
6786
6787                    temp = "";
6788                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6789                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6790                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6791                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6792                    temp = temp.trim();
6793
6794                    if(temp != null && !temp.isEmpty())
6795                        mods.add(new Modifier("G H", temp, x, y, centered));
6796                }
6797
6798                if(modifiers.containsKey(Modifiers.Y_LOCATION) ||
6799                        modifiers.containsKey(Modifiers.Z_SPEED))
6800                {
6801                    y = -3;
6802                    if(!strict)
6803                    {
6804                        if(!(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6805                                modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)))
6806                            y++;
6807                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6808                            y++;
6809                    }
6810                    temp = "";
6811                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6812                        temp = modifiers.get(Modifiers.Y_LOCATION) + sep;
6813                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6814                        temp += modifiers.get(Modifiers.Z_SPEED);
6815                    temp = temp.trim();
6816                    if(temp != null && !temp.isEmpty())
6817                        mods.add(new Modifier("Y Z", temp, x, y, centered));
6818                }
6819
6820                //No left side labels
6821                x = -1;
6822                centered = false;
6823                if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT) ||
6824                        modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6825                {
6826                    y = 2;
6827                    if(!strict)
6828                    {
6829                        y--;
6830                    }
6831                    temp = "";
6832                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6833                        temp = modifiers.get(Modifiers.AQ_GUARDED_UNIT) + sep;
6834                    if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6835                        temp += modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6836                    temp = temp.trim();
6837                    if(temp != null && !temp.isEmpty())
6838                        mods.add(new Modifier("AQ AR", temp, x, y, centered));
6839                }
6840            }
6841            else if(ss == SymbolID.SymbolSet_SeaSubsurface ||
6842                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_SeaSubsurface))
6843            {
6844                //No top center label
6845
6846
6847                //Do right side labels
6848                x = 1;//on right
6849                centered = false;
6850
6851                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6852                {
6853                    y = 1;//above center
6854                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
6855
6856                    if(temp != null && !temp.isEmpty())
6857                        mods.add(new Modifier("V", temp, x, y, centered));
6858                }
6859
6860                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6861                {
6862                    y = 2;
6863                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6864                        y--;
6865                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6866
6867                    if(temp != null && !temp.isEmpty())
6868                        mods.add(new Modifier("T", temp, x, y, centered));
6869                }
6870
6871                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6872                {
6873                    y = 3;
6874                    if(!strict)
6875                    {
6876                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6877                            y--;
6878                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6879                            y--;
6880                    }
6881
6882                    temp = modifiers.get(Modifiers.AS_COUNTRY );
6883
6884                    if(temp != null && !temp.isEmpty())
6885                        mods.add(new Modifier("AS", temp, x, y, centered));
6886                }
6887
6888                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6889                {
6890                    y = -1;//below center
6891                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
6892
6893                    if(temp != null && !temp.isEmpty())
6894                        mods.add(new Modifier("P", temp, x, y, centered));
6895                }
6896
6897                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6898                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6899                {
6900                    y = -2;//below center
6901                    if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6902                        y++;
6903
6904                    temp = "";
6905                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6906                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6907                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6908                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6909                    temp = temp.trim();
6910
6911                    if(temp != null && !temp.isEmpty())
6912                        mods.add(new Modifier("G H", temp, x, y, centered));
6913                }
6914
6915                if(modifiers.containsKey(Modifiers.Y_LOCATION) ||
6916                        modifiers.containsKey(Modifiers.Z_SPEED))
6917                {
6918                    y = -3;
6919                    if(!strict)
6920                    {
6921                        if(!(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6922                                modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)))
6923                            y++;
6924                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6925                            y++;
6926                    }
6927                    temp = "";
6928                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6929                        temp = modifiers.get(Modifiers.Y_LOCATION) + sep;
6930                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6931                        temp += modifiers.get(Modifiers.Z_SPEED);
6932                    temp = temp.trim();
6933                    if(temp != null && !temp.isEmpty())
6934                        mods.add(new Modifier("Y Z", temp, x, y, centered));
6935                }
6936
6937                //No left side labels
6938                x = -1;
6939                centered = false;
6940                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6941                {
6942                    y = 1;
6943                    temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
6944
6945                    if(temp != null && !temp.isEmpty())
6946                        mods.add(new Modifier("X", temp, x, y, centered));
6947                }
6948
6949                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6950                {
6951                    y = 2;
6952                    if(!strict && !modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6953                    {
6954                        y--;
6955                    }
6956                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6957                    temp = temp.trim();
6958                    if(temp != null && !temp.isEmpty())
6959                        mods.add(new Modifier("AR", temp, x, y, centered));
6960                }
6961            }
6962            else if(ss == SymbolID.SymbolSet_DismountedIndividuals)
6963            {
6964                //No top center label
6965
6966
6967                //Do right side labels
6968                x = 1;//on right
6969                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6970                {
6971                    y = 0;//center
6972                    centered = true;//vertically centered, only matters for labels on left and right side
6973                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6974
6975                    if(temp != null && !temp.isEmpty())
6976                        mods.add(new Modifier("H", temp, x, y, centered));
6977                }
6978                else if(!strict)
6979                {
6980                    centered = false;
6981                }
6982
6983                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6984                {
6985                    y = 1;//above center
6986                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
6987
6988                    if(temp != null && !temp.isEmpty())
6989                        mods.add(new Modifier("G", temp, x, y, centered));
6990                }
6991
6992                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6993                {
6994                    y = 2;
6995                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)))
6996                        y--;
6997                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6998
6999                    if(temp != null && !temp.isEmpty())
7000                        mods.add(new Modifier("AS", temp, x, y, centered));
7001                }
7002
7003                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7004                {
7005                    y = -1;//below center
7006                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
7007                    if(temp != null && !temp.isEmpty())
7008                        mods.add(new Modifier("M", temp, x, y, centered));
7009                }
7010
7011                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
7012                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
7013                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
7014                {
7015                    y = -2;
7016                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7017                        y++;
7018                    temp = "";
7019                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
7020                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
7021                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
7022                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
7023                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
7024                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
7025                    temp = temp.trim();
7026                    if(temp != null && !temp.isEmpty())
7027                        mods.add(new Modifier("J K P", temp, x, y, centered));
7028                }
7029
7030                //Do left side labels
7031                x = -1;//on left
7032
7033                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
7034                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
7035                {
7036                    y = 0;//center
7037                    centered = true;//vertically centered, only matters for labels on left and right side
7038
7039                    temp = "";
7040                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
7041                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
7042                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
7043                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
7044                    temp = temp.trim();
7045                    if(temp != null && !temp.isEmpty())
7046                        mods.add(new Modifier("V AF", temp, x, y, centered));
7047                }
7048                else if(!strict)
7049                {
7050                    centered = false;
7051                }
7052
7053                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
7054                {
7055                    y = 1;
7056                    temp = "";
7057                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
7058                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
7059                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
7060                        temp += modifiers.get(Modifiers.Y_LOCATION);
7061
7062                    temp = temp.trim();
7063                    mods.add(new Modifier("X Y", temp, x, y, centered));
7064                }
7065
7066                if(modifiers.containsKey(Modifiers.W_DTG_1))
7067                {
7068                    y = 2;//above center
7069                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
7070                        y--;
7071
7072                    temp = modifiers.get(Modifiers.W_DTG_1);
7073
7074                    if(temp != null && !temp.isEmpty())
7075                        mods.add(new Modifier("W", temp, x, y, centered));
7076                }
7077
7078                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7079                {
7080                    y = -1;//below center
7081                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7082
7083                    if(temp != null && !temp.isEmpty())
7084                        mods.add(new Modifier("T", temp, x, y, centered));
7085                }
7086
7087                if(modifiers.containsKey(Modifiers.Z_SPEED))
7088                {
7089                    y = -2;
7090                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
7091                        y++;
7092                    temp = modifiers.get(Modifiers.Z_SPEED);
7093                    if(temp != null && !temp.isEmpty())
7094                        mods.add(new Modifier("Z", temp, x, y, centered));
7095                }
7096            }
7097            else if(ss == SymbolID.SymbolSet_Activities)
7098            {
7099                //No top center label
7100
7101
7102                //Do right side labels
7103                x = 1;//on right
7104                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7105                {
7106                    y = 0;//center
7107                    centered = true;//vertically centered, only matters for labels on left and right side
7108                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7109
7110                    if(temp != null && !temp.isEmpty())
7111                        mods.add(new Modifier("G", temp, x, y, centered));
7112                }
7113                else if(!strict)
7114                {
7115                    centered = false;
7116                }
7117
7118                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7119                {
7120                    y = 1;//above center
7121                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7122
7123                    if(temp != null && !temp.isEmpty())
7124                        mods.add(new Modifier("T", temp, x, y, centered));
7125                }
7126
7127                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7128                {
7129                    y = 2;
7130                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
7131                        y--;
7132                    temp = modifiers.get(Modifiers.AS_COUNTRY);
7133
7134                    if(temp != null && !temp.isEmpty())
7135                        mods.add(new Modifier("AS", temp, x, y, centered));
7136                }
7137
7138                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7139                {
7140                    y = -1;//below center
7141                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7142                    if(temp != null && !temp.isEmpty())
7143                        mods.add(new Modifier("H", temp, x, y, centered));
7144                }
7145
7146                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
7147                {
7148                    y = -2;
7149                    if(!strict && !modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7150                        y++;
7151                    temp = modifiers.get(Modifiers.J_EVALUATION_RATING);
7152
7153                    if(temp != null && !temp.isEmpty())
7154                        mods.add(new Modifier("J", temp, x, y, centered));
7155                }
7156
7157                //Do left side labels
7158                x = -1;//on left
7159
7160                if(!strict)
7161                {
7162                    centered = false;
7163                }
7164
7165                if(modifiers.containsKey(Modifiers.Y_LOCATION))
7166                {
7167                    y = 1;
7168                    temp = modifiers.get(Modifiers.Y_LOCATION);
7169
7170                    if(temp != null && !temp.isEmpty())
7171                        mods.add(new Modifier("Y", temp, x, y, centered));
7172                }
7173
7174                if(modifiers.containsKey(Modifiers.W_DTG_1))
7175                {
7176                    y = 2;//above center
7177                    if(!strict && !(modifiers.containsKey(Modifiers.Y_LOCATION)))
7178                        y--;
7179
7180                    temp = modifiers.get(Modifiers.W_DTG_1);
7181
7182                    if(temp != null && !temp.isEmpty())
7183                        mods.add(new Modifier("W", temp, x, y, centered));
7184                }
7185
7186                if(modifiers.containsKey(Modifiers.C_QUANTITY))
7187                {
7188                    y = -1;//below center
7189                    temp = modifiers.get(Modifiers.C_QUANTITY);
7190
7191                    if(temp != null && !temp.isEmpty())
7192                        mods.add(new Modifier("C", temp, x, y, centered));
7193                }
7194
7195            }
7196            else if(ss == SymbolID.SymbolSet_CyberSpace ||
7197                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_Cyberspace))
7198            {
7199                //Do top center label
7200                x = 0;//centered
7201                y = 9;//on top of symbol
7202                if(modifiers.containsKey(Modifiers.B_ECHELON))
7203                {
7204                    temp = modifiers.get(Modifiers.B_ECHELON);
7205                    if(temp != null && !temp.isEmpty())
7206                        mods.add(new Modifier("B", temp, x, y, centered));
7207                }
7208
7209                //Do right side labels
7210                x = 1;//on right
7211                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7212                {
7213                    y = 0;//center
7214                    centered = true;//vertically centered, only matters for labels on left and right side
7215                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7216
7217                    if(temp != null && !temp.isEmpty())
7218                        mods.add(new Modifier("H", temp, x, y, centered));
7219                }
7220                else if(!strict)
7221                {
7222                    centered = false;
7223                }
7224
7225                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7226                {
7227                    y = 1;//above center
7228                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7229
7230                    if(temp != null && !temp.isEmpty())
7231                        mods.add(new Modifier("G", temp, x, y, centered));
7232                }
7233
7234                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
7235                {
7236                    y = 2;
7237                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)))
7238                        y--;
7239                    temp = "";
7240                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
7241                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
7242                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7243                        temp += modifiers.get(Modifiers.AS_COUNTRY);
7244                    temp = temp.trim();
7245                    if(temp != null && !temp.isEmpty())
7246                        mods.add(new Modifier("F AS", temp, x, y, centered));
7247                }
7248
7249                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7250                {
7251                    y = -1;//below center
7252                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
7253                    if(temp != null && !temp.isEmpty())
7254                        mods.add(new Modifier("M", temp, x, y, centered));
7255                }
7256
7257                if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) || modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
7258                {
7259                    y = -2;
7260                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7261                        y++;
7262                    temp = "";
7263                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
7264                        temp = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
7265                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
7266                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
7267                    temp = temp.trim();
7268                    if(temp != null && !temp.isEmpty())
7269                        mods.add(new Modifier("K L", temp, x, y, centered));
7270                }
7271
7272                //Do left side labels
7273                x=-1;
7274                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
7275                {
7276                    y = 0;//center
7277                    centered = true;//vertically centered, only matters for labels on left and right side
7278
7279                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
7280
7281                    if(temp != null && !temp.isEmpty())
7282                        mods.add(new Modifier("V", temp, x, y, centered));
7283                }
7284                else if(!strict)
7285                {
7286                    centered = false;
7287                }
7288
7289                if(modifiers.containsKey(Modifiers.Y_LOCATION))
7290                {
7291                    y = 1;
7292                    temp = modifiers.get(Modifiers.Y_LOCATION);
7293
7294                    if(temp != null && !temp.isEmpty())
7295                        mods.add(new Modifier("Y", temp, x, y, centered));
7296                }
7297
7298                if(modifiers.containsKey(Modifiers.W_DTG_1))
7299                {
7300                    y = 2;//above center
7301                    if(!strict && !(modifiers.containsKey(Modifiers.Y_LOCATION)))
7302                        y--;
7303
7304                    temp = modifiers.get(Modifiers.W_DTG_1);
7305
7306                    if(temp != null && !temp.isEmpty())
7307                        mods.add(new Modifier("W", temp, x, y, centered));
7308                }
7309
7310                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7311                {
7312                    y = -1;//below center
7313                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7314
7315                    if(temp != null && !temp.isEmpty())
7316                        mods.add(new Modifier("T", temp, x, y, centered));
7317                }
7318            }
7319            /*else if(ver == SymbolID.SymbolSet_MineWarfare)
7320            {
7321                //no modifiers
7322            }//*/
7323            //else//SymbolSet Unknown
7324            //processUnknownTextModifiers
7325        }
7326
7327        return mods;
7328    }
7329
7330
7331    /**
7332     * @param bounds     bounds of the core icon
7333     * @param labelWidth height of the label to be placed
7334     * @param location   if 1, label on right side of symbol. On left if -1, center if 0.
7335     * @returns
7336     */
7337    private static double getLabelXPosition(Rect bounds, int labelWidth, int location, float modifierFontHeight)
7338    {
7339        int buffer = (int)modifierFontHeight/2;
7340
7341        double x = 0;
7342        if(location == 1)//on right
7343        {
7344            x = bounds.left + bounds.width() + buffer;
7345        }
7346        else if(location == -1)//left
7347        {
7348            x = bounds.left - labelWidth - buffer;
7349        }
7350        else if(location == 0)
7351        {
7352            x = Math.round((bounds.left + (bounds.width() * 0.5f)) - (labelWidth * 0.5f));
7353        }
7354        return x;
7355    }
7356
7357    /**
7358     *
7359     * @param bounds bounds of the core icon
7360     * @param labelHeight height of the label to be placed
7361     * @param descent descent of the label to be placed
7362     * @param bufferText spacing buffer if desired
7363     * @param centered if true, there will be a center label location identified by 0
7364     * @param location positive 1, 2, 3 to be above symbol mid-point or negative values to be below
7365     * @returns y position
7366     */
7367    private static double getLabelYPosition(Rect bounds, int labelHeight, int descent, int bufferText, boolean centered, int location) {
7368        double y = 0;
7369        if (bounds != null && !bounds.isEmpty())
7370        {
7371            if(centered)
7372            {
7373                switch (location)
7374                {
7375                    case 3://3 above center
7376                        y = (bounds.height());
7377                        y = ((y * 0.5) + (labelHeight * 0.5));
7378                        y = y - ((labelHeight + bufferText) * 3);
7379                        y = bounds.top + y;
7380                        break;
7381                    case 2://2 above center
7382                        y = (bounds.height());
7383                        y = ((y * 0.5) + (labelHeight * 0.5));
7384                        y = y - ((labelHeight + bufferText) * 2);
7385                        y = bounds.top + y;
7386                        break;
7387                    case 1://1 above center
7388                        y = (bounds.height());
7389                        y = ((y * 0.5) + (labelHeight * 0.5));
7390                        y = y - ((labelHeight + bufferText));
7391                        y = bounds.top + y;
7392                        break;
7393                    case 0: //centered
7394                        y = (bounds.height());
7395                        y = ((y * 0.5) + ((labelHeight - descent) * 0.5));
7396                        y = bounds.top + y;
7397                        break;
7398                    case -1://1 below center
7399                        y = (bounds.height());
7400                        y = ((y * 0.5) + (labelHeight * 0.5));
7401                        y = y + ((labelHeight + bufferText - descent));
7402                        y = bounds.top + y;
7403                        break;
7404                    case -2://2 below center
7405                        y = (bounds.height());
7406                        y = ((y * 0.5) + (labelHeight * 0.5));
7407                        y = y + ((labelHeight + bufferText) * 2) - (descent);
7408                        y = bounds.top + y;
7409                        break;
7410                    case -3://3 below center
7411                        y = (bounds.height());
7412                        y = ((y * 0.5) + (labelHeight * 0.5));
7413                        y = y + ((labelHeight + bufferText) * 3) - (descent);
7414                        y = bounds.top + y;
7415                        break;
7416                }
7417            }
7418            else//split between top and bottom
7419            {
7420                switch (location)
7421                {
7422                    case 3:
7423                        y = (bounds.top + ((bounds.height() / 2) - descent - labelHeight*2 - bufferText));
7424                        break;
7425                    case 2:
7426                        y = (bounds.top + ((bounds.height() / 2) - descent - labelHeight - bufferText));
7427                        break;
7428                    case 1:
7429                        y = (bounds.top + ((bounds.height() / 2) - descent));
7430                        break;
7431                    case -1:
7432                        y = (bounds.top + (bounds.height() / 2) + (labelHeight - descent + bufferText));
7433                        break;
7434                    case -2:
7435                        y = (bounds.top + (bounds.height() / 2) + ((labelHeight*2 - descent + bufferText)));
7436                        break;
7437                    case -3:
7438                        y = (bounds.top + (bounds.height() / 2) + ((labelHeight*3 - descent + bufferText)));
7439                        break;
7440                }
7441            }
7442            if(location == 9)//on top of symbol
7443            {
7444                y = Math.round(bounds.top - bufferText - descent);
7445            }
7446        }
7447        return y;
7448    }
7449
7450    /**
7451     * Currently, modifiers are based on Symbol Set.
7452     * The exception is SIGINT which required a frame shape value in 2525E+
7453     * The SSMC couldn't come to an agreement on if frame shape should dictate modifiers.
7454     * Currently, I'm keeping it tied to Symbol Set.
7455     * @param symbolID
7456     * @return
7457     */
7458    private static boolean isCOnTop(String symbolID)
7459    {
7460        boolean onTop = false;
7461
7462        int version = SymbolID.getVersion(symbolID);
7463        int ss = SymbolID.getSymbolSet(symbolID);
7464        char frame = SymbolID.getFrameShape(symbolID);
7465
7466        if(SymbolUtilities.hasModifier(symbolID,Modifiers.C_QUANTITY)) {
7467
7468            if(version >= SymbolID.Version_2525E)
7469            {
7470
7471                if (ss == SymbolID.SymbolSet_Air ||
7472                        ss == SymbolID.SymbolSet_AirMissile ||
7473                        ss == SymbolID.SymbolSet_Space ||
7474                        ss == SymbolID.SymbolSet_SpaceMissile ||
7475                        ss == SymbolID.SymbolSet_LandEquipment)
7476                {
7477                    onTop = true;
7478                }
7479                else if(ss == SymbolID.SymbolSet_SignalsIntelligence &&
7480                        (frame == SymbolID.FrameShape_Air ||
7481                        frame == SymbolID.FrameShape_Space ||
7482                        frame == SymbolID.FrameShape_LandEquipment || frame == SymbolID.FrameShape_LandUnit || frame == '0'))
7483                {
7484                    onTop = true;
7485                }
7486
7487            }// else if <= SymbolID.Version_2525Dch1
7488            else if (ss == SymbolID.SymbolSet_LandEquipment ||
7489                    ss == SymbolID.SymbolSet_SignalsIntelligence_Land)
7490            {
7491                onTop = true;
7492            }
7493        }
7494        return onTop;
7495    }
7496    public static boolean hasDisplayModifiers(String symbolID, Map<String,String> modifiers)
7497    {
7498        boolean hasModifiers = false;
7499        int ss = SymbolID.getSymbolSet(symbolID);
7500        int status = SymbolID.getStatus(symbolID);
7501        int context = SymbolID.getContext(symbolID);
7502
7503        if(ss == SymbolID.SymbolSet_ControlMeasure)//check control measure
7504        {
7505            if (SymbolUtilities.isCBRNEvent(symbolID) == true && modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT))
7506            {
7507                hasModifiers = true;
7508            }
7509            else if(SymbolUtilities.hasFDI(symbolID))
7510                hasModifiers = true;
7511        }
7512        else if(ss != SymbolID.SymbolSet_Atmospheric &&
7513                ss != SymbolID.SymbolSet_Oceanographic &&
7514                ss != SymbolID.SymbolSet_MeteorologicalSpace)
7515        {//checking units
7516
7517            if(context > 0) //Exercise or Simulation
7518                hasModifiers = true;
7519
7520            //echelon or mobility,
7521            if (SymbolID.getAmplifierDescriptor(symbolID) > 0 || modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT))
7522                hasModifiers = true;
7523
7524            if(modifiers.containsKey(Modifiers.AJ_SPEED_LEADER))
7525                hasModifiers = true;
7526
7527            if(modifiers.containsKey(Modifiers.AO_ENGAGEMENT_BAR))
7528                hasModifiers = true;
7529
7530            //HQ/Taskforce
7531            if(SymbolID.getHQTFD(symbolID) > 0)
7532                hasModifiers = true;
7533
7534            if(status > 1)//Fully capable, damaged, destroyed
7535                hasModifiers = true;
7536        }//no display modifiers for single point weather
7537
7538
7539
7540        return hasModifiers;
7541    }
7542
7543    public static boolean hasTextModifiers(String symbolID, Map<String,String> modifiers)
7544    {
7545
7546        int ss = SymbolID.getSymbolSet(symbolID);
7547        int ec = SymbolID.getEntityCode(symbolID);
7548        if(ss == SymbolID.SymbolSet_Atmospheric)
7549        {
7550            switch(ec)
7551            {
7552                case 110102: //tropopause low
7553                case 110202: //tropopause high
7554                case 162200: //tropopause level ?
7555                case 162300: //freezing level ?
7556                    return true;
7557                default:
7558                        return false;
7559            }
7560        }
7561        else if(ss == SymbolID.SymbolSet_Oceanographic || ss == SymbolID.SymbolSet_MeteorologicalSpace)
7562        {
7563            return false;
7564        }
7565        else if (ss == SymbolID.SymbolSet_ControlMeasure)
7566        {
7567            MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
7568
7569            if( msi.getModifiers().size() > 0 && modifiers != null && modifiers.size() > 0)
7570                return true;
7571            else
7572                return false;
7573        }
7574        else
7575        {
7576
7577            if (SymbolUtilities.getStandardIdentityModifier(symbolID) != null)
7578            {
7579                return true;
7580            }
7581
7582            int cc = SymbolID.getCountryCode(symbolID);
7583            if (cc > 0 && !GENCLookup.getInstance().get3CharCode(cc).isEmpty())
7584            {
7585                return true;
7586            }//*/
7587
7588            else if (modifiers.size() > 0)
7589            {
7590                return true;
7591            }
7592        }
7593        return false;
7594    }
7595
7596    /**
7597     * Rerturns either the default font from RendererSettings or font based on properties
7598     * set in MilStdAttributes.
7599     * @param attributes
7600     * @return
7601     */
7602    private static Paint getFont(Map<String,String> attributes)
7603    {
7604        Paint p = null;
7605        Typeface tf = null;
7606
7607        p = RendererSettings.getInstance().getModiferFont();
7608
7609        String[] props = RendererSettings.getInstance().getModiferFontProps();
7610
7611        String ff = props[0];
7612        int fstyle = Integer.parseInt(props[1]);// modifierFont.getTypeface().getStyle();
7613        float fsize = Float.parseFloat(props[2]);// modifierFont.getTextSize();
7614        String temp = null;
7615
7616
7617        if(attributes.containsKey(MilStdAttributes.FontFamily) ||
7618                attributes.containsKey(MilStdAttributes.FontStyle) ||
7619                attributes.containsKey(MilStdAttributes.FontSize))
7620        {
7621            if(attributes.containsKey(MilStdAttributes.FontStyle))
7622            {
7623                temp = attributes.get(MilStdAttributes.FontStyle);
7624                if (temp != null && !temp.isEmpty()) {
7625                    fstyle = Integer.parseInt(temp);
7626                }
7627            }
7628            if(attributes.containsKey(MilStdAttributes.FontSize))
7629            {
7630                temp = attributes.get(MilStdAttributes.FontSize);
7631                if (temp != null && !temp.isEmpty()) {
7632                    fsize = Float.parseFloat(temp);
7633                }
7634            }
7635            if(attributes.containsKey(MilStdAttributes.FontFamily))
7636            {
7637                temp = attributes.get(MilStdAttributes.FontFamily);
7638                if (temp != null && !temp.isEmpty()) {
7639                    ff =  temp;//Typeface.create(temp,fstyle);
7640                }
7641            }
7642            tf = Typeface.create(ff,fstyle);
7643            if(tf == null)
7644                tf = Typeface.create(props[0],fstyle);
7645            if(tf == null)
7646                return null;
7647
7648            p = new Paint();
7649            p.setTextSize(fsize);
7650            p.setAntiAlias(true);
7651            p.setTypeface(tf);
7652            p.setStrokeCap(Cap.BUTT);
7653            p.setStrokeJoin(Join.MITER);
7654            p.setStrokeMiter(3f);
7655
7656            return p;
7657        }
7658        else
7659            return _modifierFont;
7660
7661    }
7662
7663    private static float[] getFontHeightandDescent(Paint font)
7664    {
7665        float[] hd = {0f,0f};
7666
7667        if(font != null) {
7668            Paint.FontMetrics fm = font.getFontMetrics();
7669            //_modifierFontHeight = fm.top + fm.bottom;
7670            hd[0] = fm.bottom - fm.top;
7671            hd[1] = fm.descent;
7672        }
7673        return hd;
7674    }
7675
7676}