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            {
3265                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3266                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3267                    if (strText != null) {
3268                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3269                        labelWidth = Math.round(ti.getTextBounds().width());
3270                        //One modifier symbols and modifier goes in center
3271                        x = bounds.left + (int) (bounds.width() * 0.5f);
3272                        x = x - (int) (labelWidth * 0.5f);
3273                        y = bounds.top + (int) (bounds.height() * 0.4f);
3274                        y = y + (int) (labelHeight * 0.5f);
3275
3276                        ti.setLocation(Math.round(x), Math.round(y));
3277                        arrMods.add(ti);
3278                    }
3279                }
3280                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3281                    strText = modifiers.get(Modifiers.W_DTG_1);
3282                    if (strText != null) {
3283                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3284                        labelWidth = ti.getTextBounds().width();
3285
3286                        x = (bounds.left - labelWidth - bufferXL);
3287                        y = (bounds.top + labelHeight - descent);
3288
3289                        ti.setLocation(x, y);
3290                        arrMods.add(ti);
3291                    }
3292                }
3293            }
3294            if (ec == 130700) //decision point
3295            {
3296                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3297                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3298                    if (strText != null) {
3299                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3300                        labelWidth = Math.round(ti.getTextBounds().width());
3301                        //One modifier symbols and modifier goes in center
3302                        x = bounds.left + (int) (bounds.width() * 0.5f);
3303                        x = x - (int) (labelWidth * 0.5f);
3304                        y = bounds.top + (int) (bounds.height() * 0.5f);
3305                        y = y + (int) (labelHeight * 0.5f);
3306
3307                        ti.setLocation(Math.round(x), Math.round(y));
3308                        arrMods.add(ti);
3309                    }
3310                }
3311            }
3312            else if (ec == 212800)//harbor
3313            {
3314                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3315                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3316                    if (strText != null) {
3317                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3318                        labelWidth = Math.round(ti.getTextBounds().width());
3319                        //One modifier symbols and modifier goes in center
3320                        x = bounds.left + (int) (bounds.width() * 0.5f);
3321                        x = x - (int) (labelWidth * 0.5f);
3322                        y = bounds.top + (int) (bounds.height() * 0.5f);
3323                        y = y + (int) (labelHeight * 0.5f);
3324
3325                        ti.setLocation(Math.round(x), Math.round(y));
3326                        arrMods.add(ti);
3327                    }
3328                }
3329            } else if (ec == 131300)//point of interest
3330            {
3331                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3332                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3333                    if (strText != null) {
3334                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3335                        labelWidth = Math.round(ti.getTextBounds().width());
3336                        //One modifier symbols, top third & center
3337                        x = bounds.left + (int) (bounds.width() * 0.5f);
3338                        x = x - (int) (labelWidth * 0.5f);
3339                        y = bounds.top + (int) (bounds.height() * 0.25f);
3340                        y = y + (int) (labelHeight * 0.5f);
3341
3342                        ti.setLocation(Math.round(x), Math.round(y));
3343                        arrMods.add(ti);
3344                    }
3345                }
3346            } else if (ec == 131800//waypoint
3347                    || ec == 240900)//fire support station
3348            {
3349                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3350                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3351                    if (strText != null) {
3352                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3353
3354                        //One modifier symbols and modifier goes right of center
3355                        if (ec == 131800)
3356                            x = bounds.left + (int) (bounds.width() * 0.75f);
3357                        else
3358                            x = bounds.left + (bounds.width());
3359                        y = bounds.top + (int) (bounds.height() * 0.5f);
3360                        y = y + (int) ((labelHeight - descent) * 0.5f);
3361
3362                        ti.setLocation(Math.round(x), Math.round(y));
3363                        arrMods.add(ti);
3364                    }
3365                }
3366            }
3367            else if (ec == 131900)//Airfield (AEGIS Only)
3368            {
3369                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3370                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3371                    if (strText != null) {
3372                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3373
3374                        //One modifier symbols and modifier goes right of symbol
3375
3376                        x = bounds.left + (bounds.width() + bufferXR);
3377
3378                        y = bounds.top + (int) (bounds.height() * 0.5f);
3379                        y = y + (int) ((labelHeight - descent) * 0.5f);
3380
3381                        ti.setLocation(Math.round(x), Math.round(y));
3382                        arrMods.add(ti);
3383                    }
3384                }
3385            }
3386            else if (ec == 180100 //Air Control point
3387                    || ec == 180200) //Communications Check point
3388            {
3389                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3390                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3391                    if (strText != null) {
3392                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3393                        labelWidth = ti.getTextBounds().width();
3394                        //One modifier symbols and modifier goes just below of center
3395                        x = bounds.left + (int) (bounds.width() * 0.5);
3396                        x = x - (int) (labelWidth * 0.5);
3397                        y = bounds.top + (int) (bounds.height() * 0.5f);
3398                        y = y + (int) (((bounds.height() * 0.5f) - labelHeight) / 2) + labelHeight - descent;
3399
3400                        ti.setLocation(Math.round(x), Math.round(y));
3401                        arrMods.add(ti);
3402                    }
3403                }
3404            } else if (ec == 160300 || //T (target reference point)
3405                    ec == 132000 || //T (Target Handover)
3406                    ec == 240601 || //ap,ap1,x,h (Point/Single Target)
3407                    ec == 240602) //ap (nuclear target)
3408            { //Targets with special modifier positions
3409                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)
3410                        && ec == 240601)//H //point single target
3411                {
3412                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3413                    if (strText != null) {
3414                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3415
3416                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3417                        y = bounds.top + (int) (bounds.height() * 0.75f);
3418                        y = y + (int) (labelHeight * 0.5f);
3419
3420                        ti.setLocation(Math.round(x), Math.round(y));
3421                        arrMods.add(ti);
3422                    }
3423                }
3424                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)
3425                        && ec == 240601)//X point or single target
3426                {
3427                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3428                    if (strText != null) {
3429                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3430                        labelWidth = Math.round(ti.getTextBounds().width());
3431                        x = RectUtilities.getCenterX(bounds) - (int) (bounds.width() * 0.15f);
3432                        x = x - (labelWidth);
3433                        y = bounds.top + (int) (bounds.height() * 0.75f);
3434                        y = y + (int) (labelHeight * 0.5f);
3435
3436                        ti.setLocation(Math.round(x), Math.round(y));
3437                        arrMods.add(ti);
3438                    }
3439                }
3440                strText = null;
3441                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) && (ec == 160300 || ec == 132000)) {
3442                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3443                    if (strText != null) {
3444                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3445
3446                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3447                        y = bounds.top + (int) (bounds.height() * 0.25f);
3448                        y = y + (int) (labelHeight * 0.5f);
3449
3450                        ti.setLocation(Math.round(x), Math.round(y));
3451                        arrMods.add(ti);
3452                    }
3453                }
3454                if (ec == 240601 || ec == 240602)
3455                {
3456                    if (modifiers.containsKey(Modifiers.AP_TARGET_NUMBER)) {
3457                        strText = modifiers.get(Modifiers.AP_TARGET_NUMBER);
3458                    }
3459                    if (ec == 240601 && modifiers.containsKey(Modifiers.AP1_TARGET_NUMBER_EXTENSION)) {
3460                        if (strText != null)
3461                            strText = strText + "  " + modifiers.get(Modifiers.AP1_TARGET_NUMBER_EXTENSION);
3462                        else
3463                            strText = modifiers.get(Modifiers.AP1_TARGET_NUMBER_EXTENSION);
3464                    }
3465                    if (strText != null) {
3466                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3467
3468                        x = RectUtilities.getCenterX(bounds) + (int) (bounds.width() * 0.15f);
3469                        y = bounds.top + (int) (bounds.height() * 0.25f);
3470                        y = y + (int) (labelHeight * 0.5f);
3471
3472                        ti.setLocation(Math.round(x), Math.round(y));
3473                        arrMods.add(ti);
3474                    }
3475                }
3476            }
3477            else if (ec == 132100)//Key Terrain
3478            {
3479                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3480                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3481                    if (strText != null) {
3482                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3483
3484                        //One modifier symbols and modifier goes right of symbol
3485
3486                        x = bounds.left + (int)(bounds.width() * 0.5) + bufferXL;
3487
3488                        y = bounds.top + (int) (bounds.height() * 0.5f);
3489                        y = y + (int) ((labelHeight - descent) * 0.5f);
3490
3491                        ti.setLocation(Math.round(x), Math.round(y));
3492                        arrMods.add(ti);
3493                    }
3494                }
3495            }
3496            else if(ec == 182600)//Isolated Personnel Location
3497            {
3498                if (modifiers.containsKey(Modifiers.C_QUANTITY)) {
3499                    strText = modifiers.get(Modifiers.C_QUANTITY);
3500                    if (strText != null) {
3501                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3502                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3503                        //subset of NBC, just nuclear
3504                        x = (int)(bounds.left + (bounds.width() * 0.5));
3505                        x = x - (int) (labelWidth * 0.5);
3506                        y = (int)bounds.top - descent;
3507                        ti.setLocation(Math.round(x), Math.round(y));
3508                        arrMods.add(ti);
3509                    }
3510                }
3511                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3512                    strText = modifiers.get(Modifiers.W_DTG_1);
3513                    if (strText != null) {
3514                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3515                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3516
3517                        x = (int)bounds.left - labelWidth - bufferXL;
3518                        if (!byLabelHeight) {
3519                            y = (int)bounds.top + labelHeight - descent;
3520                        } else {
3521                            //y = bounds.y + ((bounds.getHeight * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3522                            y = (int)(bounds.top + ((bounds.height() * 0.5) - ((labelHeight - descent) * 0.5) + (-descent - bufferText)));
3523                        }
3524
3525                        ti.setLocation(Math.round(x), Math.round(y));
3526                        arrMods.add(ti);
3527                    }
3528                }
3529                if (modifiers.containsKey(Modifiers.W1_DTG_2)) {
3530                    strText = modifiers.get(Modifiers.W1_DTG_2);
3531                    if (strText != null) {
3532                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3533                        labelWidth = (int)Math.round(ti.getTextBounds().width());
3534
3535                        x = (int)bounds.left - labelWidth - bufferXL;
3536                        if (!byLabelHeight) {
3537                            y = (int)bounds.top + labelHeight - descent;
3538                        } else {
3539                            //y = bounds.y + ((bounds.getHeight * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3540                            y = (int)(bounds.top + ((bounds.height() * 0.5) - (((labelHeight * 2) - descent) * 0.5) + (-descent - bufferText)));
3541                        }
3542
3543                        ti.setLocation(Math.round(x), Math.round(y));
3544                        arrMods.add(ti);
3545                    }
3546                }
3547            }
3548            else if (SymbolUtilities.isCBRNEvent(symbolID)) //CBRN
3549            {
3550                if (modifiers.containsKey(Modifiers.N_HOSTILE)) {
3551                    strText = modifiers.get(Modifiers.N_HOSTILE);
3552                    if (strText != null) {
3553                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3554
3555                        x = bounds.left + bounds.width() + bufferXR;
3556
3557                        if (!byLabelHeight) {
3558                            y = bounds.top + bounds.height();
3559                        } else {
3560                            y = bounds.top + (int) ((bounds.height() * 0.5f) + ((labelHeight - descent) * 0.5) + (labelHeight - descent + bufferText));
3561                        }
3562
3563                        ti.setLocation(Math.round(x), Math.round(y));
3564                        arrMods.add(ti);
3565                    }
3566
3567                }
3568                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3569                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3570                    if (strText != null) {
3571                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3572
3573                        x = bounds.left + bounds.width() + bufferXR;
3574                        if (!byLabelHeight) {
3575                            y = bounds.top + labelHeight - descent;
3576                        } else {
3577                            //y = bounds.y + ((bounds.height * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3578                            y = bounds.top + (int) ((bounds.height() * 0.5f) - ((labelHeight - descent) * 0.5) + (-descent - bufferText));
3579                        }
3580
3581                        ti.setLocation(Math.round(x), Math.round(y));
3582                        arrMods.add(ti);
3583                    }
3584                }
3585                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3586                    strText = modifiers.get(Modifiers.W_DTG_1);
3587                    if (strText != null) {
3588                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3589                        labelWidth = Math.round(ti.getTextBounds().width());
3590
3591                        x = bounds.left - labelWidth - bufferXL;
3592                        if (!byLabelHeight) {
3593                            y = bounds.top + labelHeight - descent;
3594                        } else {
3595                            //y = bounds.y + ((bounds.height * 0.5) + (labelHeight * 0.5) - (labelHeight + bufferText));
3596                            y = bounds.top + (int) ((bounds.height() * 0.5) - ((labelHeight - descent) * 0.5) + (-descent - bufferText));
3597                        }
3598
3599                        ti.setLocation(Math.round(x), Math.round(y));
3600                        arrMods.add(ti);
3601                    }
3602                }
3603                if ((ec == 281500 || ec == 281600) && modifiers.containsKey(Modifiers.V_EQUIP_TYPE)) {//nuclear event or nuclear fallout producing event
3604                    strText = modifiers.get(Modifiers.V_EQUIP_TYPE);
3605                    if (strText != null) {
3606                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3607
3608                        //subset of nbc, just nuclear
3609                        labelWidth = Math.round(ti.getTextBounds().width());
3610                        x = bounds.left - labelWidth - bufferXL;
3611                        y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5));//((bounds.height / 2) - (labelHeight/2));
3612
3613                        ti.setLocation(Math.round(x), Math.round(y));
3614                        arrMods.add(ti);
3615                    }
3616                }
3617                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3618                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3619                    if (strText != null) {
3620                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3621                        labelWidth = Math.round(ti.getTextBounds().width());
3622                        x = bounds.left - labelWidth - bufferXL;
3623                        if (!byLabelHeight) {
3624                            y = bounds.top + bounds.height();
3625                        } else {
3626                            //y = bounds.y + ((bounds.height * 0.5) + ((labelHeight-descent) * 0.5) + (labelHeight + bufferText));
3627                            y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5) + (labelHeight - descent + bufferText));
3628                        }
3629                        ti.setLocation(Math.round(x), Math.round(y));
3630                        arrMods.add(ti);
3631                    }
3632                }
3633                if (modifiers.containsKey(Modifiers.Y_LOCATION)) {
3634                    strText = modifiers.get(Modifiers.Y_LOCATION);
3635                    if (strText != null) {
3636                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3637                        labelWidth = Math.round(ti.getTextBounds().width());
3638                        //just NBC
3639                        //x = bounds.left + (bounds.width() * 0.5);
3640                        //x = x - (labelWidth * 0.5);
3641                        x = bounds.left + (int) (bounds.width() * 0.5f);
3642                        x = x - (int) (labelWidth * 0.5f);
3643
3644                        if (!byLabelHeight) {
3645                            y = bounds.top + bounds.height() + labelHeight - descent + bufferY;
3646                        } else {
3647                            y = bounds.top + (int) ((bounds.height() * 0.5) + ((labelHeight - descent) * 0.5) + ((labelHeight + bufferText) * 2) - descent);
3648
3649                        }
3650                        yForY = y + descent; //so we know where to start the DOM arrow.
3651                        ti.setLocation(Math.round(x), Math.round(y));
3652                        arrMods.add(ti);
3653                    }
3654
3655                }
3656                if (modifiers.containsKey(Modifiers.C_QUANTITY)) {
3657                    strText = modifiers.get(Modifiers.C_QUANTITY);
3658                    if (strText != null) {
3659                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3660                        labelWidth = Math.round(ti.getTextBounds().width());
3661                        //subset of NBC, just nuclear
3662                        x = bounds.left + (int) (bounds.width() * 0.5);
3663                        x = x - (int) (labelWidth * 0.5);
3664                        y = bounds.top - descent;
3665                        ti.setLocation(Math.round(x), Math.round(y));
3666                        arrMods.add(ti);
3667                    }
3668
3669                }
3670            }
3671            else if (ec == 270701)//static depiction
3672            {
3673                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3674                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3675                    if (strText != null) {
3676                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3677                        labelWidth = Math.round(ti.getTextBounds().width());
3678                        x = bounds.left + (int) (bounds.width() * 0.5);
3679                        x = x - (int) (labelWidth * 0.5);
3680                        y = bounds.top - descent;// + (bounds.height * 0.5);
3681                        //y = y + (labelHeight * 0.5);
3682
3683                        ti.setLocation(Math.round(x), Math.round(y));
3684                        arrMods.add(ti);
3685                    }
3686
3687                }
3688                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3689                    strText = modifiers.get(Modifiers.W_DTG_1);
3690                    if (strText != null) {
3691                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3692                        labelWidth = Math.round(ti.getTextBounds().width());
3693                        x = bounds.left + (int) (bounds.width() * 0.5);
3694                        x = x - (int) (labelWidth * 0.5);
3695                        y = bounds.top + (bounds.height());
3696                        y = y + (labelHeight);
3697
3698                        ti.setLocation(Math.round(x), Math.round(y));
3699                        arrMods.add(ti);
3700                    }
3701                }
3702                if (modifiers.containsKey(Modifiers.N_HOSTILE)) {
3703                    strText = modifiers.get(Modifiers.N_HOSTILE);
3704                    if (strText != null) {
3705                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3706                        TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3707                        labelWidth = Math.round(ti.getTextBounds().width());
3708                        x = bounds.left + (bounds.width()) + bufferXR;//right
3709                        //x = x + labelWidth;//- (labelBounds.width * 0.75);
3710
3711                        duplicate = true;
3712
3713                        x2 = bounds.left;//left
3714                        x2 = x2 - labelWidth - bufferXL;// - (labelBounds.width * 0.25);
3715
3716                        y = bounds.top + (int) (bounds.height() * 0.5);//center
3717                        y = y + (int) ((labelHeight - descent) * 0.5);
3718
3719                        y2 = y;
3720
3721                        ti.setLocation(Math.round(x), Math.round(y));
3722                        ti2.setLocation(Math.round(x2), Math.round(y2));
3723                        arrMods.add(ti);
3724                        arrMods.add(ti2);
3725                    }
3726                }
3727
3728            }
3729            else if(e == 21 && et == 35)//sonobuoys
3730            {
3731                boolean is2525E = (SymbolID.getVersion(symbolID) >= SymbolID.Version_2525E);
3732                //H sitting on center of circle to the right
3733                //T above H
3734                centerPoint = SymbolUtilities.getCMSymbolAnchorPoint(symbolID,RectUtilities.makeRectFFromRect(bounds));
3735                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3736                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3737                    if (strText != null) {
3738                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3739                        TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3740                        labelWidth = Math.round(ti.getTextBounds().width());
3741                        x = bounds.left + (bounds.width()) + bufferXR;//right
3742                        y = centerPoint.y;
3743
3744                        if(is2525E) {
3745                            x = x - (int)(bounds.width() * 0.2);
3746                            y = (int) (bounds.top + (bounds.height() / 2));
3747                        }
3748
3749                        ti.setLocation(Math.round(x), Math.round(y));
3750                        arrMods.add(ti);
3751                    }
3752                }
3753                if (est == 0 || est == 1 || est == 4 || est == 7 || est == 8 || est == 15) {
3754                    if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3755                        strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3756                        if (strText != null) {
3757                            ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3758                            TextInfo ti2 = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3759                            labelWidth = Math.round(ti.getTextBounds().width());
3760                            x = (bounds.left + (bounds.width()) + bufferXR - (int)(bounds.width() * 0.2) );//right
3761                            y = centerPoint.y - labelHeight;
3762
3763                            if(is2525E) {
3764                                y = (bounds.top + (bounds.height() / 2)) - labelHeight;
3765                            }
3766
3767                            ti.setLocation(Math.round(x), Math.round(y));
3768                            arrMods.add(ti);
3769                        }
3770                    }
3771                }
3772            }
3773            else if(ec == 282001 || //tower, low
3774                    ec == 282002)   //tower, high
3775            {
3776                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) {
3777                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3778                    if (strText != null) {
3779                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3780                        labelWidth = Math.round(ti.getTextBounds().width());
3781                        x = bounds.left + (int) (bounds.width() * 0.7);
3782                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3783                        //y = y + (labelHeight * 0.5);
3784
3785                        ti.setLocation(Math.round(x), Math.round(y));
3786                        arrMods.add(ti);
3787                    }
3788
3789                }
3790            }
3791            else if(ec == 180600)//TACAN
3792            {
3793                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3794                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3795                    if (strText != null) {
3796                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3797                        labelWidth = Math.round(ti.getTextBounds().width());
3798                        x = bounds.left + bounds.width() + bufferXR;
3799                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3800                        //y = y + (labelHeight * 0.5);
3801
3802                        ti.setLocation(Math.round(x), Math.round(y));
3803                        arrMods.add(ti);
3804                    }
3805
3806                }
3807            }
3808            else if(ec == 210300)//Defended Asset
3809            {
3810                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3811                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3812                    if (strText != null) {
3813                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3814                        labelWidth = Math.round(ti.getTextBounds().width());
3815                        x = bounds.left - labelWidth - bufferXL;
3816                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3817                        //y = y + (labelHeight * 0.5);
3818
3819                        ti.setLocation(Math.round(x), Math.round(y));
3820                        arrMods.add(ti);
3821                    }
3822
3823                }
3824            }
3825            else if(ec == 210600)//Air Detonation
3826            {
3827                if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) {
3828                    strText = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
3829                    if (strText != null) {
3830                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3831                        labelWidth = Math.round(ti.getTextBounds().width());
3832                        x = bounds.left + (bounds.width() + bufferXR);
3833                        y = bounds.top + labelHeight;// + (bounds.height * 0.5);
3834                        //y = y + (labelHeight * 0.5);
3835
3836                        ti.setLocation(Math.round(x), Math.round(y));
3837                        arrMods.add(ti);
3838                    }
3839
3840                }
3841            }
3842            else if(ec == 210800)//Impact Point
3843            {
3844                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3845                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3846                    if (strText != null) {
3847                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3848                        labelWidth = Math.round(ti.getTextBounds().width());
3849                        x = bounds.left + (int) (bounds.width() * 0.65f);
3850//                  x = x - (labelBounds.width * 0.5);
3851                        y = bounds.top + (int) (bounds.height() * 0.25f);
3852                        y = y + (int) (labelHeight * 0.5f);
3853                        //y = y + (labelHeight * 0.5);
3854
3855                        ti.setLocation(Math.round(x), Math.round(y));
3856                        arrMods.add(ti);
3857                    }
3858
3859                }
3860            }
3861            else if(ec == 211000)//Launched Torpedo
3862            {
3863                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3864                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3865                    if (strText != null) {
3866                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3867                        labelWidth = Math.round(ti.getTextBounds().width());
3868                        x = (int)(bounds.left + (bounds.width() * 0.5) - (labelWidth/2));
3869                        y = bounds.top - bufferY;
3870
3871                        ti.setLocation(Math.round(x), Math.round(y));
3872                        arrMods.add(ti);
3873                    }
3874
3875                }
3876            }
3877            else if(ec == 214900 || ec == 215600)//General Sea SubSurface Station & General Sea Surface Station
3878            {
3879                if (modifiers.containsKey(Modifiers.W_DTG_1)) {
3880                    strText = modifiers.get(Modifiers.W_DTG_1);
3881                    if (strText != null) {
3882                        ti = new TextInfo(strText + " - ", 0, 0, modifierFont, modifierFontName);
3883                        x = bounds.left + (bounds.width() + bufferXR);
3884                        y = bounds.top + labelHeight;
3885
3886                        ti.setLocation(Math.round(x), Math.round(y));
3887                        arrMods.add(ti);
3888                    }
3889
3890                }
3891                if (modifiers.containsKey(Modifiers.W1_DTG_2)) {
3892                    strText = modifiers.get(Modifiers.W1_DTG_2);
3893                    if (strText != null) {
3894                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3895                        x = bounds.left + (bounds.width() + bufferXR);
3896                        y = bounds.top + (labelHeight * 2);
3897
3898                        ti.setLocation(Math.round(x), Math.round(y));
3899                        arrMods.add(ti);
3900                    }
3901
3902                }
3903                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3904                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3905                    if (strText != null) {
3906                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3907                        x = bounds.left + (bounds.width() + bufferXR);
3908                        y = bounds.top + (labelHeight * 3);
3909
3910                        ti.setLocation(Math.round(x), Math.round(y));
3911                        arrMods.add(ti);
3912                    }
3913
3914                }
3915            }
3916            else if(ec == 217000)//Shore Control Station
3917            {
3918                if (modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)) {
3919                    strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
3920                    if (strText != null) {
3921                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3922                        labelWidth = Math.round(ti.getTextBounds().width());
3923                        x = (int)(bounds.left + (bounds.width() * 0.5) - (labelWidth/2));
3924                        y = bounds.top + bounds.height() + labelHeight + bufferY;
3925
3926                        ti.setLocation(Math.round(x), Math.round(y));
3927                        arrMods.add(ti);
3928                    }
3929
3930                }
3931            }
3932            else if(ec == 250600)//Known Point
3933            {
3934                if (modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)) {
3935                    strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
3936                    if (strText != null) {
3937                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3938                        labelWidth = Math.round(ti.getTextBounds().width());
3939                        x = bounds.left + (bounds.width() + bufferXR);
3940//                  x = x - (labelBounds.width * 0.5);
3941                        y = bounds.top + (int) (bounds.height() * 0.25f);
3942                        y = y + (int) (labelHeight * 0.5f);
3943                        //y = y + (labelHeight * 0.5);
3944
3945                        ti.setLocation(Math.round(x), Math.round(y));
3946                        arrMods.add(ti);
3947                    }
3948
3949                }
3950            }
3951        }
3952        else if(ss == SymbolID.SymbolSet_Atmospheric)
3953        {
3954            String modX = null;
3955            if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
3956                modX = (modifiers.get(Modifiers.X_ALTITUDE_DEPTH));
3957
3958            if(ec == 162300)//Freezing Level
3959            {
3960                strText = "0" + (char)(176) + ":";
3961                if(modX != null)
3962                    strText += modX;
3963                else
3964                    strText += "?";
3965
3966                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3967                labelWidth = Math.round(ti.getTextBounds().width());
3968                //One modifier symbols and modifier goes in center
3969                x = bounds.left + (int) (bounds.width() * 0.5f);
3970                x = x - (int) (labelWidth * 0.5f);
3971                y = bounds.top + (int) (bounds.height() * 0.5f);
3972                y = y + (int) ((labelHeight - modifierFontDescent) * 0.5f);
3973
3974                ti.setLocation(Math.round(x), Math.round(y));
3975                arrMods.add(ti);
3976            }
3977            else if(ec == 162200)//tropopause Level
3978            {
3979                strText = "X?";
3980                if(modX != null)
3981                    strText = modX;
3982
3983                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
3984                labelWidth = Math.round(ti.getTextBounds().width());
3985                //One modifier symbols and modifier goes in center
3986                x = bounds.left + (int) (bounds.width() * 0.5f);
3987                x = x - (int) (labelWidth * 0.5f);
3988                y = bounds.top + (int) (bounds.height() * 0.5f);
3989                y = y + (int) ((labelHeight - modifierFontDescent) * 0.5f);
3990
3991                ti.setLocation(Math.round(x), Math.round(y));
3992                arrMods.add(ti);
3993            }
3994            else if(ec == 110102)//tropopause Low
3995            {
3996                strText = "X?";
3997                if(modX != null)
3998                    strText = modX;
3999
4000                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4001                labelWidth = Math.round(ti.getTextBounds().width());
4002                //One modifier symbols and modifier goes in center
4003                x = bounds.left + (int) (bounds.width() * 0.5f);
4004                x = x - (int) (labelWidth * 0.5f);
4005                y = bounds.top + (int) (bounds.height() * 0.5f);
4006                y = y - descent;
4007
4008                ti.setLocation(Math.round(x), Math.round(y));
4009                arrMods.add(ti);
4010            }
4011            else if(ec == 110202)//tropopause High
4012            {
4013                strText = "X?";
4014                if(modX != null)
4015                    strText = modX;
4016
4017                ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4018                labelWidth = Math.round(ti.getTextBounds().width());
4019                //One modifier symbols and modifier goes in center
4020                x = bounds.left + (int) (bounds.width() * 0.5f);
4021                x = x - (int) (labelWidth * 0.5f);
4022                y = bounds.top + (int) (bounds.height() * 0.5f);
4023                //y = y + (int) ((labelHeight * 0.5f) + (labelHeight/2));
4024                y = y + (int) (((labelHeight * 0.5f) - (labelHeight/2)) + labelHeight - descent);
4025
4026                ti.setLocation(Math.round(x), Math.round(y));
4027                arrMods.add(ti);
4028            }
4029        }
4030        // </editor-fold>
4031
4032        // <editor-fold defaultstate="collapsed" desc="DOM Arrow">
4033        Point[] domPoints = null;
4034        Rect domBounds = null;
4035
4036        if (modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT) &&
4037                SymbolUtilities.isCBRNEvent(symbolID))//CBRN events
4038        {
4039            strText = modifiers.get(Modifiers.Q_DIRECTION_OF_MOVEMENT);
4040            if(strText != null && SymbolUtilities.isNumber(strText))
4041            {
4042                    float q = Float.parseFloat(strText);
4043                    Rect tempBounds = new Rect(bounds);
4044                    tempBounds.union(RectUtilities.getCenterX(bounds), yForY);
4045        
4046                    domPoints = createDOMArrowPoints(symbolID, tempBounds, sdi.getCenterPoint(), q, false, modifierFontHeight);
4047        
4048                    domBounds = RectUtilities.makeRect(domPoints[0].x, domPoints[0].y, 1, 1);
4049        
4050                    Point temp = null;
4051                    for (int i = 1; i < 6; i++)
4052                    {
4053                        temp = domPoints[i];
4054                        if (temp != null)
4055                        {
4056                            domBounds.union(temp.x, temp.y);
4057                        }
4058                    }
4059                    imageBounds.union(domBounds);
4060            }
4061        }
4062        // </editor-fold>
4063
4064        // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
4065        if (SymbolUtilities.hasFDI(symbolID))
4066        {
4067            //create feint indicator /\
4068            fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
4069            fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
4070            fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
4071
4072
4073            fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
4074            fdiBounds.union(fdiTop.x, fdiTop.y);
4075            fdiBounds.union(fdiRight.x, fdiRight.y);
4076
4077            float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4078            RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
4079
4080            ti = new TextInfo("TEST",0,0, modifierFont, modifierFontName);
4081            if (ti != null && SymbolUtilities.isCBRNEvent(symbolID))
4082            {
4083                int shiftY = Math.round(symbolBounds.top - ti.getTextBounds().height() - 2);
4084                fdiLeft.offset(0, shiftY);
4085                fdiTop.offset(0, shiftY);
4086                fdiRight.offset(0, shiftY);
4087                fdiBounds.offset(0, shiftY);
4088            }
4089
4090            imageBounds.union(fdiBounds);
4091
4092        }
4093        // </editor-fold>
4094
4095        // <editor-fold defaultstate="collapsed" desc="Shift Points and Draw">
4096        Rect modifierBounds = null;
4097        if (arrMods != null && arrMods.size() > 0)
4098        {
4099
4100            //build modifier bounds/////////////////////////////////////////
4101            modifierBounds = arrMods.get(0).getTextOutlineBounds();
4102            int size = arrMods.size();
4103            TextInfo tempShape = null;
4104            for (int i = 1; i < size; i++)
4105            {
4106                tempShape = arrMods.get(i);
4107                modifierBounds.union(tempShape.getTextOutlineBounds());
4108            }
4109
4110        }
4111
4112        if (modifierBounds != null || domBounds != null || fdiBounds != null)
4113        {
4114
4115            if (modifierBounds != null)
4116            {
4117                imageBounds.union(modifierBounds);
4118            }
4119            if (domBounds != null)
4120            {
4121                imageBounds.union(domBounds);
4122            }
4123            if (fdiBounds != null)
4124            {
4125                imageBounds.union(fdiBounds);
4126            }
4127
4128            //shift points if needed////////////////////////////////////////
4129            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4130            {
4131                int shiftX = Math.abs(imageBounds.left);
4132                int shiftY = Math.abs(imageBounds.top);
4133
4134                //shift mobility points
4135                int size = arrMods.size();
4136                TextInfo tempShape = null;
4137                for (int i = 0; i < size; i++)
4138                {
4139                    tempShape = arrMods.get(i);
4140                    tempShape.shift(shiftX, shiftY);
4141                }
4142                if(modifierBounds != null)
4143                    modifierBounds.offset(shiftX, shiftY);
4144
4145                if (domBounds != null)
4146                {
4147                    for (int i = 0; i < 6; i++)
4148                    {
4149                        Point temp = domPoints[i];
4150                        if (temp != null)
4151                        {
4152                            temp.offset(shiftX, shiftY);
4153                        }
4154                    }
4155                    domBounds.offset(shiftX, shiftY);
4156                }
4157
4158                //If there's an FDI
4159                if (fdiBounds != null)
4160                {
4161                    fdiBounds.offset(shiftX, shiftY);
4162                    fdiLeft.offset(shiftX, shiftY);
4163                    fdiTop.offset(shiftX, shiftY);
4164                    fdiRight.offset(shiftX, shiftY);
4165                }
4166
4167                //shift image points
4168                centerPoint.offset(shiftX, shiftY);
4169                symbolBounds.offset(shiftX, shiftY);
4170                imageBounds.offset(shiftX, shiftY);
4171            }
4172
4173
4174            if (attributes.containsKey(MilStdAttributes.TextColor))
4175            {
4176                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4177                if(alpha > -1)
4178                    textColor.setAlpha(alpha);
4179            }
4180            if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4181            {
4182                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4183                if(alpha > -1)
4184                    textBackgroundColor.setAlpha(alpha);
4185            }
4186
4187            if(sdi instanceof ImageInfo) {
4188                ii = (ImageInfo)sdi;
4189                //Render modifiers//////////////////////////////////////////////////
4190                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4191                Canvas ctx = new Canvas(bmp);
4192
4193                //render////////////////////////////////////////////////////////
4194                //draw original icon with potential modifiers.
4195                ctx.drawBitmap(ii.getImage(), symbolBounds.left, symbolBounds.top, null);
4196                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4197
4198
4199                renderText(ctx, arrMods, textColor, textBackgroundColor, modifierFont);
4200
4201                //draw DOM arrow
4202                if (domBounds != null)
4203                {
4204                    drawDOMArrow(ctx, domPoints, alpha, lineColor);
4205                }
4206
4207                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4208                if (fdiBounds != null) {
4209
4210                    Paint fdiPaint = new Paint();
4211                    fdiPaint.setAntiAlias(true);
4212                    fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
4213                    if (alpha > -1)
4214                        fdiPaint.setAlpha(alpha);
4215                    fdiPaint.setStyle(Style.STROKE);
4216
4217                    int dpi = RendererSettings.getInstance().getDeviceDPI();
4218                    int lineLength = dpi / 96 * 6;
4219                    int lineGap = dpi / 96 * 4;
4220
4221                    /// ///////////////////////////////////
4222                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4223                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4224                    //distance = distance / 14f;
4225                    lineGap = (int)((distance / 14f) * 2);
4226                    lineLength = (int)((distance / 14f) * 3);
4227                    /// //////////////////////////////////
4228
4229                    fdiPaint.setPathEffect(new DashPathEffect(new float[]
4230                            {
4231                                    lineLength, lineGap
4232                            }, 0));
4233
4234                    float fdiStrokeWidth = Math.round(dpi / 96f);
4235                    if (fdiStrokeWidth < 2)
4236                        fdiStrokeWidth = 2;
4237
4238                    fdiPaint.setStrokeCap(Cap.ROUND);
4239                    fdiPaint.setStrokeJoin(Join.MITER);
4240                    fdiPaint.setStrokeWidth(fdiStrokeWidth);
4241
4242                    Path fdiPath = new Path();
4243
4244                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4245                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4246                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4247                    fdiPath.lineTo(fdiRight.x, fdiRight.y);
4248                    ctx.drawPath(fdiPath, fdiPaint);
4249
4250                    fdiBounds = null;
4251
4252                }
4253                //</editor-fold>
4254
4255                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4256                ctx = null;
4257            }
4258            else if(sdi instanceof SVGSymbolInfo)
4259            {
4260                float strokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4261                if(strokeWidth < 1)
4262                    strokeWidth=1;
4263                String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
4264                String svgStrokeWidth = String.valueOf(strokeWidth);//"3";
4265
4266                ssi = (SVGSymbolInfo)sdi;
4267                StringBuilder sbSVG = new StringBuilder();
4268                sbSVG.append(ssi.getSVG());
4269                sbSVG.append(renderTextElements(arrMods,textColor,textBackgroundColor));
4270
4271                // <editor-fold defaultstate="collapsed" desc="DOM arrow">
4272                if (domBounds != null && domPoints.length == 6)
4273                {
4274                    SVGPath domPath = new SVGPath() ;
4275
4276                    domPath.moveTo(domPoints[0].x, domPoints[0].y);
4277                    if (domPoints[1] != null)
4278                    {
4279                        domPath.lineTo(domPoints[1].x, domPoints[1].y);
4280                    }
4281                    if (domPoints[2] != null)
4282                    {
4283                        domPath.lineTo(domPoints[2].x, domPoints[2].y);
4284                    }
4285                    sbSVG.append(domPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,null));
4286
4287                    domPath = new SVGPath();
4288
4289                    domPath.moveTo(domPoints[3].x, domPoints[3].y);
4290                    domPath.lineTo(domPoints[4].x, domPoints[4].y);
4291                    domPath.lineTo(domPoints[5].x, domPoints[5].y);
4292                    sbSVG.append(domPath.toSVGElement(null,0f,svgStroke,1f,1f,null));
4293
4294                    domBounds = null;
4295                    domPoints = null;
4296                }
4297                // </editor-fold>
4298
4299                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4300                if (fdiBounds != null)
4301                {
4302
4303                    /*int dpi = RendererSettings.getInstance().getDeviceDPI();
4304                    int lineLength = dpi / 96 * 6;
4305                    int lineGap = dpi / 96 * 4;
4306                    String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
4307
4308                    /// ///////////////////////////////////
4309                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4310                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4311                    //distance = distance / 14f;
4312                    int lineGap = (int)((distance / 14f) * 2);
4313                    int lineLength = (int)((distance / 14f) * 3);
4314                    String svgFDIDashArray = "" + lineLength + " " + lineGap;
4315                    /// //////////////////////////////////
4316
4317                    SVGPath fdiPath = new SVGPath();
4318                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4319                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4320                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4321                    fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
4322
4323                    fdiPath.setLineDash(svgFDIDashArray);
4324
4325                    sbSVG.append(fdiPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,"round"));
4326                    //sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray));
4327                }
4328                //</editor-fold>
4329
4330                newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
4331            }
4332
4333
4334
4335
4336            // <editor-fold defaultstate="collapsed" desc="Cleanup">
4337            //ctx = null;
4338            // </editor-fold>
4339
4340            return newsdi;
4341
4342        }
4343        else
4344        {
4345            return null;
4346        }
4347        // </editor-fold>
4348
4349    }
4350
4351    /**
4352     * Process modifiers for action points
4353     */
4354    public static SymbolDimensionInfo ProcessTGSPModifiers(SymbolDimensionInfo sdi, String symbolID, Map<String,String> modifiers, Map<String,String> attributes, Color lineColor)
4355    {
4356
4357        Paint modifierFont = getFont(attributes);
4358        float[] hd = getFontHeightandDescent(modifierFont);
4359        float modifierFontHeight = hd[0];
4360        float modifierFontDescent = hd[1];
4361
4362        String modifierFontName = RendererSettings.getInstance().getModiferFontProps()[0];
4363        if(attributes != null && attributes.containsKey(MilStdAttributes.FontFamily))
4364        {
4365            String temp = attributes.get(MilStdAttributes.FontFamily);
4366            if(temp != null && !temp.isEmpty())
4367                modifierFontName = temp;
4368        }
4369
4370        // <editor-fold defaultstate="collapsed" desc="Variables">
4371        ImageInfo ii = null;
4372        SVGSymbolInfo ssi = null;
4373
4374        int bufferXL = 6;
4375        int bufferXR = 4;
4376        int bufferY = 2;
4377        int bufferText = 2;
4378        int centerOffset = 1; //getCenterX/Y function seems to go over by a pixel
4379        int x = 0;
4380        int y = 0;
4381        int x2 = 0;
4382        int y2 = 0;
4383
4384        //Feint Dummy Indicator variables
4385        Rect fdiBounds = null;
4386        Point fdiTop = null;
4387        Point fdiLeft = null;
4388        Point fdiRight = null;
4389
4390        int outlineOffset = RS.getTextOutlineWidth();
4391        int labelHeight = 0;
4392        int labelWidth = 0;
4393        int alpha = -1;
4394        SymbolDimensionInfo newsdi = null;
4395        
4396        Color textColor = lineColor;
4397        Color textBackgroundColor = null;
4398
4399        ArrayList<TextInfo> arrMods = new ArrayList<TextInfo>();
4400        boolean duplicate = false;
4401
4402        MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
4403
4404
4405        if (attributes.containsKey(MilStdAttributes.Alpha))
4406        {
4407            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
4408        }
4409
4410        Rect bounds = new Rect(sdi.getSymbolBounds());
4411        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
4412        Point centerPoint = new Point(sdi.getCenterPoint());
4413        Rect imageBounds = new Rect(sdi.getImageBounds());
4414
4415        centerPoint = new Point(Math.round(sdi.getCenterPoint().x), Math.round(sdi.getCenterPoint().y));
4416
4417        boolean byLabelHeight = false;
4418
4419        labelHeight = Math.round(modifierFontHeight + 0.5f);
4420        int maxHeight = (symbolBounds.height());
4421        if ((labelHeight * 3) > maxHeight)
4422        {
4423            byLabelHeight = true;
4424        }
4425
4426        int descent = (int) (modifierFontDescent + 0.5f);
4427        int yForY = -1;
4428
4429        Rect labelBounds1 = null;//text.getPixelBounds(null, 0, 0);
4430        Rect labelBounds2 = null;
4431        String strText = "";
4432        String strText1 = "";
4433        String strText2 = "";
4434        TextInfo text1 = null;
4435        TextInfo text2 = null;
4436
4437        String basicID = SymbolUtilities.getBasicSymbolID(symbolID);
4438
4439        if (outlineOffset > 2)
4440        {
4441            outlineOffset = ((outlineOffset - 1) / 2);
4442        }
4443        else
4444        {
4445            outlineOffset = 0;
4446        }
4447
4448        /*bufferXL += outlineOffset;
4449         bufferXR += outlineOffset;
4450         bufferY += outlineOffset;
4451         bufferText += outlineOffset;*/
4452        // </editor-fold>
4453        // <editor-fold defaultstate="collapsed" desc="Process Modifiers">
4454        TextInfo ti = null;
4455
4456        {
4457            if (msi.getModifiers().contains(Modifiers.N_HOSTILE) && modifiers.containsKey(Modifiers.N_HOSTILE))
4458            {
4459                strText = modifiers.get(Modifiers.N_HOSTILE);
4460                if(strText != null)
4461                {
4462                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4463        
4464                        x = bounds.left + bounds.width() + bufferXR;
4465        
4466                        if (!byLabelHeight)
4467                        {
4468                            y = ((bounds.height() / 3) * 2);//checkpoint, get box above the point
4469                            y = bounds.top + y;
4470                        }
4471                        else
4472                        {
4473                            //y = ((labelHeight + bufferText) * 3);
4474                            //y = bounds.y + y - descent;
4475                            y = bounds.top + bounds.height();
4476                        }
4477        
4478                        ti.setLocation(x, y);
4479                        arrMods.add(ti);
4480                }
4481
4482            }
4483            if (msi.getModifiers().contains(Modifiers.H_ADDITIONAL_INFO_1) && modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
4484            {
4485                strText = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
4486                if(strText != null)
4487                {
4488                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4489                        labelWidth = Math.round(ti.getTextBounds().width());
4490        
4491                        x = bounds.left + (int) (bounds.width() * 0.5f);
4492                        x = x - (int) (labelWidth * 0.5f);
4493                        y = bounds.top - descent;
4494        
4495                        ti.setLocation(x, y);
4496                        arrMods.add(ti);
4497                }
4498            }
4499            if (msi.getModifiers().contains(Modifiers.H1_ADDITIONAL_INFO_2) && modifiers.containsKey(Modifiers.H1_ADDITIONAL_INFO_2))
4500            {
4501                strText = modifiers.get(Modifiers.H1_ADDITIONAL_INFO_2);
4502                if(strText != null)
4503                {
4504                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4505                        labelWidth = Math.round(ti.getTextBounds().width());
4506        
4507                        x = bounds.left + (int) (bounds.width() * 0.5);
4508                        x = x - (int) (labelWidth * 0.5);
4509                    y = bounds.top + labelHeight - descent + (int) (bounds.height() * 0.07);
4510        
4511                        ti.setLocation(x, y);
4512                        arrMods.add(ti);
4513                }
4514            }
4515            if (msi.getModifiers().contains(Modifiers.A_SYMBOL_ICON))
4516            {
4517                if(modifiers.containsKey(Modifiers.A_SYMBOL_ICON))
4518                    strText = modifiers.get(Modifiers.A_SYMBOL_ICON);
4519                else if(SymbolID.getEntityCode(symbolID)==321706)//NATO Multiple Supply Class Point
4520                    strText = "ALL?";//make it clear the required 'A' value wasn't set for this symbol.
4521
4522                if(strText != null)
4523                {
4524                    ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4525                    labelWidth = Math.round(ti.getTextBounds().width());
4526
4527                    x = bounds.left + (int) (bounds.width() * 0.5);
4528                    x = x - (int) (labelWidth * 0.5);
4529                    y = bounds.top + labelHeight - descent + (int) (bounds.height() * 0.07);
4530
4531                    ti.setLocation(x, y);
4532                    arrMods.add(ti);
4533                }
4534            }
4535            if (msi.getModifiers().contains(Modifiers.W_DTG_1) && modifiers.containsKey(Modifiers.W_DTG_1))
4536            {
4537                strText = modifiers.get(Modifiers.W_DTG_1);
4538                if(strText != null)
4539                {
4540                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4541                        labelWidth = Math.round(ti.getTextBounds().width());
4542        
4543                        x = bounds.left - labelWidth - bufferXL;
4544                        y = bounds.top + labelHeight - descent;
4545        
4546                        ti.setLocation(x, y);
4547                        arrMods.add(ti);
4548                }
4549            }
4550            if (msi.getModifiers().contains(Modifiers.W1_DTG_2) && modifiers.containsKey(Modifiers.W1_DTG_2))
4551            {
4552                strText = modifiers.get(Modifiers.W1_DTG_2);
4553                if(strText != null)
4554                {
4555                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4556                        labelWidth = Math.round(ti.getTextBounds().width());
4557        
4558                        x = bounds.left - labelWidth - bufferXL;
4559        
4560                        y = ((labelHeight - descent + bufferText) * 2);
4561                        y = bounds.top + y;
4562        
4563                        ti.setLocation(x, y);
4564                        arrMods.add(ti);
4565                }
4566            }
4567            if (msi.getModifiers().contains(Modifiers.T_UNIQUE_DESIGNATION_1) && modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
4568            {
4569                strText = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
4570                if(strText != null)
4571                {
4572                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4573        
4574                        x = bounds.left + bounds.width() + bufferXR;
4575                        y = bounds.top + labelHeight - descent;
4576        
4577                        ti.setLocation(x, y);
4578                        arrMods.add(ti);
4579                }
4580            }
4581            if (msi.getModifiers().contains(Modifiers.T1_UNIQUE_DESIGNATION_2) && modifiers.containsKey(Modifiers.T1_UNIQUE_DESIGNATION_2))
4582            {
4583                strText = modifiers.get(Modifiers.T1_UNIQUE_DESIGNATION_2);
4584                if(strText != null)
4585                {
4586                        ti = new TextInfo(strText, 0, 0, modifierFont, modifierFontName);
4587                        labelWidth = Math.round(ti.getTextBounds().width());
4588        
4589                        //points
4590                        x = bounds.left + (int) (bounds.width() * 0.5);
4591                        x = x - (int) (labelWidth * 0.5);
4592                        //y = bounds.y + (bounds.height * 0.5);
4593        
4594                        y = (int) ((bounds.height() * 0.55));//633333333
4595                        y = bounds.top + y;
4596
4597                    int ec = SymbolID.getEntityCode(symbolID);
4598                    if((ec >= 281800 && ec <= 281809) || ec == 321100)
4599                    {
4600                        y = (int) ((bounds.height() * 0.63));
4601                        y = (int)bounds.top + y;
4602                    }
4603        
4604                        ti.setLocation(x, y);
4605                        arrMods.add(ti);
4606                }
4607            }
4608            // <editor-fold defaultstate="collapsed" desc="Build Feint Dummy Indicator">
4609            if (SymbolUtilities.hasFDI(symbolID))
4610            {
4611                //create feint indicator /\
4612                fdiLeft = new Point((int) symbolBounds.left, (int) symbolBounds.top);
4613                fdiRight = new Point((int) (symbolBounds.left + symbolBounds.width()), (int) symbolBounds.top);
4614                fdiTop = new Point(Math.round(RectUtilities.getCenterX(symbolBounds)), Math.round(symbolBounds.top - (symbolBounds.width() * .5f)));
4615
4616
4617                fdiBounds = RectUtilities.makeRect(fdiLeft.x, fdiLeft.y, 1, 1);
4618                fdiBounds.union(fdiTop.x, fdiTop.y);
4619                fdiBounds.union(fdiRight.x, fdiRight.y);
4620
4621                float fdiStrokeWidth = Math.round(RendererSettings.getInstance().getDeviceDPI() / 96f);
4622                RectUtilities.grow(fdiBounds,Math.round(fdiStrokeWidth/2));
4623
4624                ti = new TextInfo("TEST",0,0, modifierFont, modifierFontName);
4625                if (ti != null)
4626                {
4627                    int shiftY = Math.round(symbolBounds.top - ti.getTextBounds().height() - 2);
4628                    fdiLeft.offset(0, shiftY);
4629                    fdiTop.offset(0, shiftY);
4630                    fdiRight.offset(0, shiftY);
4631                    fdiBounds.offset(0, shiftY);
4632                }
4633
4634                imageBounds.union(fdiBounds);
4635
4636            }
4637            // </editor-fold>
4638        }
4639
4640        // </editor-fold>
4641        // <editor-fold defaultstate="collapsed" desc="Shift Points and Draw">
4642        Rect modifierBounds = null;
4643        if (arrMods != null && arrMods.size() > 0)
4644        {
4645
4646            //build modifier bounds/////////////////////////////////////////
4647            modifierBounds = arrMods.get(0).getTextOutlineBounds();
4648            int size = arrMods.size();
4649            TextInfo tempShape = null;
4650            for (int i = 1; i < size; i++)
4651            {
4652                tempShape = arrMods.get(i);
4653                modifierBounds.union(tempShape.getTextOutlineBounds());
4654            }
4655
4656        }
4657
4658        if(fdiBounds != null)
4659        {
4660            if(modifierBounds != null)
4661                modifierBounds.union(fdiBounds);
4662            else
4663                modifierBounds = fdiBounds;
4664        }
4665
4666        if (modifierBounds != null)
4667        {
4668
4669            imageBounds.union(modifierBounds);
4670
4671            //shift points if needed////////////////////////////////////////
4672            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4673            {
4674                int shiftX = Math.abs(imageBounds.left);
4675                int shiftY = Math.abs(imageBounds.top);
4676
4677                //shift mobility points
4678                int size = arrMods.size();
4679                TextInfo tempShape = null;
4680                for (int i = 0; i < size; i++)
4681                {
4682                    tempShape = arrMods.get(i);
4683                    tempShape.shift(shiftX, shiftY);
4684                }
4685                modifierBounds.offset(shiftX, shiftY);
4686
4687                //shift image points
4688                centerPoint.offset(shiftX, shiftY);
4689                symbolBounds.offset(shiftX, shiftY);
4690                imageBounds.offset(shiftX, shiftY);
4691
4692                //If there's an FDI
4693                if (fdiBounds != null)
4694                {
4695                    fdiBounds.offset(shiftX, shiftY);
4696                    fdiLeft.offset(shiftX, shiftY);
4697                    fdiTop.offset(shiftX, shiftY);
4698                    fdiRight.offset(shiftX, shiftY);
4699                }
4700            }
4701
4702            if (attributes.containsKey(MilStdAttributes.TextColor))
4703            {
4704                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4705                if(alpha > -1)
4706                    textColor.setAlpha(alpha);
4707            }
4708            if (attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4709            {
4710                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4711                if(alpha > -1)
4712                    textBackgroundColor.setAlpha(alpha);
4713            }
4714
4715            if(sdi instanceof ImageInfo)
4716            {
4717                ii = (ImageInfo) sdi;
4718                //Render modifiers//////////////////////////////////////////////////
4719                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4720                Canvas ctx = new Canvas(bmp);
4721
4722                //draw original icon with potential modifiers.
4723                ctx.drawBitmap(ii.getImage(), symbolBounds.left, symbolBounds.top, null);
4724                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4725
4726
4727                renderText(ctx, arrMods, textColor, textBackgroundColor, modifierFont);
4728
4729                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4730                if (fdiBounds != null) {
4731
4732                    Paint fdiPaint = new Paint();
4733                    fdiPaint.setAntiAlias(true);
4734                    fdiPaint.setColor(lineColor.toInt());/// setARGB(255, 0, 0, 0);
4735                    if (alpha > -1)
4736                        fdiPaint.setAlpha(alpha);
4737                    fdiPaint.setStyle(Style.STROKE);
4738
4739                    int dpi = RendererSettings.getInstance().getDeviceDPI();
4740                    int lineLength = dpi / 96 * 6;
4741                    int lineGap = dpi / 96 * 4;
4742
4743                    /// ///////////////////////////////////
4744                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4745                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4746                    //distance = distance / 14f;
4747                    lineGap = (int)((distance / 14f) * 2);
4748                    lineLength = (int)((distance / 14f) * 3);
4749                    /// //////////////////////////////////
4750
4751                    fdiPaint.setPathEffect(new DashPathEffect(new float[]
4752                            {
4753                                    lineLength, lineGap
4754                            }, 0));
4755
4756                    float fdiStrokeWidth = Math.round(dpi / 96f);
4757                    if (fdiStrokeWidth < 2)
4758                        fdiStrokeWidth = 2;
4759
4760                    fdiPaint.setStrokeCap(Cap.ROUND);
4761                    fdiPaint.setStrokeJoin(Join.MITER);
4762                    fdiPaint.setStrokeWidth(fdiStrokeWidth);
4763
4764                    Path fdiPath = new Path();
4765
4766                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4767                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4768                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4769                    fdiPath.lineTo(fdiRight.x, fdiRight.y);
4770                    ctx.drawPath(fdiPath, fdiPaint);
4771
4772                    fdiBounds = null;
4773
4774                }
4775                //</editor-fold>
4776
4777                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4778            }
4779            else if(sdi instanceof SVGSymbolInfo)
4780            {
4781                String svgStroke = RendererUtilities.colorToHexString(lineColor,false);
4782                String svgStrokeWidth = "3";
4783                String svgAlpha = null;
4784                if(alpha > -1)
4785                    svgAlpha = String.valueOf(alpha);
4786                ssi = (SVGSymbolInfo)sdi;
4787                StringBuilder sbSVG = new StringBuilder();
4788                sbSVG.append(ssi.getSVG());
4789                sbSVG.append(renderTextElements(arrMods,textColor,textBackgroundColor));
4790
4791                //<editor-fold defaultstate="collapsed" desc="Draw FDI">
4792                if (fdiBounds != null)
4793                {
4794                    /*int dpi = RendererSettings.getInstance().getDeviceDPI();
4795                    int lineLength = dpi / 96 * 6;
4796                    int lineGap = dpi / 96 * 4;
4797                    String svgFDIDashArray = "" + lineLength + " " + lineGap;//*/
4798
4799                    /// ///////////////////////////////////
4800                    //Divide line in 14 parts. line is 3 parts to 2 parts gap
4801                    float distance = RendererUtilities.getDistanceBetweenPoints(fdiTop,fdiLeft);
4802                    //distance = distance / 14f;
4803                    int lineGap = (int)((distance / 14f) * 2);
4804                    int lineLength = (int)((distance / 14f) * 3);
4805                    String svgFDIDashArray = "" + lineLength + " " + lineGap;
4806                    /// //////////////////////////////////
4807
4808                    SVGPath fdiPath = new SVGPath();
4809                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4810                    fdiPath.lineTo(fdiLeft.x, fdiLeft.y);
4811                    fdiPath.moveTo(fdiTop.x, fdiTop.y);
4812                    fdiPath.lineTo(fdiRight.x, fdiRight.y);//*/
4813
4814                    fdiPath.setLineDash(svgFDIDashArray);
4815                    sbSVG.append(fdiPath.toSVGElement(svgStroke,Float.parseFloat(svgStrokeWidth),null,1f,1f,"round"));
4816                    //sbSVG.append(Shape2SVG.Convert(fdiPath, svgStroke, null, svgStrokeWidth, svgAlpha, svgAlpha, svgFDIDashArray));
4817                }
4818                //</editor-fold>
4819
4820                newsdi = new SVGSymbolInfo(sbSVG.toString(),centerPoint,symbolBounds,imageBounds);
4821            }
4822
4823            // <editor-fold defaultstate="collapsed" desc="Cleanup">
4824            //ctx = null;
4825
4826            // </editor-fold>
4827        }
4828        // </editor-fold>
4829        return newsdi;
4830
4831    }
4832
4833    private static SymbolDimensionInfo shiftUnitPointsAndDraw(ArrayList<TextInfo> tiArray, SymbolDimensionInfo sdi, Map<String,String> attributes, Paint modifierFont)
4834    {
4835
4836        ImageInfo ii = null;
4837        SVGSymbolInfo ssi = null;
4838        SymbolDimensionInfo newsdi = null;
4839
4840        int alpha = -1;
4841
4842
4843        if (attributes != null && attributes.containsKey(MilStdAttributes.Alpha))
4844        {
4845            alpha = Integer.parseInt(attributes.get(MilStdAttributes.Alpha));
4846        }
4847
4848        Color textColor = Color.BLACK;
4849        Color textBackgroundColor = null;
4850
4851        Rect symbolBounds = new Rect(sdi.getSymbolBounds());
4852        Point centerPoint = new Point(sdi.getCenterPoint());
4853        Rect imageBounds = new Rect(sdi.getImageBounds());
4854        Rect imageBoundsOld = new Rect(sdi.getImageBounds());
4855
4856        Rect modifierBounds = null;
4857        if (tiArray != null && tiArray.size() > 0)
4858        {
4859
4860            //build modifier bounds/////////////////////////////////////////
4861            modifierBounds = tiArray.get(0).getTextOutlineBounds();
4862            int size = tiArray.size();
4863            TextInfo tempShape = null;
4864            for (int i = 1; i < size; i++)
4865            {
4866                tempShape = tiArray.get(i);
4867                modifierBounds.union(tempShape.getTextOutlineBounds());
4868            }
4869
4870        }
4871
4872        if (modifierBounds != null)
4873        {
4874
4875            imageBounds.union(modifierBounds);
4876
4877            //shift points if needed////////////////////////////////////////
4878            if (sdi instanceof ImageInfo && (imageBounds.left < 0 || imageBounds.top < 0))
4879            {
4880                int shiftX = Math.round(Math.abs(imageBounds.left)),
4881                        shiftY = Math.round(Math.abs(imageBounds.top));
4882
4883                //shift mobility points
4884                int size = tiArray.size();
4885                TextInfo tempShape = null;
4886                for (int i = 0; i < size; i++)
4887                {
4888                    tempShape = tiArray.get(i);
4889                    tempShape.shift(shiftX, shiftY);
4890                }
4891                RectUtilities.shift(modifierBounds, shiftX, shiftY);
4892                //modifierBounds.shift(shiftX,shiftY);
4893
4894                //shift image points
4895                centerPoint.offset(shiftX, shiftY);
4896                RectUtilities.shift(symbolBounds, shiftX, shiftY);
4897                RectUtilities.shift(imageBounds, shiftX, shiftY);
4898                RectUtilities.shift(imageBoundsOld, shiftX, shiftY);
4899                /*centerPoint.shift(shiftX, shiftY);
4900                 symbolBounds.shift(shiftX, shiftY);
4901                 imageBounds.shift(shiftX, shiftY);
4902                 imageBoundsOld.shift(shiftX, shiftY);//*/
4903            }
4904
4905            if (attributes != null && attributes.containsKey(MilStdAttributes.TextColor))
4906            {
4907                textColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextColor));
4908                if(alpha > -1)
4909                    textColor.setAlpha(alpha);
4910            }
4911            if (attributes != null && attributes.containsKey(MilStdAttributes.TextBackgroundColor))
4912            {
4913                textBackgroundColor = RendererUtilities.getColorFromHexString(attributes.get(MilStdAttributes.TextBackgroundColor));
4914                if(alpha > -1)
4915                    textBackgroundColor.setAlpha(alpha);
4916            }
4917
4918            if(sdi instanceof ImageInfo)
4919            {
4920                ii = (ImageInfo) sdi;
4921
4922                Bitmap bmp = Bitmap.createBitmap(imageBounds.width(), imageBounds.height(), Config.ARGB_8888);
4923                Canvas ctx = new Canvas(bmp);
4924
4925                //render////////////////////////////////////////////////////////
4926                //draw original icon with potential modifiers.
4927                ctx.drawBitmap(ii.getImage(), imageBoundsOld.left, imageBoundsOld.top, null);
4928                //ctx.drawImage(ii.getImage(),imageBoundsOld.left,imageBoundsOld.top);
4929
4930                renderText(ctx, tiArray, textColor, textBackgroundColor, modifierFont);
4931
4932                newsdi = new ImageInfo(bmp, centerPoint, symbolBounds);
4933            }
4934            else if(sdi instanceof SVGSymbolInfo)
4935            {
4936                ssi = (SVGSymbolInfo)sdi;
4937                StringBuilder sb = new StringBuilder();
4938                sb.append(ssi.getSVG());
4939                sb.append(renderTextElements(tiArray,textColor,textBackgroundColor));
4940                newsdi = new SVGSymbolInfo(sb.toString(),centerPoint,symbolBounds,imageBounds);
4941            }
4942        }
4943
4944        if(newsdi == null)
4945            newsdi = sdi;
4946
4947        return newsdi;
4948    }
4949    private static String renderTextElement(ArrayList<TextInfo> tiArray, Color color, Color backgroundColor)
4950    {
4951        StringBuilder sbSVG = new StringBuilder();
4952
4953        String svgStroke = RendererUtilities.colorToHexString(RendererUtilities.getIdealOutlineColor(color),false);
4954        if(backgroundColor != null)
4955            svgStroke = RendererUtilities.colorToHexString(backgroundColor,false);
4956
4957        String svgFill = RendererUtilities.colorToHexString(color,false);
4958        String svgStrokeWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
4959        for (TextInfo ti : tiArray) {
4960            sbSVG.append(Shape2SVG.Convert(ti, svgStroke,svgFill,svgStrokeWidth,null,null,null));
4961            sbSVG.append("\n");
4962        }
4963
4964        return sbSVG.toString();
4965    }
4966
4967    private static String renderTextElements(ArrayList<TextInfo> tiArray, Color color, Color backgroundColor)
4968    {
4969        String style = null;
4970        String name = tiArray.get(0).getFontName();//"SansSerif";
4971        if(!name.endsWith("serif"))
4972            name += ", sans-serif";
4973        String size = String.valueOf(tiArray.get(0).getFontSize());
4974        String weight = null;
4975        String anchor = null;//"start";
4976        if(tiArray.get(0).getFontStyle() == Typeface.BOLD)
4977            weight = "bold";
4978        StringBuilder sbSVG = new StringBuilder();
4979
4980        String svgStroke = RendererUtilities.colorToHexString(RendererUtilities.getIdealOutlineColor(color),false);
4981        if(backgroundColor != null)
4982            svgStroke = RendererUtilities.colorToHexString(backgroundColor,false);
4983
4984        String svgFill = RendererUtilities.colorToHexString(color,false);
4985        String svgStrokeWidth = String.valueOf(RendererSettings.getInstance().getTextOutlineWidth());
4986        sbSVG.append("\n<g");
4987        sbSVG.append(" font-family=\"").append(name).append('"');
4988        sbSVG.append(" font-size=\"").append(size).append("px\"");
4989        if(weight != null)
4990            sbSVG.append(" font-weight=\"").append(weight).append("\"");
4991        sbSVG.append(" alignment-baseline=\"alphabetic\"");//
4992        sbSVG.append(">");
4993
4994        for (TextInfo ti : tiArray) {
4995            sbSVG.append(Shape2SVG.ConvertForGroup(ti, svgStroke,svgFill,svgStrokeWidth,null,null,null));
4996            sbSVG.append("\n");
4997        }
4998        sbSVG.append("</g>\n");
4999
5000        return sbSVG.toString();
5001    }
5002    private static void renderText(Canvas ctx, ArrayList<TextInfo> tiArray, Color color, Color backgroundColor, Paint font)
5003    {
5004        ModifierRenderer.renderText(ctx, (TextInfo[]) tiArray.toArray(new TextInfo[0]), color, backgroundColor, font);
5005    }
5006
5007    /**
5008     * 
5009     * @param ctx
5010     * @param tiArray
5011     * @param color
5012     * @param backgroundColor 
5013     */
5014    public static void renderText(Canvas ctx, TextInfo[] tiArray, Color color, Color backgroundColor, Paint modifierFont)
5015    {
5016        /*for (TextInfo textInfo : tiArray) 
5017         {
5018         ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);    
5019         }*/
5020
5021        int size = tiArray.length;
5022
5023        int tbm = RS.getTextBackgroundMethod();
5024        int outlineWidth = RS.getTextOutlineWidth();
5025
5026        if (color == null)
5027        {
5028            color = Color.BLACK;
5029        }
5030
5031        Color outlineColor = null;
5032        
5033        if(backgroundColor != null)
5034            outlineColor = backgroundColor;
5035        else
5036            outlineColor = RendererUtilities.getIdealOutlineColor(color);
5037
5038        if (tbm == RendererSettings.TextBackgroundMethod_OUTLINE_QUICK)
5039        {
5040            synchronized (modifierFontMutex) {
5041                //draw text outline
5042                modifierFont.setStyle(Style.FILL);
5043                modifierFont.setStrokeWidth(RS.getTextOutlineWidth());
5044                modifierFont.setColor(outlineColor.toInt());
5045
5046                if (outlineWidth > 2)
5047                    outlineWidth = 2;
5048
5049                if (outlineWidth > 0) {
5050                    for (int i = 0; i < size; i++) {
5051                        TextInfo textInfo = tiArray[i];
5052                        if (outlineWidth > 0) {
5053                            for (int j = 1; j <= outlineWidth; j++) {
5054                                if (j == 1) {
5055                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y - j, modifierFont);
5056                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y - j, modifierFont);
5057                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y + j, modifierFont);
5058                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y + j, modifierFont);
5059
5060                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y, modifierFont);
5061                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y, modifierFont);
5062
5063                                } else {
5064                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y - j, modifierFont);
5065                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y - j, modifierFont);
5066                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y + j, modifierFont);
5067                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y + j, modifierFont);
5068
5069                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x - j, textInfo.getLocation().y, modifierFont);
5070                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x + j, textInfo.getLocation().y, modifierFont);
5071
5072                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y + j, modifierFont);
5073                                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y - j, modifierFont);
5074                                }
5075
5076                            }
5077
5078                        }
5079
5080                    }
5081                }
5082                //draw text
5083                modifierFont.setColor(color.toInt());
5084
5085                for (int j = 0; j < size; j++) {
5086                    TextInfo textInfo = tiArray[j];
5087                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5088                /*Paint outline = new Paint();
5089                 outline.setStyle(Style.STROKE);
5090                 outline.setColor(Color.red.toInt());
5091                 outline.setAlpha(155);
5092                 outline.setStrokeWidth(1f);
5093                 ctx.drawRect(textInfo.getTextBounds(), outline);
5094                 outline.setColor(Color.blue.toInt());
5095                 ctx.drawRect(textInfo.getTextOutlineBounds(), outline);//*/
5096                }
5097            }
5098        }
5099        else if (tbm == RendererSettings.TextBackgroundMethod_OUTLINE)
5100        {
5101            synchronized (modifierFontMutex) {
5102                //draw text outline
5103                //draw text outline
5104                modifierFont.setStyle(Style.STROKE);
5105                modifierFont.setStrokeWidth(RS.getTextOutlineWidth());
5106                modifierFont.setColor(outlineColor.toInt());
5107                if (outlineWidth > 0) {
5108                    for (int i = 0; i < size; i++) {
5109                        TextInfo textInfo = tiArray[i];
5110                        ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5111                    }
5112                }
5113                //draw text
5114                modifierFont.setColor(color.toInt());
5115                modifierFont.setStyle(Style.FILL);
5116                for (int j = 0; j < size; j++) {
5117                    TextInfo textInfo = tiArray[j];
5118                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5119                }
5120            }
5121        }
5122        else if (tbm == RendererSettings.TextBackgroundMethod_COLORFILL)
5123        {
5124            synchronized (modifierFontMutex) {
5125                Paint rectFill = new Paint();
5126                rectFill.setStyle(Paint.Style.FILL);
5127                rectFill.setColor(outlineColor.toARGB());
5128
5129
5130                //draw rectangle
5131                for (int k = 0; k < size; k++) {
5132                    TextInfo textInfo = tiArray[k];
5133                    ctx.drawRect(textInfo.getTextOutlineBounds(), rectFill);
5134                }
5135                //draw text
5136                modifierFont.setColor(color.toInt());
5137                modifierFont.setStyle(Style.FILL);
5138                for (int j = 0; j < size; j++) {
5139                    TextInfo textInfo = tiArray[j];
5140                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5141                }
5142            }
5143        }
5144        else if (tbm == RendererSettings.TextBackgroundMethod_NONE)
5145        {
5146            synchronized (modifierFontMutex) {
5147                modifierFont.setColor(color.toInt());
5148                modifierFont.setStyle(Style.FILL);
5149                for (int j = 0; j < size; j++) {
5150                    TextInfo textInfo = tiArray[j];
5151                    ctx.drawText(textInfo.getText(), textInfo.getLocation().x, textInfo.getLocation().y, modifierFont);
5152                }
5153            }
5154        }
5155    }
5156
5157    /**
5158     *
5159     * @param symbolID
5160     * @param modifiers
5161     * @return int[] where {xposition (-1 left, 0 centered, 1 right), yposition (0 centered, 1+ goes up, 1- goes down),
5162     * centered (0-no, 1-yes)} -999 means passed modifier is not supported by this symbol
5163     */
5164    private static List<Modifier> getLabelPositionIndexes(String symbolID, Map<String,String> modifiers, Map<String,String> attributes)
5165    {
5166        List<Modifier> mods = null;
5167        if(modifiers != null && !modifiers.isEmpty())
5168            mods = new ArrayList<>();
5169        else
5170            return null;
5171
5172        int ver = SymbolID.getVersion(symbolID);
5173        int ss = SymbolID.getSymbolSet(symbolID);
5174        int x = 0;
5175        int y = 0;
5176        boolean centered = true;
5177        int p = RendererSettings.getInstance().getSPModifierPlacement();
5178        boolean strict = (RendererSettings.getInstance().getSPModifierPlacement() == RendererSettings.ModifierPlacement_STRICT);
5179        if(attributes != null && attributes.containsKey(MilStdAttributes.ModifierPlacement))
5180        {
5181            String mp = attributes.get(MilStdAttributes.ModifierPlacement);
5182            if(mp.equals("0") || mp.equals("1") || mp.equals("2"))
5183            {
5184                p = Integer.parseInt(mp);
5185                if(p == 0)
5186                    strict = true;
5187                else
5188                    strict = false;
5189            }
5190        }
5191        String temp = null;
5192        String sep = " ";
5193        if(ss == SymbolID.SymbolSet_DismountedIndividuals) {
5194            ver = SymbolID.Version_2525E;
5195        }
5196
5197        if(ver < SymbolID.Version_2525E)
5198        {
5199            if(ss == SymbolID.SymbolSet_LandUnit ||
5200                    ss == SymbolID.SymbolSet_LandCivilianUnit_Organization)
5201            {
5202
5203                //Only Command & Control has AA; ec.equals("110000").  Always in the middle of the unit.
5204                if(modifiers.containsKey(Modifiers.AA_SPECIAL_C2_HQ))
5205                {
5206                    temp = modifiers.get(Modifiers.AA_SPECIAL_C2_HQ);
5207                    if(temp != null && !temp.isEmpty())
5208                        mods.add(new Modifier("AA", temp, 0, 0, true));
5209                }
5210
5211                //Do top center label
5212                x = 0;//centered
5213                y = 9;//on top of symbol
5214                if(modifiers.containsKey(Modifiers.B_ECHELON))
5215                {
5216                    temp = modifiers.get(Modifiers.B_ECHELON);
5217                    if(temp != null && !temp.isEmpty())
5218                        mods.add(new Modifier("B", temp, x, y, centered));
5219                }
5220
5221                //Do right side labels
5222                x = 1;//on right
5223                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5224                {
5225                    y = 0;//center
5226                    centered = true;//vertically centered, only matters for labels on left and right side
5227                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5228                    if(temp != null && !temp.isEmpty())
5229                        mods.add(new Modifier("H", temp, x, y, centered));
5230                }
5231                else if(!strict)
5232                {
5233                    //if no "H', bring G and M closer to the center
5234                    centered = false;
5235                }
5236
5237                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5238                {
5239                    y = 1;//above center
5240                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5241                    if(temp != null && !temp.isEmpty())
5242                        mods.add(new Modifier("G", temp, x, y, centered));
5243                }
5244
5245                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
5246                {
5247                    y = 2;
5248                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5249                        y--;
5250                    temp = "";
5251                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
5252                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
5253                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5254                        temp += modifiers.get(Modifiers.AS_COUNTRY);
5255                    temp = temp.trim();
5256                    if(temp != null && !temp.isEmpty())
5257                        mods.add(new Modifier("F AS", temp, x, y, centered));
5258                }
5259
5260                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
5261                {
5262                    y = -1;//below center
5263                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
5264                    if(temp != null && !temp.isEmpty())
5265                        mods.add(new Modifier("M", temp, x, y, centered));
5266                }
5267
5268                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5269                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
5270                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5271                {
5272                    y = -2;
5273                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
5274                        y++;
5275                    temp = "";
5276                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5277                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5278                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
5279                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
5280                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5281                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5282                    temp = temp.trim();
5283                    if(temp != null && !temp.isEmpty())
5284                        mods.add(new Modifier("J K P", temp, x, y, centered));
5285                }
5286
5287                //Do left side labels
5288                x = -1;//on left
5289                centered = false;
5290
5291                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5292                {
5293                    y = 1;
5294                    temp = "";
5295                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5296                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5297                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5298                        temp += modifiers.get(Modifiers.Y_LOCATION);
5299
5300                    temp = temp.trim();
5301                    if(temp != null && !temp.isEmpty())
5302                        mods.add(new Modifier("X Y", temp, x, y, centered));
5303                }
5304
5305                if(modifiers.containsKey(Modifiers.W_DTG_1))
5306                {
5307                    y = 2;//above center
5308                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
5309                        y--;
5310                    temp = modifiers.get(Modifiers.W_DTG_1);
5311                    if(temp != null && !temp.isEmpty())
5312                        mods.add(new Modifier("W", temp, x, y, centered));
5313                }
5314
5315                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5316                {
5317                    y = -1;//below center
5318                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5319                    if(temp != null && !temp.isEmpty())
5320                        mods.add(new Modifier("T", temp, x, y, centered));
5321                }
5322
5323                if(modifiers.containsKey(Modifiers.Z_SPEED))
5324                {
5325                    y = -2;
5326                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5327                        y++;
5328                    temp = modifiers.get(Modifiers.Z_SPEED);
5329                    if(temp != null && !temp.isEmpty())
5330                        mods.add(new Modifier(Modifiers.J_EVALUATION_RATING, temp, x, y, centered));
5331                }
5332            }
5333            else if(ss == SymbolID.SymbolSet_LandEquipment ||
5334                    ss == SymbolID.SymbolSet_SignalsIntelligence_Land)
5335            {
5336                //Do top center label
5337                x = 0;//centered
5338                y = 9;//on top of symbol
5339                if(modifiers.containsKey(Modifiers.C_QUANTITY))
5340                {
5341                    temp = modifiers.get(Modifiers.C_QUANTITY);
5342                    if(temp != null && !temp.isEmpty())
5343                        mods.add(new Modifier("C", temp, x, y, centered));
5344                }
5345
5346                //Do right side labels
5347                x = 1;//on right
5348                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
5349                {
5350                    y = 0;//center
5351                    centered = true;//vertically centered, only matters for labels on left and right side
5352                    temp = "";
5353                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5354                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
5355                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
5356                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
5357                    temp = temp.trim();
5358                    if(temp != null && !temp.isEmpty())
5359                        mods.add(new Modifier("H AF", temp, x, y, centered));
5360                }
5361                else if(!strict)
5362                {
5363                    //if no "H', bring G and M closer to the center
5364                    centered = false;
5365                }
5366
5367                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5368                {
5369                    y = 1;//above center
5370                    temp = "";
5371                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5372                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5373                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5374                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
5375                    temp = temp.trim();
5376                    if(temp != null && !temp.isEmpty())
5377                        mods.add(new Modifier("G AQ", temp, x, y, centered));
5378                }
5379
5380                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5381                {
5382                    y = 2;
5383                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
5384                        y--;
5385
5386                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5387                    if(temp != null && !temp.isEmpty())
5388                        mods.add(new Modifier("AS", temp, x, y, centered));
5389                }
5390
5391                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5392                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
5393                        modifiers.containsKey(Modifiers.N_HOSTILE) ||
5394                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5395                {
5396                    y = -1;
5397
5398                    temp = "";
5399                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5400                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5401                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
5402                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
5403                    if(modifiers.containsKey(Modifiers.N_HOSTILE))
5404                        temp += modifiers.get(Modifiers.N_HOSTILE) + sep;
5405                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5406                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5407                    temp = temp.trim();
5408                    if(temp != null && !temp.isEmpty())
5409                        mods.add(new Modifier("J L N P", temp, x, y, centered));
5410                }
5411
5412                //Do left side labels
5413                x = -1;//on left
5414
5415                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
5416                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
5417                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
5418                {
5419                    y = 0;//center
5420                    centered = true;//vertically centered, only matters for labels on left and right side
5421
5422                    temp = "";
5423                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5424                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
5425                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
5426                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
5427                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
5428                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
5429                    temp = temp.trim();
5430                    if(temp != null && !temp.isEmpty())
5431                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
5432                }
5433                else if(!strict)
5434                {
5435                    centered = false;
5436                }
5437
5438                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5439                {
5440                    y = 1;
5441                    temp = "";
5442                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5443                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5444                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5445                        temp += modifiers.get(Modifiers.Y_LOCATION);
5446
5447                    temp = temp.trim();
5448                    mods.add(new Modifier("X Y", temp, x, y, centered));
5449                }
5450
5451                if(modifiers.containsKey(Modifiers.W_DTG_1) || modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5452                {
5453                    y = 2;//above center
5454                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
5455                        y--;
5456
5457                    temp = modifiers.get(Modifiers.W_DTG_1);
5458
5459                    if(temp != null && !temp.isEmpty())
5460                        mods.add(new Modifier("W", temp, x, y, centered));
5461                }
5462
5463                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5464                {
5465                    y = -1;//below center
5466                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5467                    if(temp != null && !temp.isEmpty())
5468                        mods.add(new Modifier("T", temp, x, y, centered));
5469                }
5470
5471                if(modifiers.containsKey(Modifiers.Z_SPEED))
5472                {
5473                    y = -2;
5474                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5475                        y++;
5476                    temp = modifiers.get(Modifiers.Z_SPEED);
5477                    if(temp != null && !temp.isEmpty())
5478                        mods.add(new Modifier("Z", temp, x, y, centered));
5479                }
5480            }
5481            else if(ss == SymbolID.SymbolSet_LandInstallation)
5482            {
5483                //No top center label
5484
5485                //Do right side labels
5486                x = 1;//on right
5487
5488                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5489                {
5490                    y = 0;//center
5491                    centered = true;//vertically centered, only matters for labels on left and right side
5492                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5493
5494                    if(temp != null && !temp.isEmpty())
5495                        mods.add(new Modifier("H", temp, x, y, centered));
5496                }
5497                else if(!strict)
5498                {
5499                    centered = false;
5500                }
5501
5502                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5503                {
5504                    y = 1;//above center
5505                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5506
5507                    if(temp != null && !temp.isEmpty())
5508                        mods.add(new Modifier("G", temp, x, y, centered));
5509                }
5510
5511                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5512                {
5513                    y = 2;
5514                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5515                        y--;
5516
5517                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5518                    if(temp != null && !temp.isEmpty())
5519                        mods.add(new Modifier("AS", temp, x, y, centered));
5520                }
5521
5522                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
5523                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
5524                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5525                {
5526                    y = -1;
5527
5528                    temp = "";
5529                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
5530                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
5531                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
5532                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
5533                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5534                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
5535                    temp = temp.trim();
5536                    mods.add(new Modifier("J K P", temp, x, y, centered));
5537                }
5538
5539                //Do left side labels
5540                x = -1;//on left
5541
5542                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
5543                {
5544                    y = 0;//center
5545                    centered = true;//vertically centered, only matters for labels on left and right side
5546
5547                    temp = "";
5548                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5549                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
5550                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
5551                        temp += modifiers.get(Modifiers.Y_LOCATION);
5552                    temp = temp.trim();
5553                    if(temp != null && !temp.isEmpty())
5554                        mods.add(new Modifier("X Y", temp, x, y, centered));
5555                }
5556                else if(!strict)
5557                {
5558                    centered = false;
5559                }
5560
5561                if(modifiers.containsKey(Modifiers.W_DTG_1))
5562                {
5563                    y = 1;//above center
5564
5565                    temp = modifiers.get(Modifiers.W_DTG_1);
5566
5567                    if(temp != null && !temp.isEmpty())
5568                        mods.add(new Modifier("W AR", temp, x, y, centered));
5569                }
5570
5571                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5572                {
5573                    y = -1;//below center
5574                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5575                    if(temp != null && !temp.isEmpty())
5576                        mods.add(new Modifier("T", temp, x, y, centered));
5577                }
5578            }
5579            else if(ss == SymbolID.SymbolSet_Air ||
5580                    ss == SymbolID.SymbolSet_AirMissile ||
5581                    ss == SymbolID.SymbolSet_SignalsIntelligence_Air)
5582            {
5583                //No top center label
5584
5585
5586                //Do right side labels
5587                x = 1;//on right
5588                centered = false;
5589
5590                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5591                {
5592                    y = 1;//above center
5593                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
5594
5595                    if(temp != null && !temp.isEmpty())
5596                        mods.add(new Modifier("P", temp, x, y, centered));
5597                }
5598
5599                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5600                {
5601                    y = 2;
5602                    if(!strict && !modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5603                        y--;
5604                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5605
5606                    if(temp != null && !temp.isEmpty())
5607                        mods.add(new Modifier("T", temp, x, y, centered));
5608                }
5609
5610                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5611                {
5612                    y = 3;
5613                    if(!strict)
5614                    {
5615                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5616                            y--;
5617                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5618                            y--;
5619                    }
5620
5621                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5622
5623                    if(temp != null && !temp.isEmpty())
5624                        mods.add(new Modifier("AS", temp, x, y, centered));
5625                }
5626
5627                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5628                {
5629                    y = -1;//below center
5630                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5631
5632                    if(temp != null && !temp.isEmpty())
5633                        mods.add(new Modifier("V", temp, x, y, centered));
5634                }
5635
5636                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5637                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5638                {
5639                    y = -2;//below center
5640                    if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5641                        y++;
5642
5643                    temp = "";
5644                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5645                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5646                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5647                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5648                    temp = temp.trim();
5649
5650                    if(temp != null && !temp.isEmpty())
5651                        mods.add(new Modifier("Z X", temp, x, y, centered));
5652                }
5653
5654                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5655                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5656                {
5657                    y = -3;
5658                    if(!strict)
5659                    {
5660                        if(!(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5661                                modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5662                            y++;
5663                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5664                            y++;
5665                    }
5666                    temp = "";
5667                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5668                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5669                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5670                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5671                    temp = temp.trim();
5672                    if(temp != null && !temp.isEmpty())
5673                        mods.add(new Modifier("G H", temp, x, y, centered));
5674                }
5675
5676                //No left side labels
5677
5678            }
5679            else if(ss == SymbolID.SymbolSet_Space ||
5680                    ss == SymbolID.SymbolSet_SpaceMissile ||
5681                    ss == SymbolID.SymbolSet_SignalsIntelligence_Space)
5682            {
5683                //No top center label
5684
5685
5686                //Do right side labels
5687                x = 1;//on right
5688                centered = false;
5689
5690                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5691                {
5692                    y = 1;//above center
5693                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5694                    if(temp != null && !temp.isEmpty())
5695                        mods.add(new Modifier("V", temp, x, y, centered));
5696                }
5697
5698                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5699                {
5700                    y = 2;
5701                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5702                        y--;
5703                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5704
5705                    if(temp != null && !temp.isEmpty())
5706                        mods.add(new Modifier("T", temp, x, y, centered));
5707                }
5708
5709                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5710                {
5711                    y = 3;
5712                    if(!strict)
5713                    {
5714                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5715                            y--;
5716                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5717                            y--;
5718                    }
5719
5720                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5721
5722                    if(temp != null && !temp.isEmpty())
5723                        mods.add(new Modifier("AS", temp, x, y, centered));
5724                }
5725
5726                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5727                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5728                {
5729                    y = -1;//below center
5730                    temp = "";
5731                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5732                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5733                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5734                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5735                    temp = temp.trim();
5736
5737                    if(temp != null && !temp.isEmpty())
5738                        mods.add(new Modifier("Z X", temp, x, y, centered));
5739                }
5740
5741                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5742                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5743                {
5744                    y = -2;
5745                    if(!strict &&
5746                            !(modifiers.containsKey(Modifiers.Z_SPEED) || modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5747                        y++;
5748                    temp = "";
5749                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5750                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5751                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5752                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5753                    temp = temp.trim();
5754                    if(temp != null && !temp.isEmpty())
5755                        mods.add(new Modifier("G H", temp, x, y, centered));
5756                }
5757
5758                //No left side labels
5759            }
5760            else if(ss == SymbolID.SymbolSet_SeaSurface ||
5761                    ss == SymbolID.SymbolSet_SignalsIntelligence_SeaSurface)
5762            {
5763                //No top center label
5764
5765
5766                //Do right side labels
5767                x = 1;//on right
5768                centered = true;
5769                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5770                {
5771                    y = 0;//center
5772                    centered = true;//vertically centered, only matters for labels on left and right side
5773                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5774                    if(temp != null && !temp.isEmpty())
5775                        mods.add(new Modifier("V", temp, x, y, centered));
5776                }
5777                else if(!strict)
5778                {
5779                    //if no "H', bring G and M closer to the center
5780                    centered = false;
5781                }
5782
5783                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5784                {
5785                    y = 1;//above center
5786                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
5787                    if(temp != null && !temp.isEmpty())
5788                        mods.add(new Modifier("P", temp, x, y, centered));
5789                }
5790
5791                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5792                {
5793                    y = 2;
5794                    if(!strict && !modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
5795                        y--;
5796                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5797
5798                    if(temp != null && !temp.isEmpty())
5799                        mods.add(new Modifier("T", temp, x, y, centered));
5800                }
5801
5802                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5803                {
5804                    y = 3;
5805                    if(!strict)
5806                    {
5807                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5808                            y--;
5809                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5810                            y--;
5811                    }
5812
5813                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5814
5815                    if(temp != null && !temp.isEmpty())
5816                        mods.add(new Modifier("AS", temp, x, y, centered));
5817                }
5818
5819                if(modifiers.containsKey(Modifiers.Z_SPEED)  ||
5820                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5821                {
5822                    y = -1;//below center
5823                    temp = "";
5824                    if(modifiers.containsKey(Modifiers.Z_SPEED))
5825                        temp = modifiers.get(Modifiers.Z_SPEED) + sep;
5826                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5827                        temp += modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5828                    temp = temp.trim();
5829
5830                    if(temp != null && !temp.isEmpty())
5831                        mods.add(new Modifier("Z X", temp, x, y, centered));
5832                }
5833
5834                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
5835                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5836                {
5837                    y = -2;
5838                    if(!strict &&
5839                            !(modifiers.containsKey(Modifiers.Z_SPEED) || modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5840                        y++;
5841                    temp = "";
5842                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5843                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
5844                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5845                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5846                    temp = temp.trim();
5847                    if(temp != null && !temp.isEmpty())
5848                        mods.add(new Modifier("G H", temp, x, y, centered));
5849                }
5850
5851                //Do left side labels
5852                x = -1;
5853                centered = false;
5854                if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT) || modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5855                {
5856                    y = 3;//above center
5857                    if(!strict)
5858                        y--;
5859
5860                    temp = "";
5861                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
5862                        temp = modifiers.get(Modifiers.AQ_GUARDED_UNIT) + sep;
5863                    if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5864                        temp += modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
5865                    temp = temp.trim();
5866
5867                    if(temp != null && !temp.isEmpty())
5868                        mods.add(new Modifier("AQ AR", temp, x, y, centered));
5869                }
5870            }
5871            else if(ss == SymbolID.SymbolSet_SeaSubsurface ||
5872                    ss == SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface)
5873            {
5874                //No top center label
5875
5876
5877                //Do right side labels
5878                x = 1;//on right
5879                centered = false;
5880                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5881                {
5882                    y = 1;//center
5883                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
5884                    if(temp != null && !temp.isEmpty())
5885                        mods.add(new Modifier("V", temp, x, y, centered));
5886                }
5887
5888                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5889                {
5890                    y = 2;
5891                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5892                        y--;
5893                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
5894
5895                    if(temp != null && !temp.isEmpty())
5896                        mods.add(new Modifier("T", temp, x, y, centered));
5897                }
5898
5899                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5900                {
5901                    y = 3;
5902                    if(!strict)
5903                    {
5904                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
5905                            y--;
5906                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
5907                            y--;
5908                    }
5909
5910                    temp = modifiers.get(Modifiers.AS_COUNTRY );
5911
5912                    if(temp != null && !temp.isEmpty())
5913                        mods.add(new Modifier("AS", temp, x, y, centered));
5914                }
5915
5916                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5917                {
5918                    y = -1;//below center
5919
5920                    temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
5921
5922                    if(temp != null && !temp.isEmpty())
5923                        mods.add(new Modifier("X", temp, x, y, centered));
5924                }
5925
5926                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5927                {
5928                    y = -2;
5929                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)))
5930                        y++;
5931                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5932
5933                    if(temp != null && !temp.isEmpty())
5934                        mods.add(new Modifier("G", temp, x, y, centered));
5935                }
5936
5937                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
5938                {
5939                    y = -3;//below center
5940                    if(!strict)
5941                    {
5942                        if(!modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5943                            y++;
5944                        if(!modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
5945                            y++;
5946                    }
5947
5948                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
5949
5950                    if(temp != null && !temp.isEmpty())
5951                        mods.add(new Modifier("H", temp, x, y, centered));
5952                }
5953
5954                //Do left side labels
5955                x = -1;
5956                centered = false;
5957                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
5958                {
5959                    y = 3;//above center
5960                    if(!strict)
5961                    {
5962                        y--;
5963                    }
5964
5965                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
5966
5967                    if(temp != null && !temp.isEmpty())
5968                        mods.add(new Modifier("AR", temp, x, y, centered));
5969                }
5970
5971            }
5972            else if(ss == SymbolID.SymbolSet_Activities)
5973            {
5974                //No top center label
5975
5976                //Do right side labels
5977                x = 1;//on right
5978                centered = false;
5979
5980                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5981                {
5982                    y = 1;
5983
5984                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
5985                    if(temp != null && !temp.isEmpty())
5986                        mods.add(new Modifier("G", temp, x, y, centered));
5987                }
5988
5989                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
5990                {
5991                    y = 2;
5992                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
5993                        y--;
5994                    temp = modifiers.get(Modifiers.AS_COUNTRY);
5995
5996                    if(temp != null && !temp.isEmpty())
5997                        mods.add(new Modifier("AS", temp, x, y, centered));
5998                }
5999
6000                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6001                {
6002                    y = -1;//below center
6003                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6004                    if(temp != null && !temp.isEmpty())
6005                        mods.add(new Modifier("H", temp, x, y, centered));
6006                }
6007
6008                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6009                {
6010                    y = -2;
6011                    if(!strict && !modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6012                        y++;
6013                    temp = temp = modifiers.get(Modifiers.J_EVALUATION_RATING);
6014
6015                    if(temp != null && !temp.isEmpty())
6016                        mods.add(new Modifier("J", temp, x, y, centered));
6017                }
6018
6019                //Do left side labels
6020                x = -1;//on left
6021                centered = false;
6022
6023                if(modifiers.containsKey(Modifiers.Y_LOCATION))
6024                {
6025                    y = 1;
6026                    temp = modifiers.get(Modifiers.Y_LOCATION);
6027
6028                    if(temp != null && !temp.isEmpty())
6029                        mods.add(new Modifier("Y", temp, x, y, centered));
6030                }
6031
6032                if(modifiers.containsKey(Modifiers.W_DTG_1))
6033                {
6034                    y = 2;//above center
6035                    if(!strict && !modifiers.containsKey(Modifiers.Y_LOCATION))
6036                        y--;
6037                    temp = modifiers.get(Modifiers.W_DTG_1);
6038                    if(temp != null && !temp.isEmpty())
6039                        mods.add(new Modifier("W", temp, x, y, centered));
6040                }
6041
6042            }
6043            else if(ss == SymbolID.SymbolSet_CyberSpace)
6044            {
6045                //Do top center label
6046                x = 0;//centered
6047                y = 9;//on top of symbol
6048                if(modifiers.containsKey(Modifiers.B_ECHELON))
6049                {
6050                    temp = modifiers.get(Modifiers.B_ECHELON);
6051                    if(temp != null && !temp.isEmpty())
6052                        mods.add(new Modifier("B", temp, x, y, centered));
6053                }
6054
6055                //Do right side labels
6056                x = 1;//on right
6057                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6058                {
6059                    y = 0;//center
6060                    centered = true;//vertically centered, only matters for labels on left and right side
6061                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6062                    if(temp != null && !temp.isEmpty())
6063                        mods.add(new Modifier("H", temp, x, y, centered));
6064                }
6065                else if(!strict)
6066                {
6067                    //if no "H', bring G and M closer to the center
6068                    centered = false;
6069                }
6070
6071                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6072                {
6073                    y = 1;//above center
6074                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
6075                    if(temp != null && !temp.isEmpty())
6076                        mods.add(new Modifier("G", temp, x, y, centered));
6077                }
6078
6079                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
6080                {
6081                    y = 2;
6082                    if(!strict && !modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6083                        y--;
6084                    temp = "";
6085                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
6086                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
6087                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6088                        temp += modifiers.get(Modifiers.AS_COUNTRY);
6089                    temp = temp.trim();
6090                    if(temp != null && !temp.isEmpty())
6091                        mods.add(new Modifier("F AS", temp, x, y, centered));
6092                }
6093
6094                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6095                {
6096                    y = -1;//below center
6097                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6098                    if(temp != null && !temp.isEmpty())
6099                        mods.add(new Modifier("M", temp, x, y, centered));
6100                }
6101
6102                if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6103                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6104                {
6105                    y = -2;
6106                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6107                        y++;
6108                    temp = "";
6109                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6110                        temp = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6111                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6112                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
6113
6114                    temp = temp.trim();
6115                    if(temp != null && !temp.isEmpty())
6116                        mods.add(new Modifier("K L", temp, x, y, centered));
6117                }
6118
6119                //Do left side labels
6120                x = -1;//on left
6121                centered = true;
6122
6123                if(modifiers.containsKey(Modifiers.Y_LOCATION))
6124                {
6125                    y = 0;
6126                    temp = modifiers.get(Modifiers.Y_LOCATION);
6127
6128                    if(temp != null && !temp.isEmpty())
6129                        mods.add(new Modifier("Y", temp, x, y, centered));
6130                }
6131                else if (!strict)
6132                {
6133                    centered = false;
6134                }
6135
6136                if(modifiers.containsKey(Modifiers.W_DTG_1))
6137                {
6138                    y = 1;//above center
6139                    temp = modifiers.get(Modifiers.W_DTG_1);
6140                    if(temp != null && !temp.isEmpty())
6141                        mods.add(new Modifier("W", temp, x, y, centered));
6142                }
6143
6144                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6145                {
6146                    y = -1;//below center
6147                    temp = "";
6148                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6149                        temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1) + sep;
6150                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6151                        temp += modifiers.get(Modifiers.V_EQUIP_TYPE);
6152
6153                    temp = temp.trim();
6154                    if(temp != null && !temp.isEmpty())
6155                        mods.add(new Modifier("T V", temp, x, y, centered));
6156                }
6157
6158            }
6159            /*else if(ver == SymbolID.SymbolSet_MineWarfare)
6160            {
6161                //no modifiers
6162            }//*/
6163            //else//SymbolSet Unknown
6164            //processUnknownTextModifiers
6165        }
6166        else// if(ver >= SymbolID.Version_2525E)
6167        {
6168            int fs = SymbolID.getFrameShape(symbolID);
6169            if(ss == SymbolID.SymbolSet_LandUnit ||
6170                    ss == SymbolID.SymbolSet_LandCivilianUnit_Organization ||
6171                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_LandUnit))
6172            {
6173
6174                //Only Command & Control has AA; ec.equals("110000").  Always in the middle of the unit.
6175                if(modifiers.containsKey(Modifiers.AA_SPECIAL_C2_HQ))
6176                {
6177                    temp = modifiers.get(Modifiers.AA_SPECIAL_C2_HQ);
6178                    if(temp != null && !temp.isEmpty())
6179                        mods.add(new Modifier("AA", temp, 0, 0, true));
6180                }
6181                
6182                //Do top center label
6183                x = 0;//centered
6184                y = 9;//on top of symbol
6185                if(modifiers.containsKey(Modifiers.B_ECHELON))
6186                {
6187                    temp = modifiers.get(Modifiers.B_ECHELON);
6188                    if(temp != null && !temp.isEmpty())
6189                        mods.add(new Modifier("B", temp, x, y, centered));
6190                }
6191
6192                //Do right side labels
6193                x = 1;//on right
6194                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6195                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6196                {
6197                    y = 0;//center
6198                    centered = true;//vertically centered, only matters for labels on left and right side
6199                    temp = "";
6200                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6201                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6202                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6203                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6204                    temp = temp.trim();
6205                    if(temp != null && !temp.isEmpty())
6206                        mods.add(new Modifier("H AF", temp, x, y, centered));
6207                }
6208                else if(!strict)
6209                {
6210                    //if no "H', bring G and M closer to the center
6211                    centered = false;
6212                }
6213
6214                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6215                {
6216                    y = 1;//above center
6217                    temp = "";
6218                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6219                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6220                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6221                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6222                    temp = temp.trim();
6223                    if(temp != null && !temp.isEmpty())
6224                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6225                }
6226
6227                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
6228                {
6229                    y = 2;
6230                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6231                        y--;
6232                    temp = "";
6233                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
6234                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
6235                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6236                        temp += modifiers.get(Modifiers.AS_COUNTRY);
6237                    temp = temp.trim();
6238                    if(temp != null && !temp.isEmpty())
6239                        mods.add(new Modifier("F AS", temp, x, y, centered));
6240                }
6241
6242                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6243                {
6244                    y = -1;//below center
6245                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6246                    if(temp != null && !temp.isEmpty())
6247                        mods.add(new Modifier("M", temp, x, y, centered));
6248                }
6249
6250                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6251                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6252                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
6253                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6254                {
6255                    y = -2;
6256                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6257                        y++;
6258                    temp = "";
6259                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6260                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6261                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6262                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6263                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6264                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
6265                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6266                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6267                    temp = temp.trim();
6268                    if(temp != null && !temp.isEmpty())
6269                        mods.add(new Modifier("J K L P", temp, x, y, centered));
6270                }
6271
6272                //Do left side labels
6273                x = -1;//on left
6274
6275                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
6276                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
6277                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6278                {
6279                    y = 0;//center
6280                    centered = true;//vertically centered, only matters for labels on left and right side
6281
6282                    temp = "";
6283                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6284                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6285                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6286                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
6287                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6288                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6289                    temp = temp.trim();
6290                    if(temp != null && !temp.isEmpty())
6291                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
6292                }
6293                else if(!strict)
6294                {
6295                    centered = false;
6296                }
6297
6298                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6299                {
6300                    y = 1;
6301                    temp = "";
6302                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6303                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6304                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6305                        temp += modifiers.get(Modifiers.Y_LOCATION);
6306
6307                    temp = temp.trim();
6308                    mods.add(new Modifier("X Y", temp, x, y, centered));
6309                }
6310
6311                if(modifiers.containsKey(Modifiers.W_DTG_1))
6312                {
6313                    y = 2;//above center
6314                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6315                        y--;
6316
6317                    temp = modifiers.get(Modifiers.W_DTG_1);
6318
6319                    if(temp != null && !temp.isEmpty())
6320                        mods.add(new Modifier("W", temp, x, y, centered));
6321                }
6322
6323                if(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6324                {
6325                    y = -1;//below center
6326                    temp = "";
6327                    if(modifiers.containsKey(Modifiers.C_QUANTITY))
6328                        temp = modifiers.get(Modifiers.C_QUANTITY) + sep;
6329                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6330                        temp += modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6331
6332                    temp = temp.trim();
6333                    if(temp != null && !temp.isEmpty())
6334                        mods.add(new Modifier("C T", temp, x, y, centered));
6335                }
6336
6337                if(modifiers.containsKey(Modifiers.Z_SPEED))
6338                {
6339                    y = -2;
6340                    if(!strict && !(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
6341                        y++;
6342                    temp = modifiers.get(Modifiers.Z_SPEED);
6343                    if(temp != null && !temp.isEmpty())
6344                        mods.add(new Modifier("Z", temp, x, y, centered));
6345                }
6346            }
6347            else if(ss == SymbolID.SymbolSet_LandEquipment ||
6348                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_LandEquipment))
6349            {
6350                //Do top center label
6351                x = 0;//centered
6352                y = 9;//on top of symbol
6353                if(modifiers.containsKey(Modifiers.C_QUANTITY))
6354                {
6355                    temp = modifiers.get(Modifiers.C_QUANTITY);
6356                    if(temp != null && !temp.isEmpty())
6357                        mods.add(new Modifier("C", temp, x, y, centered));
6358                }
6359
6360                //Do right side labels
6361                x = 1;//on right
6362                centered = false;
6363
6364                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6365                {
6366                    y = 1;//above center
6367                    temp = "";
6368                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6369                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6370                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6371                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6372                    temp = temp.trim();
6373                    if(temp != null && !temp.isEmpty())
6374                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6375                }
6376
6377                if( modifiers.containsKey(Modifiers.AS_COUNTRY))
6378                {
6379                    y = 2;
6380                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6381                        y--;
6382                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6383
6384                    if(temp != null && !temp.isEmpty())
6385                        mods.add(new Modifier("AS", temp, x, y, centered));
6386                }
6387
6388                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6389                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6390                {
6391                    y = -1;
6392                    temp = "";
6393                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6394                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6395                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6396                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6397                    temp = temp.trim();
6398                    if(temp != null && !temp.isEmpty())
6399                        mods.add(new Modifier("H AF", temp, x, y, centered));
6400                }
6401
6402                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6403                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6404                        modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP) ||
6405                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6406                {
6407                    y = -2;
6408                    if(!strict && !(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6409                            modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER)))
6410                        y++;
6411                    temp = "";
6412                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6413                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6414                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6415                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6416                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
6417                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP) + sep;
6418                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6419                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6420                    temp = temp.trim();
6421                    if(temp != null && !temp.isEmpty())
6422                        mods.add(new Modifier("J K L P", temp, x, y, centered));
6423                }
6424
6425                //Do left side labels
6426                x = -1;//on left
6427
6428                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
6429                        modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE) ||
6430                        modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6431                {
6432                    y = 0;//center
6433                    centered = true;//vertically centered, only matters for labels on left and right side
6434
6435                    temp = "";
6436                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6437                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6438                    if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6439                        temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE) + sep;
6440                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6441                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6442                    temp = temp.trim();
6443                    if(temp != null && !temp.isEmpty())
6444                        mods.add(new Modifier("V AD AE", temp, x, y, centered));
6445                }
6446                else if(!strict)
6447                {
6448                    centered = false;
6449                }
6450
6451                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6452                {
6453                    y = 1;
6454                    temp = "";
6455                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6456                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6457                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6458                        temp += modifiers.get(Modifiers.Y_LOCATION);
6459
6460                    temp = temp.trim();
6461                    mods.add(new Modifier("X Y", temp, x, y, centered));
6462                }
6463
6464                if(modifiers.containsKey(Modifiers.W_DTG_1))
6465                {
6466                    y = 2;//above center
6467                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6468                        y--;
6469
6470                    temp = modifiers.get(Modifiers.W_DTG_1);
6471
6472                    if(temp != null && !temp.isEmpty())
6473                        mods.add(new Modifier("W", temp, x, y, centered));
6474                }
6475
6476                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6477                {
6478                    y = -1;//below center
6479                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6480
6481                    temp = temp.trim();
6482                    if(temp != null && !temp.isEmpty())
6483                        mods.add(new Modifier("T", temp, x, y, centered));
6484                }
6485
6486                if(modifiers.containsKey(Modifiers.Z_SPEED))
6487                {
6488                    y = -2;
6489                    if(!strict && !modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6490                        y++;
6491                    temp = modifiers.get(Modifiers.Z_SPEED);
6492                    if(temp != null && !temp.isEmpty())
6493                        mods.add(new Modifier("Z", temp, x, y, centered));
6494                }
6495            }
6496            else if(ss == SymbolID.SymbolSet_LandInstallation)
6497            {
6498                //No top center label
6499
6500                //Do right side labels
6501                x = 1;//on right
6502                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6503                {
6504                    y = 0;//center
6505                    centered = true;//vertically centered, only matters for labels on left and right side
6506                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6507
6508                    if(temp != null && !temp.isEmpty())
6509                        mods.add(new Modifier("H", temp, x, y, centered));
6510                }
6511                else if(!strict)
6512                {
6513                    //if no "H', bring G and M closer to the center
6514                    centered = false;
6515                }
6516
6517                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6518                {
6519                    y = 1;//above center
6520                    temp = "";
6521                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6522                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6523                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6524                        temp += modifiers.get(Modifiers.AQ_GUARDED_UNIT);
6525                    temp = temp.trim();
6526                    if(temp != null && !temp.isEmpty())
6527                        mods.add(new Modifier("G AQ", temp, x, y, centered));
6528                }
6529
6530                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6531                {
6532                    y = 2;
6533                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) || modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT)))
6534                        y--;
6535                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6536
6537                    if(temp != null && !temp.isEmpty())
6538                        mods.add(new Modifier("AS", temp, x, y, centered));
6539                }
6540
6541                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6542                {
6543                    y = -1;//below center
6544                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
6545                    if(temp != null && !temp.isEmpty())
6546                        mods.add(new Modifier("M", temp, x, y, centered));
6547                }
6548
6549                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
6550                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
6551                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6552                {
6553                    y = -2;
6554                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
6555                        y++;
6556                    temp = "";
6557                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6558                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
6559                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
6560                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
6561                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6562                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
6563                    temp = temp.trim();
6564                    if(temp != null && !temp.isEmpty())
6565                        mods.add(new Modifier("J K P", temp, x, y, centered));
6566                }
6567
6568                //Do left side labels
6569                x = -1;//on left
6570                centered = false;
6571
6572                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
6573                {
6574                    y = 1;
6575                    temp = "";
6576                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6577                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6578                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6579                        temp += modifiers.get(Modifiers.Y_LOCATION);
6580
6581                    temp = temp.trim();
6582                    mods.add(new Modifier("X Y", temp, x, y, centered));
6583                }
6584
6585                if(modifiers.containsKey(Modifiers.W_DTG_1))
6586                {
6587                    y = 2;//above center
6588                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6589                        y--;
6590
6591                    temp = modifiers.get(Modifiers.W_DTG_1);
6592
6593                    if(temp != null && !temp.isEmpty())
6594                        mods.add(new Modifier("W", temp, x, y, centered));
6595                }
6596
6597                if(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6598                {
6599                    y = -1;//below center
6600                    temp = "";
6601                    if(modifiers.containsKey(Modifiers.C_QUANTITY))
6602                        temp = modifiers.get(Modifiers.C_QUANTITY) + sep;
6603                    if(modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME))
6604                        temp += modifiers.get(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME);
6605
6606                    temp = temp.trim();
6607                    if(temp != null && !temp.isEmpty())
6608                        mods.add(new Modifier("C AE", temp, x, y, centered));
6609                }
6610
6611                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6612                {
6613                    y = -2;
6614                    if(!strict && !(modifiers.containsKey(Modifiers.C_QUANTITY) || modifiers.containsKey(Modifiers.AE_EQUIPMENT_TEARDOWN_TIME)))
6615                        y++;
6616                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6617                    if(temp != null && !temp.isEmpty())
6618                        mods.add(new Modifier("T", temp, x, y, centered));
6619                }
6620            }
6621            else if(ss == SymbolID.SymbolSet_Space ||
6622                    ss == SymbolID.SymbolSet_SpaceMissile ||
6623                    ss == SymbolID.SymbolSet_Air ||
6624                    ss == SymbolID.SymbolSet_AirMissile ||
6625                    (ss == SymbolID.SymbolSet_SignalsIntelligence &&
6626                            (fs == SymbolID.FrameShape_Space || fs == SymbolID.FrameShape_Air)))
6627            {
6628                //No top center label
6629                x = 0;//centered
6630                y = 9;//on top of symbol
6631
6632                if(modifiers.containsKey(Modifiers.C_QUANTITY))
6633                {
6634                    temp = modifiers.get(Modifiers.C_QUANTITY);
6635                    if(temp != null && !temp.isEmpty())
6636                        mods.add(new Modifier("C", temp, x, y, centered));
6637                }
6638                else if(modifiers.containsKey(Modifiers.B_ECHELON))
6639                {
6640                    temp = modifiers.get(Modifiers.B_ECHELON);
6641                    if(temp != null && !temp.isEmpty())
6642                        mods.add(new Modifier("B", temp, x, y, centered));
6643                }
6644
6645
6646                //Do right side labels
6647                x = 1;//on right
6648                centered = true;
6649
6650                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) || modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6651                {
6652                    y = 0;//
6653                    temp = "";
6654                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6655                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
6656                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
6657                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
6658                    temp = temp.trim();
6659
6660                    if(temp != null && !temp.isEmpty())
6661                        mods.add(new Modifier("V AF", temp, x, y, centered));
6662                }
6663                else
6664                {
6665                    centered = false;
6666                }
6667
6668                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.Y_LOCATION))
6669                {
6670                    y = 1;//above center
6671                    temp = "";
6672                    if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6673                        temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1) + sep;
6674                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6675                        temp += modifiers.get(Modifiers.Y_LOCATION);
6676                    temp = temp.trim();
6677
6678                    if(temp != null && !temp.isEmpty())
6679                        mods.add(new Modifier("T Y", temp, x, y, centered));
6680                }
6681
6682                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6683                {
6684                    y = 2;
6685                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) || modifiers.containsKey(Modifiers.Y_LOCATION)))
6686                        y--;
6687                    temp = modifiers.get(Modifiers.AS_COUNTRY);
6688
6689                    if(temp != null && !temp.isEmpty())
6690                        mods.add(new Modifier("AS", temp, x, y, centered));
6691                }
6692
6693                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS)  ||
6694                        modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)  ||
6695                        modifiers.containsKey(Modifiers.Z_SPEED))
6696                {
6697                    y = -1;//below center
6698                    temp = "";
6699                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6700                        temp = modifiers.get(Modifiers.P_IFF_SIF_AIS) + sep;
6701                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6702                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
6703                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6704                        temp = modifiers.get(Modifiers.Z_SPEED);
6705
6706                    temp = temp.trim();
6707
6708                    if(temp != null && !temp.isEmpty())
6709                        mods.add(new Modifier("P X Z", temp, x, y, centered));
6710                }
6711
6712                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS) ||
6713                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1) ||
6714                        modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6715                {
6716                    y = -2;//below center
6717                    if(!(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS)  ||
6718                            modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)  ||
6719                            modifiers.containsKey(Modifiers.Z_SPEED)))
6720                        y++;
6721
6722                    temp = "";
6723                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6724                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6725                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6726                        temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1) + sep;
6727                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
6728                        temp += modifiers.get(Modifiers.J_EVALUATION_RATING);
6729                    temp = temp.trim();
6730
6731                    if(temp != null && !temp.isEmpty())
6732                        mods.add(new Modifier("G H J", temp, x, y, centered));
6733                }
6734
6735                //No left side labels
6736                x = -1;//on right
6737                centered = true;
6738
6739                if(modifiers.containsKey(Modifiers.AD_PLATFORM_TYPE))
6740                {
6741                    y = 0;//
6742                    temp = temp += modifiers.get(Modifiers.AD_PLATFORM_TYPE);
6743
6744                    if(temp != null && !temp.isEmpty())
6745                        mods.add(new Modifier("AD", temp, x, y, centered));
6746                }
6747                else
6748                {
6749                    centered = false;
6750                }
6751
6752                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6753                {
6754                    y = 1;//above center
6755                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6756
6757                    if(temp != null && !temp.isEmpty())
6758                        mods.add(new Modifier("AR", temp, x, y, centered));
6759                }
6760
6761                if(modifiers.containsKey(Modifiers.W_DTG_1))
6762                {
6763                    y = 2;
6764                    if(!strict && !modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6765                        y--;
6766                    temp = modifiers.get(Modifiers.W_DTG_1);
6767
6768                    if(temp != null && !temp.isEmpty())
6769                        mods.add(new Modifier("W", temp, x, y, centered));
6770                }
6771            }
6772            else if(ss == SymbolID.SymbolSet_SeaSurface ||
6773                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_SeaSurface))
6774            {
6775                //No top center label
6776
6777
6778                //Do right side labels
6779                x = 1;//on right
6780                centered = false;
6781
6782                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6783                {
6784                    y = 1;//above center
6785                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
6786
6787                    if(temp != null && !temp.isEmpty())
6788                        mods.add(new Modifier("V", temp, x, y, centered));
6789                }
6790
6791                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6792                {
6793                    y = 2;
6794                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6795                        y--;
6796                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6797
6798                    if(temp != null && !temp.isEmpty())
6799                        mods.add(new Modifier("T", temp, x, y, centered));
6800                }
6801
6802                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6803                {
6804                    y = 3;
6805                    if(!strict)
6806                    {
6807                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6808                            y--;
6809                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6810                            y--;
6811                    }
6812
6813                    temp = modifiers.get(Modifiers.AS_COUNTRY );
6814
6815                    if(temp != null && !temp.isEmpty())
6816                        mods.add(new Modifier("AS", temp, x, y, centered));
6817                }
6818
6819                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6820                {
6821                    y = -1;//below center
6822                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
6823
6824                    if(temp != null && !temp.isEmpty())
6825                        mods.add(new Modifier("P", temp, x, y, centered));
6826                }
6827
6828                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6829                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6830                {
6831                    y = -2;//below center
6832                    if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6833                        y++;
6834
6835                    temp = "";
6836                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6837                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6838                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6839                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6840                    temp = temp.trim();
6841
6842                    if(temp != null && !temp.isEmpty())
6843                        mods.add(new Modifier("G H", temp, x, y, centered));
6844                }
6845
6846                if(modifiers.containsKey(Modifiers.Y_LOCATION) ||
6847                        modifiers.containsKey(Modifiers.Z_SPEED))
6848                {
6849                    y = -3;
6850                    if(!strict)
6851                    {
6852                        if(!(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6853                                modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)))
6854                            y++;
6855                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6856                            y++;
6857                    }
6858                    temp = "";
6859                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6860                        temp = modifiers.get(Modifiers.Y_LOCATION) + sep;
6861                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6862                        temp += modifiers.get(Modifiers.Z_SPEED);
6863                    temp = temp.trim();
6864                    if(temp != null && !temp.isEmpty())
6865                        mods.add(new Modifier("Y Z", temp, x, y, centered));
6866                }
6867
6868                //No left side labels
6869                x = -1;
6870                centered = false;
6871                if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT) ||
6872                        modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6873                {
6874                    y = 2;
6875                    if(!strict)
6876                    {
6877                        y--;
6878                    }
6879                    temp = "";
6880                    if(modifiers.containsKey(Modifiers.AQ_GUARDED_UNIT))
6881                        temp = modifiers.get(Modifiers.AQ_GUARDED_UNIT) + sep;
6882                    if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6883                        temp += modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
6884                    temp = temp.trim();
6885                    if(temp != null && !temp.isEmpty())
6886                        mods.add(new Modifier("AQ AR", temp, x, y, centered));
6887                }
6888            }
6889            else if(ss == SymbolID.SymbolSet_SeaSubsurface ||
6890                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_SeaSubsurface))
6891            {
6892                //No top center label
6893
6894
6895                //Do right side labels
6896                x = 1;//on right
6897                centered = false;
6898
6899                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6900                {
6901                    y = 1;//above center
6902                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
6903
6904                    if(temp != null && !temp.isEmpty())
6905                        mods.add(new Modifier("V", temp, x, y, centered));
6906                }
6907
6908                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6909                {
6910                    y = 2;
6911                    if(!strict && !modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6912                        y--;
6913                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
6914
6915                    if(temp != null && !temp.isEmpty())
6916                        mods.add(new Modifier("T", temp, x, y, centered));
6917                }
6918
6919                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
6920                {
6921                    y = 3;
6922                    if(!strict)
6923                    {
6924                        if(!modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
6925                            y--;
6926                        if(!modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
6927                            y--;
6928                    }
6929
6930                    temp = modifiers.get(Modifiers.AS_COUNTRY );
6931
6932                    if(temp != null && !temp.isEmpty())
6933                        mods.add(new Modifier("AS", temp, x, y, centered));
6934                }
6935
6936                if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6937                {
6938                    y = -1;//below center
6939                    temp = modifiers.get(Modifiers.P_IFF_SIF_AIS);
6940
6941                    if(temp != null && !temp.isEmpty())
6942                        mods.add(new Modifier("P", temp, x, y, centered));
6943                }
6944
6945                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6946                        modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6947                {
6948                    y = -2;//below center
6949                    if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6950                        y++;
6951
6952                    temp = "";
6953                    if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
6954                        temp = modifiers.get(Modifiers.G_STAFF_COMMENTS) + sep;
6955                    if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
6956                        temp += modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
6957                    temp = temp.trim();
6958
6959                    if(temp != null && !temp.isEmpty())
6960                        mods.add(new Modifier("G H", temp, x, y, centered));
6961                }
6962
6963                if(modifiers.containsKey(Modifiers.Y_LOCATION) ||
6964                        modifiers.containsKey(Modifiers.Z_SPEED))
6965                {
6966                    y = -3;
6967                    if(!strict)
6968                    {
6969                        if(!(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)  ||
6970                                modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1)))
6971                            y++;
6972                        if(!modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
6973                            y++;
6974                    }
6975                    temp = "";
6976                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
6977                        temp = modifiers.get(Modifiers.Y_LOCATION) + sep;
6978                    if(modifiers.containsKey(Modifiers.Z_SPEED))
6979                        temp += modifiers.get(Modifiers.Z_SPEED);
6980                    temp = temp.trim();
6981                    if(temp != null && !temp.isEmpty())
6982                        mods.add(new Modifier("Y Z", temp, x, y, centered));
6983                }
6984
6985                //No left side labels
6986                x = -1;
6987                centered = false;
6988                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
6989                {
6990                    y = 1;
6991                    temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH);
6992
6993                    if(temp != null && !temp.isEmpty())
6994                        mods.add(new Modifier("X", temp, x, y, centered));
6995                }
6996
6997                if(modifiers.containsKey(Modifiers.AR_SPECIAL_DESIGNATOR))
6998                {
6999                    y = 2;
7000                    if(!strict && !modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
7001                    {
7002                        y--;
7003                    }
7004                    temp = modifiers.get(Modifiers.AR_SPECIAL_DESIGNATOR);
7005                    temp = temp.trim();
7006                    if(temp != null && !temp.isEmpty())
7007                        mods.add(new Modifier("AR", temp, x, y, centered));
7008                }
7009            }
7010            else if(ss == SymbolID.SymbolSet_DismountedIndividuals)
7011            {
7012                //No top center label
7013
7014
7015                //Do right side labels
7016                x = 1;//on right
7017                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7018                {
7019                    y = 0;//center
7020                    centered = true;//vertically centered, only matters for labels on left and right side
7021                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7022
7023                    if(temp != null && !temp.isEmpty())
7024                        mods.add(new Modifier("H", temp, x, y, centered));
7025                }
7026                else if(!strict)
7027                {
7028                    centered = false;
7029                }
7030
7031                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7032                {
7033                    y = 1;//above center
7034                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7035
7036                    if(temp != null && !temp.isEmpty())
7037                        mods.add(new Modifier("G", temp, x, y, centered));
7038                }
7039
7040                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7041                {
7042                    y = 2;
7043                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)))
7044                        y--;
7045                    temp = modifiers.get(Modifiers.AS_COUNTRY);
7046
7047                    if(temp != null && !temp.isEmpty())
7048                        mods.add(new Modifier("AS", temp, x, y, centered));
7049                }
7050
7051                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7052                {
7053                    y = -1;//below center
7054                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
7055                    if(temp != null && !temp.isEmpty())
7056                        mods.add(new Modifier("M", temp, x, y, centered));
7057                }
7058
7059                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING) ||
7060                        modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) ||
7061                        modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
7062                {
7063                    y = -2;
7064                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7065                        y++;
7066                    temp = "";
7067                    if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
7068                        temp = modifiers.get(Modifiers.J_EVALUATION_RATING) + sep;
7069                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
7070                        temp += modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
7071                    if(modifiers.containsKey(Modifiers.P_IFF_SIF_AIS))
7072                        temp += modifiers.get(Modifiers.P_IFF_SIF_AIS);
7073                    temp = temp.trim();
7074                    if(temp != null && !temp.isEmpty())
7075                        mods.add(new Modifier("J K P", temp, x, y, centered));
7076                }
7077
7078                //Do left side labels
7079                x = -1;//on left
7080
7081                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE) ||
7082                        modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
7083                {
7084                    y = 0;//center
7085                    centered = true;//vertically centered, only matters for labels on left and right side
7086
7087                    temp = "";
7088                    if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
7089                        temp = modifiers.get(Modifiers.V_EQUIP_TYPE) + sep;
7090                    if(modifiers.containsKey(Modifiers.AF_COMMON_IDENTIFIER))
7091                        temp += modifiers.get(Modifiers.AF_COMMON_IDENTIFIER);
7092                    temp = temp.trim();
7093                    if(temp != null && !temp.isEmpty())
7094                        mods.add(new Modifier("V AF", temp, x, y, centered));
7095                }
7096                else if(!strict)
7097                {
7098                    centered = false;
7099                }
7100
7101                if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION))
7102                {
7103                    y = 1;
7104                    temp = "";
7105                    if(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH))
7106                        temp = modifiers.get(Modifiers.X_ALTITUDE_DEPTH) + sep;
7107                    if(modifiers.containsKey(Modifiers.Y_LOCATION))
7108                        temp += modifiers.get(Modifiers.Y_LOCATION);
7109
7110                    temp = temp.trim();
7111                    mods.add(new Modifier("X Y", temp, x, y, centered));
7112                }
7113
7114                if(modifiers.containsKey(Modifiers.W_DTG_1))
7115                {
7116                    y = 2;//above center
7117                    if(!strict && !(modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH) || modifiers.containsKey(Modifiers.Y_LOCATION)))
7118                        y--;
7119
7120                    temp = modifiers.get(Modifiers.W_DTG_1);
7121
7122                    if(temp != null && !temp.isEmpty())
7123                        mods.add(new Modifier("W", temp, x, y, centered));
7124                }
7125
7126                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7127                {
7128                    y = -1;//below center
7129                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7130
7131                    if(temp != null && !temp.isEmpty())
7132                        mods.add(new Modifier("T", temp, x, y, centered));
7133                }
7134
7135                if(modifiers.containsKey(Modifiers.Z_SPEED))
7136                {
7137                    y = -2;
7138                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
7139                        y++;
7140                    temp = modifiers.get(Modifiers.Z_SPEED);
7141                    if(temp != null && !temp.isEmpty())
7142                        mods.add(new Modifier("Z", temp, x, y, centered));
7143                }
7144            }
7145            else if(ss == SymbolID.SymbolSet_Activities)
7146            {
7147                //No top center label
7148
7149
7150                //Do right side labels
7151                x = 1;//on right
7152                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7153                {
7154                    y = 0;//center
7155                    centered = true;//vertically centered, only matters for labels on left and right side
7156                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7157
7158                    if(temp != null && !temp.isEmpty())
7159                        mods.add(new Modifier("G", temp, x, y, centered));
7160                }
7161                else if(!strict)
7162                {
7163                    centered = false;
7164                }
7165
7166                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7167                {
7168                    y = 1;//above center
7169                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7170
7171                    if(temp != null && !temp.isEmpty())
7172                        mods.add(new Modifier("T", temp, x, y, centered));
7173                }
7174
7175                if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7176                {
7177                    y = 2;
7178                    if(!strict && !(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1)))
7179                        y--;
7180                    temp = modifiers.get(Modifiers.AS_COUNTRY);
7181
7182                    if(temp != null && !temp.isEmpty())
7183                        mods.add(new Modifier("AS", temp, x, y, centered));
7184                }
7185
7186                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7187                {
7188                    y = -1;//below center
7189                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7190                    if(temp != null && !temp.isEmpty())
7191                        mods.add(new Modifier("H", temp, x, y, centered));
7192                }
7193
7194                if(modifiers.containsKey(Modifiers.J_EVALUATION_RATING))
7195                {
7196                    y = -2;
7197                    if(!strict && !modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7198                        y++;
7199                    temp = modifiers.get(Modifiers.J_EVALUATION_RATING);
7200
7201                    if(temp != null && !temp.isEmpty())
7202                        mods.add(new Modifier("J", temp, x, y, centered));
7203                }
7204
7205                //Do left side labels
7206                x = -1;//on left
7207
7208                if(!strict)
7209                {
7210                    centered = false;
7211                }
7212
7213                if(modifiers.containsKey(Modifiers.Y_LOCATION))
7214                {
7215                    y = 1;
7216                    temp = modifiers.get(Modifiers.Y_LOCATION);
7217
7218                    if(temp != null && !temp.isEmpty())
7219                        mods.add(new Modifier("Y", temp, x, y, centered));
7220                }
7221
7222                if(modifiers.containsKey(Modifiers.W_DTG_1))
7223                {
7224                    y = 2;//above center
7225                    if(!strict && !(modifiers.containsKey(Modifiers.Y_LOCATION)))
7226                        y--;
7227
7228                    temp = modifiers.get(Modifiers.W_DTG_1);
7229
7230                    if(temp != null && !temp.isEmpty())
7231                        mods.add(new Modifier("W", temp, x, y, centered));
7232                }
7233
7234                if(modifiers.containsKey(Modifiers.C_QUANTITY))
7235                {
7236                    y = -1;//below center
7237                    temp = modifiers.get(Modifiers.C_QUANTITY);
7238
7239                    if(temp != null && !temp.isEmpty())
7240                        mods.add(new Modifier("C", temp, x, y, centered));
7241                }
7242
7243            }
7244            else if(ss == SymbolID.SymbolSet_CyberSpace ||
7245                    (ss == SymbolID.SymbolSet_SignalsIntelligence && fs == SymbolID.FrameShape_Cyberspace))
7246            {
7247                //Do top center label
7248                x = 0;//centered
7249                y = 9;//on top of symbol
7250                if(modifiers.containsKey(Modifiers.B_ECHELON))
7251                {
7252                    temp = modifiers.get(Modifiers.B_ECHELON);
7253                    if(temp != null && !temp.isEmpty())
7254                        mods.add(new Modifier("B", temp, x, y, centered));
7255                }
7256
7257                //Do right side labels
7258                x = 1;//on right
7259                if(modifiers.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
7260                {
7261                    y = 0;//center
7262                    centered = true;//vertically centered, only matters for labels on left and right side
7263                    temp = modifiers.get(Modifiers.H_ADDITIONAL_INFO_1);
7264
7265                    if(temp != null && !temp.isEmpty())
7266                        mods.add(new Modifier("H", temp, x, y, centered));
7267                }
7268                else if(!strict)
7269                {
7270                    centered = false;
7271                }
7272
7273                if(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS))
7274                {
7275                    y = 1;//above center
7276                    temp = modifiers.get(Modifiers.G_STAFF_COMMENTS);
7277
7278                    if(temp != null && !temp.isEmpty())
7279                        mods.add(new Modifier("G", temp, x, y, centered));
7280                }
7281
7282                if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED) || modifiers.containsKey(Modifiers.AS_COUNTRY))
7283                {
7284                    y = 2;
7285                    if(!strict && !(modifiers.containsKey(Modifiers.G_STAFF_COMMENTS)))
7286                        y--;
7287                    temp = "";
7288                    if(modifiers.containsKey(Modifiers.F_REINFORCED_REDUCED))
7289                        temp = modifiers.get(Modifiers.F_REINFORCED_REDUCED) + sep;
7290                    if(modifiers.containsKey(Modifiers.AS_COUNTRY))
7291                        temp += modifiers.get(Modifiers.AS_COUNTRY);
7292                    temp = temp.trim();
7293                    if(temp != null && !temp.isEmpty())
7294                        mods.add(new Modifier("F AS", temp, x, y, centered));
7295                }
7296
7297                if(modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7298                {
7299                    y = -1;//below center
7300                    temp = modifiers.get(Modifiers.M_HIGHER_FORMATION);
7301                    if(temp != null && !temp.isEmpty())
7302                        mods.add(new Modifier("M", temp, x, y, centered));
7303                }
7304
7305                if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS) || modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
7306                {
7307                    y = -2;
7308                    if(!strict && !modifiers.containsKey(Modifiers.M_HIGHER_FORMATION))
7309                        y++;
7310                    temp = "";
7311                    if(modifiers.containsKey(Modifiers.K_COMBAT_EFFECTIVENESS))
7312                        temp = modifiers.get(Modifiers.K_COMBAT_EFFECTIVENESS) + sep;
7313                    if(modifiers.containsKey(Modifiers.L_SIGNATURE_EQUIP))
7314                        temp += modifiers.get(Modifiers.L_SIGNATURE_EQUIP);
7315                    temp = temp.trim();
7316                    if(temp != null && !temp.isEmpty())
7317                        mods.add(new Modifier("K L", temp, x, y, centered));
7318                }
7319
7320                //Do left side labels
7321                x=-1;
7322                if(modifiers.containsKey(Modifiers.V_EQUIP_TYPE))
7323                {
7324                    y = 0;//center
7325                    centered = true;//vertically centered, only matters for labels on left and right side
7326
7327                    temp = modifiers.get(Modifiers.V_EQUIP_TYPE);
7328
7329                    if(temp != null && !temp.isEmpty())
7330                        mods.add(new Modifier("V", temp, x, y, centered));
7331                }
7332                else if(!strict)
7333                {
7334                    centered = false;
7335                }
7336
7337                if(modifiers.containsKey(Modifiers.Y_LOCATION))
7338                {
7339                    y = 1;
7340                    temp = modifiers.get(Modifiers.Y_LOCATION);
7341
7342                    if(temp != null && !temp.isEmpty())
7343                        mods.add(new Modifier("Y", temp, x, y, centered));
7344                }
7345
7346                if(modifiers.containsKey(Modifiers.W_DTG_1))
7347                {
7348                    y = 2;//above center
7349                    if(!strict && !(modifiers.containsKey(Modifiers.Y_LOCATION)))
7350                        y--;
7351
7352                    temp = modifiers.get(Modifiers.W_DTG_1);
7353
7354                    if(temp != null && !temp.isEmpty())
7355                        mods.add(new Modifier("W", temp, x, y, centered));
7356                }
7357
7358                if(modifiers.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
7359                {
7360                    y = -1;//below center
7361                    temp = modifiers.get(Modifiers.T_UNIQUE_DESIGNATION_1);
7362
7363                    if(temp != null && !temp.isEmpty())
7364                        mods.add(new Modifier("T", temp, x, y, centered));
7365                }
7366            }
7367            /*else if(ver == SymbolID.SymbolSet_MineWarfare)
7368            {
7369                //no modifiers
7370            }//*/
7371            //else//SymbolSet Unknown
7372            //processUnknownTextModifiers
7373        }
7374
7375        return mods;
7376    }
7377
7378
7379    /**
7380     * @param bounds     bounds of the core icon
7381     * @param labelWidth height of the label to be placed
7382     * @param location   -1 left, 0 center, 1 right
7383     * @returns
7384     */
7385    private static double getLabelXPosition(Rect bounds, int labelWidth, int location, float modifierFontHeight)
7386    {
7387        int buffer = (int)modifierFontHeight/2;
7388
7389        double x = 0;
7390        if(location == 1)//on right
7391        {
7392            x = bounds.left + bounds.width() + buffer;
7393        }
7394        else if(location == -1)//left
7395        {
7396            x = bounds.left - labelWidth - buffer;
7397        }
7398        else if(location == 0)
7399        {
7400            x = Math.round((bounds.left + (bounds.width() * 0.5f)) - (labelWidth * 0.5f));
7401        }
7402        return x;
7403    }
7404
7405    /**
7406     *
7407     * @param bounds bounds of the core icon
7408     * @param labelHeight height of the label to be placed
7409     * @param descent descent of the label to be placed
7410     * @param bufferText spacing buffer if desired
7411     * @param centered if true, there will be a center label location identified by 0
7412     * @param location positive 1, 2, 3 to be above symbol mid-point or negative values to be below
7413     * @returns y position
7414     */
7415    private static double getLabelYPosition(Rect bounds, int labelHeight, int descent, int bufferText, boolean centered, int location) {
7416        double y = 0;
7417        if (bounds != null && !bounds.isEmpty())
7418        {
7419            if(centered)
7420            {
7421                switch (location)
7422                {
7423                    case 3://3 above center
7424                        y = (bounds.height());
7425                        y = ((y * 0.5) + (labelHeight * 0.5));
7426                        y = y - ((labelHeight + bufferText) * 3);
7427                        y = bounds.top + y;
7428                        break;
7429                    case 2://2 above center
7430                        y = (bounds.height());
7431                        y = ((y * 0.5) + (labelHeight * 0.5));
7432                        y = y - ((labelHeight + bufferText) * 2);
7433                        y = bounds.top + y;
7434                        break;
7435                    case 1://1 above center
7436                        y = (bounds.height());
7437                        y = ((y * 0.5) + (labelHeight * 0.5));
7438                        y = y - ((labelHeight + bufferText));
7439                        y = bounds.top + y;
7440                        break;
7441                    case 0: //centered
7442                        y = (bounds.height());
7443                        y = ((y * 0.5) + ((labelHeight - descent) * 0.5));
7444                        y = bounds.top + y;
7445                        break;
7446                    case -1://1 below center
7447                        y = (bounds.height());
7448                        y = ((y * 0.5) + (labelHeight * 0.5));
7449                        y = y + ((labelHeight + bufferText - descent));
7450                        y = bounds.top + y;
7451                        break;
7452                    case -2://2 below center
7453                        y = (bounds.height());
7454                        y = ((y * 0.5) + (labelHeight * 0.5));
7455                        y = y + ((labelHeight + bufferText) * 2) - (descent);
7456                        y = bounds.top + y;
7457                        break;
7458                    case -3://3 below center
7459                        y = (bounds.height());
7460                        y = ((y * 0.5) + (labelHeight * 0.5));
7461                        y = y + ((labelHeight + bufferText) * 3) - (descent);
7462                        y = bounds.top + y;
7463                        break;
7464                }
7465            }
7466            else//split between top and bottom
7467            {
7468                switch (location)
7469                {
7470                    case 3:
7471                        y = (bounds.top + ((bounds.height() / 2) - descent - labelHeight*2 - bufferText));
7472                        break;
7473                    case 2:
7474                        y = (bounds.top + ((bounds.height() / 2) - descent - labelHeight - bufferText));
7475                        break;
7476                    case 1:
7477                        y = (bounds.top + ((bounds.height() / 2) - descent));
7478                        break;
7479                    case -1:
7480                        y = (bounds.top + (bounds.height() / 2) + (labelHeight - descent + bufferText));
7481                        break;
7482                    case -2:
7483                        y = (bounds.top + (bounds.height() / 2) + ((labelHeight*2 - descent + bufferText)));
7484                        break;
7485                    case -3:
7486                        y = (bounds.top + (bounds.height() / 2) + ((labelHeight*3 - descent + bufferText)));
7487                        break;
7488                }
7489            }
7490            if(location == 9)//on top of symbol
7491            {
7492                y = Math.round(bounds.top - bufferText - descent);
7493            }
7494        }
7495        return y;
7496    }
7497
7498    /**
7499     * Currently, modifiers are based on Symbol Set.
7500     * The exception is SIGINT which required a frame shape value in 2525E+
7501     * The SSMC couldn't come to an agreement on if frame shape should dictate modifiers.
7502     * Currently, I'm keeping it tied to Symbol Set.
7503     * @param symbolID
7504     * @return
7505     */
7506    private static boolean isCOnTop(String symbolID)
7507    {
7508        boolean onTop = false;
7509
7510        int version = SymbolID.getVersion(symbolID);
7511        int ss = SymbolID.getSymbolSet(symbolID);
7512        char frame = SymbolID.getFrameShape(symbolID);
7513
7514        if(SymbolUtilities.hasModifier(symbolID,Modifiers.C_QUANTITY)) {
7515
7516            if(version >= SymbolID.Version_2525E)
7517            {
7518
7519                if (ss == SymbolID.SymbolSet_Air ||
7520                        ss == SymbolID.SymbolSet_AirMissile ||
7521                        ss == SymbolID.SymbolSet_Space ||
7522                        ss == SymbolID.SymbolSet_SpaceMissile ||
7523                        ss == SymbolID.SymbolSet_LandEquipment)
7524                {
7525                    onTop = true;
7526                }
7527                else if(ss == SymbolID.SymbolSet_SignalsIntelligence &&
7528                        (frame == SymbolID.FrameShape_Air ||
7529                        frame == SymbolID.FrameShape_Space ||
7530                        frame == SymbolID.FrameShape_LandEquipment || frame == SymbolID.FrameShape_LandUnit || frame == '0'))
7531                {
7532                    onTop = true;
7533                }
7534
7535            }// else if <= SymbolID.Version_2525Dch1
7536            else if (ss == SymbolID.SymbolSet_LandEquipment ||
7537                    ss == SymbolID.SymbolSet_SignalsIntelligence_Land)
7538            {
7539                onTop = true;
7540            }
7541        }
7542        return onTop;
7543    }
7544    public static boolean hasDisplayModifiers(String symbolID, Map<String,String> modifiers)
7545    {
7546        boolean hasModifiers = false;
7547        int ss = SymbolID.getSymbolSet(symbolID);
7548        int status = SymbolID.getStatus(symbolID);
7549        int context = SymbolID.getContext(symbolID);
7550
7551        if(ss == SymbolID.SymbolSet_ControlMeasure)//check control measure
7552        {
7553            if (SymbolUtilities.isCBRNEvent(symbolID) == true && modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT))
7554            {
7555                hasModifiers = true;
7556            }
7557            else if(SymbolUtilities.hasFDI(symbolID))
7558                hasModifiers = true;
7559        }
7560        else if(ss != SymbolID.SymbolSet_Atmospheric &&
7561                ss != SymbolID.SymbolSet_Oceanographic &&
7562                ss != SymbolID.SymbolSet_MeteorologicalSpace)
7563        {//checking units
7564
7565            if(context > 0) //Exercise or Simulation
7566                hasModifiers = true;
7567
7568            //echelon or mobility,
7569            if (SymbolID.getAmplifierDescriptor(symbolID) > 0 || modifiers.containsKey(Modifiers.Q_DIRECTION_OF_MOVEMENT))
7570                hasModifiers = true;
7571
7572            if(modifiers.containsKey(Modifiers.AJ_SPEED_LEADER))
7573                hasModifiers = true;
7574
7575            if(modifiers.containsKey(Modifiers.AO_ENGAGEMENT_BAR))
7576                hasModifiers = true;
7577
7578            //HQ/Taskforce
7579            if(SymbolID.getHQTFD(symbolID) > 0)
7580                hasModifiers = true;
7581
7582            if(status > 1)//Fully capable, damaged, destroyed
7583                hasModifiers = true;
7584        }//no display modifiers for single point weather
7585
7586
7587
7588        return hasModifiers;
7589    }
7590
7591    public static boolean hasTextModifiers(String symbolID, Map<String,String> modifiers)
7592    {
7593
7594        int ss = SymbolID.getSymbolSet(symbolID);
7595        int ec = SymbolID.getEntityCode(symbolID);
7596        if(ss == SymbolID.SymbolSet_Atmospheric)
7597        {
7598            switch(ec)
7599            {
7600                case 110102: //tropopause low
7601                case 110202: //tropopause high
7602                case 162200: //tropopause level ?
7603                case 162300: //freezing level ?
7604                    return true;
7605                default:
7606                        return false;
7607            }
7608        }
7609        else if(ss == SymbolID.SymbolSet_Oceanographic || ss == SymbolID.SymbolSet_MeteorologicalSpace)
7610        {
7611            return false;
7612        }
7613        else if (ss == SymbolID.SymbolSet_ControlMeasure)
7614        {
7615            MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
7616
7617            if( msi.getModifiers().size() > 0 && modifiers != null && modifiers.size() > 0)
7618                return true;
7619            else
7620                return false;
7621        }
7622        else
7623        {
7624
7625            if (SymbolUtilities.getStandardIdentityModifier(symbolID) != null)
7626            {
7627                return true;
7628            }
7629
7630            int cc = SymbolID.getCountryCode(symbolID);
7631            if (cc > 0 && !GENCLookup.getInstance().get3CharCode(cc).isEmpty())
7632            {
7633                return true;
7634            }//*/
7635
7636            else if (modifiers.size() > 0)
7637            {
7638                return true;
7639            }
7640        }
7641        return false;
7642    }
7643
7644    /**
7645     * Rerturns either the default font from RendererSettings or font based on properties
7646     * set in MilStdAttributes.
7647     * @param attributes
7648     * @return
7649     */
7650    private static Paint getFont(Map<String,String> attributes)
7651    {
7652        Paint p = null;
7653        Typeface tf = null;
7654
7655        p = RendererSettings.getInstance().getModiferFont();
7656
7657        String[] props = RendererSettings.getInstance().getModiferFontProps();
7658
7659        String ff = props[0];
7660        int fstyle = Integer.parseInt(props[1]);// modifierFont.getTypeface().getStyle();
7661        float fsize = Float.parseFloat(props[2]);// modifierFont.getTextSize();
7662        String temp = null;
7663
7664
7665        if(attributes.containsKey(MilStdAttributes.FontFamily) ||
7666                attributes.containsKey(MilStdAttributes.FontStyle) ||
7667                attributes.containsKey(MilStdAttributes.FontSize))
7668        {
7669            if(attributes.containsKey(MilStdAttributes.FontStyle))
7670            {
7671                temp = attributes.get(MilStdAttributes.FontStyle);
7672                if (temp != null && !temp.isEmpty()) {
7673                    fstyle = Integer.parseInt(temp);
7674                }
7675            }
7676            if(attributes.containsKey(MilStdAttributes.FontSize))
7677            {
7678                temp = attributes.get(MilStdAttributes.FontSize);
7679                if (temp != null && !temp.isEmpty()) {
7680                    fsize = Float.parseFloat(temp);
7681                }
7682            }
7683            if(attributes.containsKey(MilStdAttributes.FontFamily))
7684            {
7685                temp = attributes.get(MilStdAttributes.FontFamily);
7686                if (temp != null && !temp.isEmpty()) {
7687                    ff =  temp;//Typeface.create(temp,fstyle);
7688                }
7689            }
7690            tf = Typeface.create(ff,fstyle);
7691            if(tf == null)
7692                tf = Typeface.create(props[0],fstyle);
7693            if(tf == null)
7694                return null;
7695
7696            p = new Paint();
7697            p.setTextSize(fsize);
7698            p.setAntiAlias(true);
7699            p.setTypeface(tf);
7700            p.setStrokeCap(Cap.BUTT);
7701            p.setStrokeJoin(Join.MITER);
7702            p.setStrokeMiter(3f);
7703
7704            return p;
7705        }
7706        else
7707            return _modifierFont;
7708
7709    }
7710
7711    private static float[] getFontHeightandDescent(Paint font)
7712    {
7713        float[] hd = {0f,0f};
7714
7715        if(font != null) {
7716            Paint.FontMetrics fm = font.getFontMetrics();
7717            //_modifierFontHeight = fm.top + fm.bottom;
7718            hd[0] = fm.bottom - fm.top;
7719            hd[1] = fm.descent;
7720        }
7721        return hd;
7722    }
7723
7724}