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