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