001/*
002 * A class to serve JavaRendererServer
003 */
004package armyc2.c5isr.RenderMultipoints;
005
006import android.content.Context;
007
008import java.util.ArrayList;
009import java.util.Collections;
010import java.util.HashMap;
011import java.util.Map;
012
013import armyc2.c5isr.JavaLineArray.CELineArray;
014import armyc2.c5isr.JavaLineArray.DISMSupport;
015import armyc2.c5isr.JavaLineArray.POINT2;
016import armyc2.c5isr.JavaLineArray.Shape2;
017import armyc2.c5isr.JavaLineArray.TacticalLines;
018import armyc2.c5isr.JavaLineArray.lineutility;
019import armyc2.c5isr.JavaTacticalRenderer.Modifier2;
020import armyc2.c5isr.JavaTacticalRenderer.TGLight;
021import armyc2.c5isr.JavaTacticalRenderer.mdlGeodesic;
022import armyc2.c5isr.graphics2d.BasicStroke;
023import armyc2.c5isr.graphics2d.BufferedImage;
024import armyc2.c5isr.graphics2d.Font;
025import armyc2.c5isr.graphics2d.Graphics2D;
026import armyc2.c5isr.graphics2d.Point2D;
027import armyc2.c5isr.graphics2d.Rectangle;
028import armyc2.c5isr.graphics2d.Rectangle2D;
029import armyc2.c5isr.renderer.utilities.Color;
030import armyc2.c5isr.renderer.utilities.DistanceUnit;
031import armyc2.c5isr.renderer.utilities.DrawRules;
032import armyc2.c5isr.renderer.utilities.ErrorLogger;
033import armyc2.c5isr.renderer.utilities.IPointConversion;
034import armyc2.c5isr.renderer.utilities.MSInfo;
035import armyc2.c5isr.renderer.utilities.MSLookup;
036import armyc2.c5isr.renderer.utilities.MilStdSymbol;
037import armyc2.c5isr.renderer.utilities.Modifiers;
038import armyc2.c5isr.renderer.utilities.RendererException;
039import armyc2.c5isr.renderer.utilities.RendererSettings;
040import armyc2.c5isr.renderer.utilities.ShapeInfo;
041import armyc2.c5isr.renderer.utilities.SymbolID;
042import armyc2.c5isr.renderer.utilities.SymbolUtilities;
043
044/**
045 * Rendering class
046 *
047*
048 */
049public final class clsRenderer {
050
051    private static final String _className = "clsRenderer";
052
053    /**
054     * Set tg geo points from the client points
055     *
056     * @param milStd
057     * @param tg
058     */
059    private static void setClientCoords(MilStdSymbol milStd,
060                                        TGLight tg) {
061        try {
062            ArrayList<POINT2> latLongs = new ArrayList();
063            int j = 0;
064            ArrayList<Point2D> coords = milStd.getCoordinates();
065            Point2D pt2d = null;
066            POINT2 pt2 = null;
067            int n = coords.size();
068            //for (j = 0; j < coords.size(); j++) 
069            for (j = 0; j < n; j++) {
070                pt2d = coords.get(j);
071                pt2 = clsUtility.Point2DToPOINT2(pt2d);
072                latLongs.add(pt2);
073            }
074            tg.set_LatLongs(latLongs);
075        } catch (Exception exc) {
076            ErrorLogger.LogException("clsRenderer", "setClientCoords",
077                    new RendererException("Failed to set geo points or pixels for " + milStd.getSymbolID(), exc));
078        }
079    }
080
081    private static ArrayList<Point2D> getClientCoords(TGLight tg) {
082        ArrayList<Point2D> coords = null;
083        try {
084            int j = 0;
085            Point2D pt2d = null;
086            POINT2 pt2 = null;
087            coords = new ArrayList();
088            int n = tg.LatLongs.size();
089            //for (j = 0; j < tg.LatLongs.size(); j++) 
090            for (j = 0; j < n; j++) {
091                pt2 = tg.LatLongs.get(j);
092                pt2d = new Point2D.Double(pt2.x, pt2.y);
093                coords.add(pt2d);
094            }
095        } catch (Exception exc) {
096            ErrorLogger.LogException("clsRenderer", "getClientCoords",
097                    new RendererException("Failed to set geo points or pixels for " + tg.get_SymbolId(), exc));
098        }
099        return coords;
100    }
101
102    /**
103     * Create MilStdSymbol from tactical graphic
104     *
105     * @deprecated
106     * @param tg tactical graphic
107     * @param converter geographic to pixels to converter
108     * @return MilstdSymbol object
109     */
110    public static MilStdSymbol createMilStdSymboFromTGLight(TGLight tg, IPointConversion converter) {
111        MilStdSymbol milStd = null;
112        try {
113            String symbolId = tg.get_SymbolId();
114            int lineType = armyc2.c5isr.JavaTacticalRenderer.clsUtility.GetLinetypeFromString(symbolId);
115            String status = tg.get_Status();
116            //build tg.Pixels
117            tg.Pixels = clsUtility.LatLongToPixels(tg.LatLongs, converter);
118            boolean isClosedArea = armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(lineType);
119            if (isClosedArea) {
120                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(tg.Pixels);
121                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(tg.LatLongs);
122            }
123
124            ArrayList<Point2D> coords = getClientCoords(tg);
125            tg.set_Font(new Font("Arial", Font.PLAIN, 12));
126            Map<String,String> modifiers = new HashMap<>();
127            modifiers.put(Modifiers.W_DTG_1, tg.get_DTG());
128            modifiers.put(Modifiers.W1_DTG_2, tg.get_DTG1());
129            modifiers.put(Modifiers.H_ADDITIONAL_INFO_1, tg.get_H());
130            modifiers.put(Modifiers.H1_ADDITIONAL_INFO_2, tg.get_H1());
131            modifiers.put(Modifiers.H2_ADDITIONAL_INFO_3, tg.get_H2());
132            modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, tg.get_Name());
133            modifiers.put(Modifiers.T1_UNIQUE_DESIGNATION_2, tg.get_T1());
134            modifiers.put(Modifiers.Y_LOCATION, tg.get_Location());
135            modifiers.put(Modifiers.N_HOSTILE, tg.get_N());
136
137            milStd = new MilStdSymbol(symbolId, "1", coords, modifiers);
138            milStd.setFillColor(tg.get_FillColor());
139            milStd.setLineColor(tg.get_LineColor());
140            milStd.setLineWidth(tg.get_LineThickness());
141            milStd.setFillStyle(tg.get_TexturePaint());
142            milStd.setPatternScale(tg.get_patternScale());
143        } catch (Exception exc) {
144            ErrorLogger.LogException("clsRenderer", "createMilStdSymboFromTGLight",
145                    new RendererException("Failed to set geo points or pixels for " + tg.get_SymbolId(), exc));
146        }
147        return milStd;
148    }
149
150    /**
151     * Build a tactical graphic object from the client MilStdSymbol
152     *
153     * @param milStd MilstdSymbol object
154     * @param converter geographic to pixels converter
155     * @return tactical graphic
156     */
157    public static TGLight createTGLightFromMilStdSymbol(MilStdSymbol milStd,
158            IPointConversion converter) {
159        TGLight tg = new TGLight();
160        try {
161            String symbolId = milStd.getSymbolID();
162            tg.set_SymbolId(symbolId);
163            boolean useLineInterpolation = milStd.getUseLineInterpolation();
164            tg.set_UseLineInterpolation(useLineInterpolation);
165            int lineType = armyc2.c5isr.JavaTacticalRenderer.clsUtility.GetLinetypeFromString(symbolId);
166            tg.set_LineType(lineType);
167            String status = tg.get_Status();
168            if (status != null && status.equals("A")) {
169                tg.set_LineStyle(1);
170            }
171            tg.set_VisibleModifiers(true);
172            //set tg latlongs and pixels
173            setClientCoords(milStd, tg);
174            //build tg.Pixels
175            tg.Pixels = clsUtility.LatLongToPixels(tg.LatLongs, converter);
176            //tg.set_Font(new Font("Arial", Font.PLAIN, 12));
177            RendererSettings r = RendererSettings.getInstance();
178            int type = r.getMPLabelFontType();
179            String name = r.getMPLabelFontName();
180            int sz = r.getMPLabelFontSize();
181            Font font = new Font(name, type, sz);
182            tg.set_Font(font);
183            tg.set_FillColor(milStd.getFillColor());
184            tg.set_LineColor(milStd.getLineColor());
185            tg.set_LineThickness(milStd.getLineWidth());
186            tg.set_TexturePaint(milStd.getFillStyle());
187            tg.set_patternScale(milStd.getPatternScale());
188
189            tg.set_IconSize(milStd.getUnitSize());
190            tg.set_KeepUnitRatio(milStd.getKeepUnitRatio());
191
192            tg.set_FontBackColor(Color.WHITE);
193            tg.set_TextColor(milStd.getTextColor());
194            if (milStd.getModifier(Modifiers.W_DTG_1) != null) {
195                tg.set_DTG(milStd.getModifier(Modifiers.W_DTG_1));
196            }
197            if (milStd.getModifier(Modifiers.W1_DTG_2) != null) {
198                tg.set_DTG1(milStd.getModifier(Modifiers.W1_DTG_2));
199            }
200            if (milStd.getModifier(Modifiers.H_ADDITIONAL_INFO_1) != null) {
201                tg.set_H(milStd.getModifier(Modifiers.H_ADDITIONAL_INFO_1));
202            }
203            if (milStd.getModifier(Modifiers.H1_ADDITIONAL_INFO_2) != null) {
204                tg.set_H1(milStd.getModifier(Modifiers.H1_ADDITIONAL_INFO_2));
205            }
206            if (milStd.getModifier(Modifiers.H2_ADDITIONAL_INFO_3) != null) {
207                tg.set_H2(milStd.getModifier(Modifiers.H2_ADDITIONAL_INFO_3));
208            }
209            if (milStd.getModifier(Modifiers.T_UNIQUE_DESIGNATION_1) != null) {
210                tg.set_Name(milStd.getModifier(Modifiers.T_UNIQUE_DESIGNATION_1));
211            }
212            if (milStd.getModifier(Modifiers.T1_UNIQUE_DESIGNATION_2) != null) {
213                tg.set_T1(milStd.getModifier(Modifiers.T1_UNIQUE_DESIGNATION_2));
214            }
215            if (milStd.getModifier(Modifiers.V_EQUIP_TYPE) != null) {
216                tg.set_V(milStd.getModifier(Modifiers.V_EQUIP_TYPE));
217            }
218            if (milStd.getModifier(Modifiers.AS_COUNTRY) != null) {
219                tg.set_AS(milStd.getModifier(Modifiers.AS_COUNTRY));
220            }
221            if (milStd.getModifier(Modifiers.AP_TARGET_NUMBER) != null) {
222                tg.set_AP(milStd.getModifier(Modifiers.AP_TARGET_NUMBER));
223            }
224            if (milStd.getModifier(Modifiers.Y_LOCATION) != null) {
225                tg.set_Location(milStd.getModifier(Modifiers.Y_LOCATION));
226            }
227            if (milStd.getModifier(Modifiers.N_HOSTILE) != null) {
228                tg.set_N(milStd.getModifier(Modifiers.N_HOSTILE));
229            }
230            tg.set_UseDashArray(milStd.getUseDashArray());
231            tg.set_UseHatchFill(milStd.getUseFillPattern());
232            //tg.set_UsePatternFill(milStd.getUseFillPattern());
233            tg.set_HideOptionalLabels(milStd.getHideOptionalLabels());
234            boolean isClosedArea = armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(lineType);
235
236            if (lineType == TacticalLines.STRIKWARN) {
237                ArrayList<POINT2> poly1Pixels = new ArrayList<>(tg.Pixels.subList(0, tg.Pixels.size() / 2));
238                ArrayList<POINT2> poly1LatLons = new ArrayList<>(tg.LatLongs.subList(0, tg.LatLongs.size() / 2));
239                ArrayList<POINT2> poly2Pixels = new ArrayList<>(tg.Pixels.subList(tg.Pixels.size() / 2, tg.Pixels.size()));
240                ArrayList<POINT2> poly2LatLons = new ArrayList<>(tg.LatLongs.subList(tg.LatLongs.size() / 2, tg.LatLongs.size()));
241
242                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(poly1Pixels);
243                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(poly1LatLons);
244                tg.Pixels = poly1Pixels;
245                tg.LatLongs = poly1LatLons;
246
247                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(poly2Pixels);
248                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(poly2LatLons);
249                tg.Pixels.addAll(poly2Pixels);
250                tg.LatLongs.addAll(poly2LatLons);
251            }
252            else if (isClosedArea) {
253                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(tg.Pixels);
254                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(tg.LatLongs);
255            }
256
257            //implement meters to feet for altitude labels
258            String altitudeLabel = milStd.getAltitudeMode();
259            if (altitudeLabel == null || altitudeLabel.isEmpty()) {
260                altitudeLabel = "AMSL";
261            }
262            DistanceUnit altitudeUnit = milStd.getAltitudeUnit();
263            if(altitudeUnit == null){
264                altitudeUnit = DistanceUnit.FEET;
265            }
266            DistanceUnit distanceUnit = milStd.getDistanceUnit();
267            if(distanceUnit == null){
268                distanceUnit = DistanceUnit.METERS;
269            }
270
271            String strXAlt = "";
272            //construct the H1 and H2 modifiers for sector from the mss AM, AN, and X arraylists
273            if (lineType == TacticalLines.RANGE_FAN_SECTOR) {
274                ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
275                ArrayList<Double> AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH);
276                ArrayList<Double> X = milStd.getModifiers_AM_AN_X(Modifiers.X_ALTITUDE_DEPTH);
277                if (AM != null) {
278                    String strAM = "";
279                    for (int j = 0; j < AM.size(); j++) {
280                        strAM += Double.toString(AM.get(j));
281                        if (j < AM.size() - 1) {
282                            strAM += ",";
283                        }
284                    }
285                    tg.set_AM(strAM);
286                }
287                if (AN != null) {
288                    String strAN = "";
289                    for (int j = 0; j < AN.size(); j++) {
290                        strAN += AN.get(j);
291                        if (j < AN.size() - 1) {
292                            strAN += ",";
293                        }
294                    }
295                    tg.set_AN(strAN);
296                }
297                if (X != null) {
298                    String strX = "";
299                    for (int j = 0; j < X.size(); j++) {
300                        strXAlt = createAltitudeLabel(X.get(j), altitudeUnit, altitudeLabel);
301                        strX += strXAlt;
302
303                        if (j < X.size() - 1) {
304                            strX += ",";
305                        }
306                    }
307                    tg.set_X(strX);
308                }
309                if (AM != null && AN != null) {
310                    int numSectors = AN.size() / 2;
311                    double left, right, min = 0, max = 0;
312                    //construct left,right,min,max from the arraylists
313                    String strLeftRightMinMax = "";
314                    for (int j = 0; j < numSectors; j++) {
315                        left = AN.get(2 * j);
316                        right = AN.get(2 * j + 1);
317                        if (j + 1 == AM.size()) {
318                            break;
319                        }
320                        min = AM.get(j);
321                        max = AM.get(j + 1);
322                        strLeftRightMinMax += Double.toString(left) + "," + Double.toString(right) + "," + Double.toString(min) + "," + Double.toString(max);
323                        if (j < numSectors - 1) {
324                            strLeftRightMinMax += ",";
325                        }
326
327                    }
328                    int len = strLeftRightMinMax.length();
329                    String c = strLeftRightMinMax.substring(len - 1, len);
330                    if (c.equalsIgnoreCase(",")) {
331                        strLeftRightMinMax = strLeftRightMinMax.substring(0, len - 1);
332                    }
333                    tg.set_LRMM(strLeftRightMinMax);
334                }
335            } else if (lineType == TacticalLines.RADAR_SEARCH) {
336                ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
337                ArrayList<Double> AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH);
338                if (AM != null) {
339                    String strAM = "";
340                    for (int j = 0; j < AM.size() && j < 2; j++) {
341                        strAM += Double.toString(AM.get(j));
342                        if (j < AM.size() - 1) {
343                            strAM += ",";
344                        }
345                    }
346                    tg.set_AM(strAM);
347                }
348                if (AN != null) {
349                    String strAN = "";
350                    for (int j = 0; j < AN.size() && j < 2; j++) {
351                        strAN += AN.get(j);
352                        if (j < AN.size() - 1) {
353                            strAN += ",";
354                        }
355                    }
356                    tg.set_AN(strAN);
357                }
358                if (AM != null && AN != null) {
359                    double left, right, min = 0, max = 0;
360                    //construct left,right,min,max from the arraylists
361                    String strLeftRightMinMax = "";
362                    left = AN.get(0);
363                    right = AN.get(1);
364                    min = AM.get(0);
365                    max = AM.get(1);
366                    strLeftRightMinMax += Double.toString(left) + "," + Double.toString(right) + "," + Double.toString(min) + "," + Double.toString(max);
367                    tg.set_LRMM(strLeftRightMinMax);
368                }
369            }
370            int j = 0;
371            if (lineType == TacticalLines.LAUNCH_AREA || lineType == TacticalLines.DEFENDED_AREA_CIRCULAR || lineType == TacticalLines.SHIP_AOI_CIRCULAR) //geo ellipse
372            {
373                ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
374                ArrayList<Double> AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH);
375                if (AM != null && AM.size() > 1) {
376                    String strAM = AM.get(0).toString(); // major axis
377                    tg.set_AM(strAM);
378                    String strAM1 = AM.get(1).toString(); // minor axis
379                    tg.set_AM1(strAM1);
380                }
381                if (AN != null && AN.size() > 0) {
382                    String strAN = AN.get(0).toString(); // rotation
383                    tg.set_AN(strAN);
384                }
385            }
386            switch (lineType) {
387                case TacticalLines.ROZ:
388                case TacticalLines.AARROZ:
389                case TacticalLines.UAROZ:
390                case TacticalLines.WEZ:
391                case TacticalLines.FEZ:
392                case TacticalLines.JEZ:
393                case TacticalLines.FAADZ:
394                case TacticalLines.HIDACZ:
395                case TacticalLines.MEZ:
396                case TacticalLines.LOMEZ:
397                case TacticalLines.HIMEZ:
398                case TacticalLines.ACA:
399                case TacticalLines.ACA_RECTANGULAR:
400                case TacticalLines.ACA_CIRCULAR:
401                    ArrayList<Double> X = milStd.getModifiers_AM_AN_X(Modifiers.X_ALTITUDE_DEPTH);
402                    if (X != null && X.size() > 0) {
403                        strXAlt = createAltitudeLabel(X.get(0), altitudeUnit, altitudeLabel);
404                        tg.set_X(strXAlt);
405                    }
406                    if (X != null && X.size() > 1) {
407                        strXAlt = createAltitudeLabel(X.get(1), altitudeUnit, altitudeLabel);
408                        tg.set_X1(strXAlt);
409                    }
410                    break;
411                case TacticalLines.SC:
412                case TacticalLines.MRR:
413                case TacticalLines.SL:
414                case TacticalLines.TC:
415                case TacticalLines.LLTR:
416                case TacticalLines.AC:
417                case TacticalLines.SAAFR:
418                    POINT2 pt = tg.LatLongs.get(0);
419                    Point2D pt2d0 = new Point2D.Double(pt.x, pt.y);
420                    Point2D pt2d0Pixels = converter.GeoToPixels(pt2d0);
421                    POINT2 pt0Pixels = new POINT2(pt2d0Pixels.getX(), pt2d0Pixels.getY());
422
423                    //get some point 10000 meters away from pt
424                    //10000 should work for any scale                    
425                    double dist = 10000;
426                    POINT2 pt2 = mdlGeodesic.geodesic_coordinate(pt, dist, 0);
427                    Point2D pt2d1 = new Point2D.Double(pt2.x, pt2.y);
428                    Point2D pt2d1Pixels = converter.GeoToPixels(pt2d1);
429                    POINT2 pt1Pixels = new POINT2(pt2d1Pixels.getX(), pt2d1Pixels.getY());
430                    //calculate pixels per meter
431                    double distPixels = lineutility.CalcDistanceDouble(pt0Pixels, pt1Pixels);
432                    double pixelsPerMeter = distPixels / dist;
433
434                    ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
435                    if (AM != null) {
436                        String strAM = "";
437                        for (j = 0; j < AM.size(); j++) {
438                            strAM += AM.get(j).toString();
439                            if (j < AM.size() - 1) {
440                                strAM += ",";
441                            }
442                        }
443                        tg.set_AM(strAM);
444                    }
445                    String[] strRadii = null;
446                    //get the widest value
447                    //the current requirement is to use the greatest width as the default width
448                    double maxWidth = 0,
449                    temp = 0;
450                    double maxWidthMeters = 0;
451                    if (tg.get_AM() != null && tg.get_AM().isEmpty() == false) {
452                        strRadii = tg.get_AM().split(",");
453                        if (strRadii.length > 0) {
454                            for (j = 0; j < strRadii.length; j++) {
455                                if (!Double.isNaN(Double.parseDouble(strRadii[j]))) {
456                                    temp = Double.parseDouble(strRadii[j]);
457                                    if (temp > maxWidth) {
458                                        maxWidth = temp;
459                                    }
460                                }
461                            }
462                            maxWidthMeters = maxWidth;
463                            maxWidth *= pixelsPerMeter / 2;
464
465                            for (j = 0; j < tg.Pixels.size(); j++) {
466                                if (strRadii.length > j) {
467                                    if (!Double.isNaN(Double.parseDouble(strRadii[j]))) {
468                                        double pixels = Double.parseDouble(strRadii[j]) * pixelsPerMeter / 2;
469                                        tg.Pixels.get(j).style = (int) pixels;
470                                        tg.LatLongs.get(j).style = (int) pixels;
471                                    } else {
472                                        tg.Pixels.get(j).style = (int) maxWidth;
473                                        tg.LatLongs.get(j).style = (int) maxWidth;
474                                    }
475                                } else {
476                                    tg.Pixels.get(j).style = (int) maxWidth;
477                                    tg.LatLongs.get(j).style = (int) maxWidth;
478                                }
479                            }
480                        }
481                    }
482
483                    maxWidthMeters *= distanceUnit.conversionFactor;
484                    maxWidthMeters *= 10.0;
485                    maxWidthMeters = Math.round(maxWidthMeters);
486                    int tempWidth = (int) maxWidthMeters;
487                    maxWidthMeters = tempWidth / 10.0;
488
489                    tg.set_AM(Double.toString(maxWidthMeters) + " " + distanceUnit.label);
490                    //use X, X1 to set tg.H, tg.H1
491                    X = milStd.getModifiers_AM_AN_X(Modifiers.X_ALTITUDE_DEPTH);
492                    if (X != null && X.size() > 0) {
493                        strXAlt = createAltitudeLabel(X.get(0), altitudeUnit, altitudeLabel);
494                        tg.set_X(strXAlt);
495                    }
496                    if (X != null && X.size() > 1) {
497                        strXAlt = createAltitudeLabel(X.get(1), altitudeUnit, altitudeLabel);
498                        tg.set_X1(strXAlt);
499                    }
500                    break;
501                default:
502                    break;
503            }
504            //circular range fans
505            if (lineType == TacticalLines.RANGE_FAN) {
506                ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
507                ArrayList<Double> X = milStd.getModifiers_AM_AN_X(Modifiers.X_ALTITUDE_DEPTH);
508                String strAM = "";
509                String strX = "";
510                if (AM != null) {
511                    // Range fan circular has a maximum of 3 circles
512                    for (j = 0; j < AM.size() && j < 3; j++) {
513                        strAM += Double.toString(AM.get(j));
514                        if (j < AM.size() - 1) {
515                            strAM += ",";
516                        }
517
518                        if (X != null && j < X.size()) {
519                            strXAlt = createAltitudeLabel(X.get(j), altitudeUnit, altitudeLabel);
520                            strX += strXAlt;
521                            if (j < X.size() - 1) {
522                                strX += ",";
523                            }
524                        }
525                    }
526                }
527                tg.set_AM(strAM);
528                tg.set_X(strX);
529            }
530            switch (lineType) {
531                case TacticalLines.PAA_RECTANGULAR:
532                case TacticalLines.RECTANGULAR_TARGET:
533                case TacticalLines.FSA_RECTANGULAR:
534                case TacticalLines.SHIP_AOI_RECTANGULAR:
535                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
536                case TacticalLines.FFA_RECTANGULAR:
537                case TacticalLines.ACA_RECTANGULAR:
538                case TacticalLines.NFA_RECTANGULAR:
539                case TacticalLines.RFA_RECTANGULAR:
540                case TacticalLines.ATI_RECTANGULAR:
541                case TacticalLines.CFFZ_RECTANGULAR:
542                case TacticalLines.SENSOR_RECTANGULAR:
543                case TacticalLines.CENSOR_RECTANGULAR:
544                case TacticalLines.DA_RECTANGULAR:
545                case TacticalLines.CFZ_RECTANGULAR:
546                case TacticalLines.ZOR_RECTANGULAR:
547                case TacticalLines.TBA_RECTANGULAR:
548                case TacticalLines.TVAR_RECTANGULAR:
549                case TacticalLines.CIRCULAR:
550                case TacticalLines.BDZ:
551                case TacticalLines.FSA_CIRCULAR:
552                case TacticalLines.NOTACK:
553                case TacticalLines.ACA_CIRCULAR:
554                case TacticalLines.FFA_CIRCULAR:
555                case TacticalLines.NFA_CIRCULAR:
556                case TacticalLines.RFA_CIRCULAR:
557                case TacticalLines.PAA_CIRCULAR:
558                case TacticalLines.ATI_CIRCULAR:
559                case TacticalLines.CFFZ_CIRCULAR:
560                case TacticalLines.SENSOR_CIRCULAR:
561                case TacticalLines.CENSOR_CIRCULAR:
562                case TacticalLines.DA_CIRCULAR:
563                case TacticalLines.CFZ_CIRCULAR:
564                case TacticalLines.ZOR_CIRCULAR:
565                case TacticalLines.TBA_CIRCULAR:
566                case TacticalLines.TVAR_CIRCULAR:
567                case TacticalLines.KILLBOXBLUE_CIRCULAR:
568                case TacticalLines.KILLBOXPURPLE_CIRCULAR:
569                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
570                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
571                    ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
572                    if (AM != null && AM.size() > 0) {
573                        String strAM = Double.toString(AM.get(0));
574                        //set width for rectangles or radius for circles
575                        tg.set_AM(strAM);
576                    }
577                    break;
578                default:
579                    break;
580            }
581            if (lineType == TacticalLines.RECTANGULAR || lineType == TacticalLines.CUED_ACQUISITION) {
582                ArrayList<Double> AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE);
583                ArrayList<Double> AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH);
584                if (AN == null) {
585                    AN = new ArrayList<>();
586                }
587                if (AN.isEmpty()) {
588                    AN.add(0d);
589                }
590
591                if (AM != null && AM.size() > 1) {
592                    String strAM = Double.toString(AM.get(0));    //width
593                    String strAM1 = Double.toString(AM.get(1));     //length
594                    //set width and length in meters for rectangular target
595                    tg.set_AM(strAM);
596                    tg.set_AM1(strAM1);
597                    //set attitude in degrees
598                    String strAN = Double.toString(AN.get(0));
599                    tg.set_AN(strAN);
600                }
601                /*
602                if(AM.size()>2)
603                {
604                    String strH1 = Double.toString(AM.get(2));     //buffer size
605                    tg.set_H1(strH1);
606                }
607                 */
608            }
609        } catch (Exception exc) {
610            ErrorLogger.LogException("clsRenderer", "createTGLightfromMilStdSymbol",
611                    new RendererException("Failed to build multipoint TG for " + milStd.getSymbolID(), exc));
612        }
613        return tg;
614    }
615
616    private static String createAltitudeLabel(double distance, DistanceUnit altitudeUnit, String altitudeLabel){
617        double conversionFactor;
618
619        // if using "FL" (Flight Level) for altitudeLabel, override conversion factor to avoid potential user error with altitudeUnit
620        if (altitudeLabel.equals("FL")) {
621            conversionFactor = DistanceUnit.FLIGHT_LEVEL.conversionFactor;
622        } else {
623            conversionFactor = altitudeUnit.conversionFactor;
624        }
625
626        // Truncate the result
627        double result = distance * conversionFactor;
628        result *= 10.0;
629        result = Math.round(result);
630        int tempResult = (int) result;
631        int truncatedResult = tempResult / 10;
632        // MIL-STD-2525D says altitude/depth must be an integer
633
634        // Simplifies labels of "0 units AGL" to "GL" (Ground Level) and "0 units AMSL/BMSL" to "MSL" (Mean Sea Level)
635        // as permitted by MIL-STD-2525D 5.3.7.5.1.
636        // Also works for "0 units GL" and "0 units MSL", which are improperly labeled but can be understood to mean the same thing.
637        if (truncatedResult == 0) {
638            if (altitudeLabel.equals("AGL") || altitudeLabel.equals("GL")) {
639                return "GL";
640            }
641            if (altitudeLabel.equals("AMSL") || altitudeLabel.equals("BMSL") || altitudeLabel.equals("MSL")) {
642                return "MSL";
643            }
644        }
645
646        // Flight level is a special altitude displayed as "FL ###" where ### are 3 digits representing hundreds of feet.
647        if (altitudeLabel.equals("FL")) {
648            return "FL " + String.format("%03d", truncatedResult);
649        }
650
651        return truncatedResult + " " + altitudeUnit.label + " " + altitudeLabel;
652    }
653
654    /**
655     * @deprecated @param milStd
656     * @param converter
657     * @param computeChannelPt
658     * @return
659     */
660    public static TGLight createTGLightFromMilStdSymbol(MilStdSymbol milStd,
661            IPointConversion converter, Boolean computeChannelPt) {
662        TGLight tg = new TGLight();
663        try {
664            String symbolId = milStd.getSymbolID();
665            tg.set_SymbolId(symbolId);
666            String status = tg.get_Status();
667            if (status != null && status.equals("A")) {
668                //lineStyle=GraphicProperties.LINE_TYPE_DASHED;
669                tg.set_LineStyle(1);
670            }
671            tg.set_VisibleModifiers(true);
672            //set tg latlongs and pixels
673            setClientCoords(milStd, tg);
674            //build tg.Pixels
675            tg.Pixels = clsUtility.LatLongToPixels(tg.LatLongs, converter);
676            tg.set_Font(new Font("Arial", Font.PLAIN, 12));
677            tg.set_FillColor(milStd.getFillColor());
678            tg.set_LineColor(milStd.getLineColor());
679            tg.set_LineThickness(milStd.getLineWidth());
680            tg.set_TexturePaint(milStd.getFillStyle());
681            tg.set_patternScale(milStd.getPatternScale());
682            tg.set_FontBackColor(Color.WHITE);
683            tg.set_TextColor(milStd.getTextColor());
684
685//            tg.set_DTG(milStd.getModifier(Modifiers.W_DTG_1));
686//            tg.set_DTG1(milStd.getModifier(Modifiers.W1_DTG_2));
687//            tg.set_H(milStd.getModifier(Modifiers.H_ADDITIONAL_INFO_1));
688//            tg.set_H1(milStd.getModifier(Modifiers.H1_ADDITIONAL_INFO_2));
689//            tg.set_H2(milStd.getModifier(Modifiers.H2_ADDITIONAL_INFO_3));
690//            tg.set_Name(milStd.getModifier(Modifiers.T_UNIQUE_DESIGNATION_1));
691//            tg.set_T1(milStd.getModifier(Modifiers.T1_UNIQUE_DESIGNATION_2));
692//            tg.set_Location(milStd.getModifier(Modifiers.Y_LOCATION));
693//            tg.set_N(Modifiers.N_HOSTILE);
694            if (milStd.getModifier(Modifiers.W_DTG_1) != null) {
695                tg.set_DTG(milStd.getModifier(Modifiers.W_DTG_1));
696            }
697            if (milStd.getModifier(Modifiers.W1_DTG_2) != null) {
698                tg.set_DTG1(milStd.getModifier(Modifiers.W1_DTG_2));
699            }
700            if (milStd.getModifier(Modifiers.H_ADDITIONAL_INFO_1) != null) {
701                tg.set_H(milStd.getModifier(Modifiers.H_ADDITIONAL_INFO_1));
702            }
703            if (milStd.getModifier(Modifiers.H1_ADDITIONAL_INFO_2) != null) {
704                tg.set_H1(milStd.getModifier(Modifiers.H1_ADDITIONAL_INFO_2));
705            }
706            if (milStd.getModifier(Modifiers.H2_ADDITIONAL_INFO_3) != null) {
707                tg.set_H2(milStd.getModifier(Modifiers.H2_ADDITIONAL_INFO_3));
708            }
709            if (milStd.getModifier(Modifiers.T_UNIQUE_DESIGNATION_1) != null) {
710                tg.set_Name(milStd.getModifier(Modifiers.T_UNIQUE_DESIGNATION_1));
711            }
712            if (milStd.getModifier(Modifiers.T1_UNIQUE_DESIGNATION_2) != null) {
713                tg.set_T1(milStd.getModifier(Modifiers.T1_UNIQUE_DESIGNATION_2));
714            }
715            if (milStd.getModifier(Modifiers.V_EQUIP_TYPE) != null) {
716                tg.set_V(milStd.getModifier(Modifiers.V_EQUIP_TYPE));
717            }
718            if (milStd.getModifier(Modifiers.AS_COUNTRY) != null) {
719                tg.set_AS(milStd.getModifier(Modifiers.AS_COUNTRY));
720            }
721            if (milStd.getModifier(Modifiers.AP_TARGET_NUMBER) != null) {
722                tg.set_AP(milStd.getModifier(Modifiers.AP_TARGET_NUMBER));
723            }
724            if (milStd.getModifier(Modifiers.Y_LOCATION) != null) {
725                tg.set_Location(milStd.getModifier(Modifiers.Y_LOCATION));
726            }
727            if (milStd.getModifier(Modifiers.N_HOSTILE) != null) {
728                tg.set_N(milStd.getModifier(Modifiers.N_HOSTILE));
729            }
730
731            //int lineType=CELineArray.CGetLinetypeFromString(tg.get_SymbolId());
732            int lineType = armyc2.c5isr.JavaTacticalRenderer.clsUtility.GetLinetypeFromString(symbolId);
733            boolean isClosedArea = armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(lineType);
734
735            if (isClosedArea) {
736                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(tg.Pixels);
737                armyc2.c5isr.JavaTacticalRenderer.clsUtility.ClosePolygon(tg.LatLongs);
738            }
739
740            //these channels need a channel point added
741            if (computeChannelPt) {
742                switch (lineType) {
743                    case TacticalLines.CATK:
744                    case TacticalLines.CATKBYFIRE:
745                    case TacticalLines.AAAAA:
746                    case TacticalLines.AIRAOA:
747                    case TacticalLines.MAIN:
748                    case TacticalLines.SPT:
749                        POINT2 ptPixels = armyc2.c5isr.JavaTacticalRenderer.clsUtility.ComputeLastPoint(tg.Pixels);
750                        tg.Pixels.add(ptPixels);
751                        //Point pt = clsUtility.POINT2ToPoint(ptPixels);
752                        Point2D pt = new Point2D.Double(ptPixels.x, ptPixels.y);
753                        //in case it needs the corresponding geo point
754                        Point2D ptGeo2d = converter.PixelsToGeo(pt);
755                        POINT2 ptGeo = clsUtility.Point2DToPOINT2(ptGeo2d);
756                        tg.LatLongs.add(ptGeo);
757                        //}
758                        break;
759                    default:
760                        break;
761                }
762            }
763        } catch (Exception exc) {
764            ErrorLogger.LogException("clsRenderer", "createTGLightfromMilStdSymbol",
765                    new RendererException("Failed to build multipoint TG for " + milStd.getSymbolID(), exc));
766        }
767        return tg;
768    }
769
770    private static void Shape2ToShapeInfo(ArrayList<ShapeInfo> shapeInfos, ArrayList<Shape2> shapes) {
771        try {
772            int j = 0;
773            Shape2 shape = null;
774            if (shapes == null || shapeInfos == null || shapes.size() == 0) {
775                return;
776            }
777
778            for (j = 0; j < shapes.size(); j++) {
779                shape = shapes.get(j);
780                shapeInfos.add((ShapeInfo) shape);
781            }
782        } catch (Exception exc) {
783            ErrorLogger.LogException("clsRenderer", "Shape2ToShapeInfo",
784                    new RendererException("Failed to build ShapeInfo ArrayList", exc));
785        }
786    }
787
788    /**
789     * Added function to handle when coords or display area spans IDL but not
790     * both, it prevents the symbol from rendering if the bounding rectangles
791     * don't intersect.
792     *
793     * @param tg
794     * @param converter
795     * @param clipArea
796     * @return
797     */
798    public static boolean intersectsClipArea(TGLight tg, IPointConversion converter, Object clipArea)
799    {
800        boolean result=false;
801        try
802        {
803            if (clipArea==null || tg.LatLongs.size() < 2)
804                return true;
805            Rectangle2D clipBounds = null;
806            ArrayList<Point2D> clipPoints = null;
807            
808//            if (clipArea != null) {
809//                if (clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
810//                    clipBounds = (Rectangle2D.Double) clipArea;
811//                } else if (clipArea.getClass().isAssignableFrom(Rectangle.class)) {
812//                    clipBounds = (Rectangle2D) clipArea;
813//                } else if (clipArea.getClass().isAssignableFrom(ArrayList.class)) {
814//                    clipPoints = (ArrayList<Point2D>) clipArea;
815//                }
816//            }
817            if (clipArea != null) {
818                if (clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
819                    clipBounds = (Rectangle2D.Double) clipArea;
820                } else if (clipArea.getClass().isAssignableFrom(Rectangle.class)) {
821                    Rectangle rectx = (Rectangle) clipArea;
822                    clipBounds = new Rectangle2D.Double(rectx.x, rectx.y, rectx.width, rectx.height);
823                } else if (clipArea.getClass().isAssignableFrom(ArrayList.class)) {
824                    clipPoints = (ArrayList<Point2D>) clipArea;                    
825                    //double x0=clipPoints.get(0).getX(),y0=clipPoints.get(0).getY();
826                    //double w=clipPoints.get(1).getX()-x0,h=clipPoints.get(3).getY()-y0;
827                    //clipBounds = new Rectangle2D.Double(x0, y0, w, h);                    
828                    clipBounds=clsUtility.getMBR(clipPoints);
829                }
830            }
831            //assumes we are using clipBounds
832            int j = 0;
833            double x = clipBounds.getMinX();
834            double y = clipBounds.getMinY();
835            double width = clipBounds.getWidth();
836            double height = clipBounds.getHeight();
837            POINT2 tl = new POINT2(x, y);
838            POINT2 br = new POINT2(x + width, y + height);
839            tl = clsUtility.PointPixelsToLatLong(tl, converter);
840            br = clsUtility.PointPixelsToLatLong(br, converter);
841            //the latitude range
842            //boolean ptInside = false, ptAbove = false, ptBelow = false;
843            double coordsLeft = tg.LatLongs.get(0).x;
844            double coordsRight = coordsLeft;
845            double coordsTop=tg.LatLongs.get(0).y;
846            double coordsBottom=coordsTop;
847            boolean intersects=false;
848            double minx=tg.LatLongs.get(0).x,maxx=minx,maxNegX=0;
849            for (j = 0; j < tg.LatLongs.size(); j++)
850            {                
851                POINT2 pt=tg.LatLongs.get(j);
852                if (pt.x < minx)
853                    minx = pt.x;
854                if (pt.x > maxx)
855                    maxx = pt.x;
856                if(maxNegX==0 && pt.x<0)
857                    maxNegX=pt.x;
858                if(maxNegX<0 && pt.x<0 && pt.x>maxNegX)
859                    maxNegX=pt.x;
860                if (pt.y < coordsBottom)
861                    coordsBottom = pt.y;
862                if (pt.y > coordsTop)
863                    coordsTop = pt.y;                
864            }
865            boolean coordSpanIDL = false;
866            if(maxx==180 || minx==-180)
867                coordSpanIDL=true;
868            if(maxx-minx>=180)
869            {
870                coordSpanIDL=true;
871                coordsLeft=maxx;
872                coordsRight=maxNegX;
873            }else
874            {
875                coordsLeft=minx;
876                coordsRight=maxx;
877            }
878            //if(canClipPoints)
879            //{                
880                if(br.y<=coordsBottom && coordsBottom <= tl.y)
881                    intersects=true;
882                else if(coordsBottom<=br.y && br.y <=coordsTop)
883                    intersects=true;
884                else
885                    return false;
886            //}
887            //if it gets this far then the latitude ranges intersect
888            //re-initialize intersects for the longitude ranges
889            intersects=false;
890            //the longitude range
891            //the min and max coords longitude
892            boolean boxSpanIDL = false;
893            //boolean coordSpanIDL = false;
894            if(tl.x==180 || tl.x==-180 || br.x==180 || br.x==-180)
895                boxSpanIDL=true;
896            else if (Math.abs(br.x - tl.x) > 180)
897                boxSpanIDL = true;
898            
899//            if (coordsRight - coordsLeft > 180)
900//            {
901//                double temp = coordsLeft;
902//                coordsLeft = coordsRight;
903//                coordsRight = temp;
904//                coordSpanIDL=true;
905//            }
906            //boolean intersects=false;
907            if(coordSpanIDL && boxSpanIDL)
908                intersects=true;
909            else if(!coordSpanIDL && !boxSpanIDL)   //was && canclipPoints
910            {
911                if(coordsLeft<=tl.x && tl.x<=coordsRight)
912                    intersects=true;
913                if(coordsLeft<=br.x && br.x<=coordsRight)
914                    intersects=true;
915                if(tl.x<=coordsLeft && coordsLeft<=br.x)
916                    intersects=true;
917                if(tl.x<=coordsRight && coordsRight<=br.x)
918                    intersects=true;
919            }
920            else if(!coordSpanIDL && boxSpanIDL)    //box spans IDL and coords do not
921            {   
922                if(tl.x<coordsRight && coordsRight<180)
923                    intersects=true;
924                if(-180<coordsLeft && coordsLeft<br.x)
925                    intersects=true;
926            }
927            else if(coordSpanIDL && !boxSpanIDL)    //coords span IDL and box does not
928            {   
929                if(coordsLeft<br.x && br.x<180)
930                    intersects=true;
931                if(-180<tl.x && tl.x<coordsRight)
932                    intersects=true;
933            }
934            return intersects;
935            
936        }
937        catch (Exception exc) {
938            ErrorLogger.LogException("clsRenderer", "intersectsClipArea",
939                    new RendererException("Failed inside intersectsClipArea", exc));
940        }    
941        return result;
942    }
943
944    /**
945     * Adds Feint, decoy, or dummy indicator to shapes. Does not check if tactical graphic should have indicator
946     */
947    private static void addFDI(TGLight tg, ArrayList<Shape2> shapes) {
948        try {
949            MSInfo msi = MSLookup.getInstance().getMSLInfo(tg.get_SymbolId());
950            final int drawRule = msi != null ? msi.getDrawRule() : -1;
951            final int lineType = tg.get_LineType();
952
953            if (lineType == TacticalLines.MAIN) {
954                // Only Axis of Advance with arrowhead in a different location
955                ArrayList<POINT2> points = shapes.get(1).getPoints();
956                POINT2 ptA = new POINT2(points.get(points.size() - 3));
957                POINT2 ptB = new POINT2(points.get(points.size() - 8));
958                POINT2 ptC = new POINT2(points.get(points.size() - 7));
959                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
960            } else if (drawRule == DrawRules.AXIS1 || drawRule == DrawRules.AXIS2) {
961                // Axis of Advance symbols
962                ArrayList<POINT2> points = shapes.get(0).getPoints();
963                POINT2 ptA = new POINT2(points.get(points.size() / 2 - 1));
964                POINT2 ptB = new POINT2(points.get(points.size() / 2));
965                POINT2 ptC = new POINT2(points.get(points.size() / 2 + 1));
966                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
967            }
968            // Direction of attack symbols
969            else if (lineType == TacticalLines.DIRATKAIR) {
970                ArrayList<POINT2> points = shapes.get(2).getPoints();
971                POINT2 ptA = new POINT2(points.get(0));
972                POINT2 ptB = new POINT2(points.get(1));
973                POINT2 ptC = new POINT2(points.get(2));
974                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
975            } else if (lineType == TacticalLines.DIRATKGND) {
976                ArrayList<POINT2> points = shapes.get(1).getPoints();
977                POINT2 ptA = new POINT2(points.get(7));
978                POINT2 ptB = new POINT2(points.get(4));
979                POINT2 ptC = new POINT2(points.get(9));
980                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
981            } else if (lineType == TacticalLines.DIRATKSPT) {
982                ArrayList<POINT2> points = shapes.get(1).getPoints();
983                POINT2 ptA = new POINT2(points.get(0));
984                POINT2 ptB = new POINT2(points.get(1));
985                POINT2 ptC = new POINT2(points.get(2));
986                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
987            } else {
988                // Shape has no arrow. Put on top of shape
989                POINT2 firstPoint = shapes.get(0).getPoints().get(0);
990                POINT2 ptUl = new POINT2(firstPoint);
991                POINT2 ptUr = new POINT2(firstPoint);
992                POINT2 ptLr = new POINT2(firstPoint);
993                POINT2 ptLl = new POINT2(firstPoint);
994                clsUtility.GetMBR(shapes, ptUl, ptUr, ptLr, ptLl);
995                shapes.add(DISMSupport.getFDIShape(tg, ptUl, ptUr));
996            }
997        } catch (Exception exc) {
998            ErrorLogger.LogException(_className, "addFDI", new RendererException("failed inside addFDI", exc));
999        }
1000    }
1001
1002    /**
1003     * @param mss
1004     * @param converter
1005     * @param clipArea
1006     * @param context
1007     * @deprecated context not used
1008     */
1009    public static void renderWithPolylines(MilStdSymbol mss,
1010            IPointConversion converter,
1011            Object clipArea,
1012            Context context) {
1013        try {
1014            TGLight tg = clsRenderer.createTGLightFromMilStdSymbol(mss, converter);
1015            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1016            ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList();
1017            if (intersectsClipArea(tg, converter, clipArea)) {
1018                render_GE(tg, shapeInfos, modifierShapeInfos, converter, clipArea, context);
1019            }
1020            mss.setSymbolShapes(shapeInfos);
1021            mss.setModifierShapes(modifierShapeInfos);
1022        } catch (Exception exc) {
1023            ErrorLogger.LogException("clsRenderer", "renderWithPolylines",
1024                    new RendererException("Failed inside renderWithPolylines", exc));
1025        }
1026    }
1027
1028    /**
1029     * GoogleEarth renderer uses polylines for rendering
1030     *
1031     * @param mss MilStdSymbol object
1032     * @param converter the geographic to pixels coordinate converter
1033     * @param clipArea the clip bounds
1034     */
1035    public static void renderWithPolylines(MilStdSymbol mss,
1036            IPointConversion converter,
1037            Object clipArea) {
1038        try {
1039            TGLight tg = clsRenderer.createTGLightFromMilStdSymbol(mss, converter);
1040            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1041            ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList();
1042            if (intersectsClipArea(tg, converter, clipArea)) {
1043                render_GE(tg, shapeInfos, modifierShapeInfos, converter, clipArea);
1044            }
1045            mss.setSymbolShapes(shapeInfos);
1046            mss.setModifierShapes(modifierShapeInfos);
1047            mss.set_WasClipped(tg.get_WasClipped());
1048        } catch (Exception exc) {
1049            ErrorLogger.LogException("clsRenderer", "renderWithPolylines",
1050                    new RendererException("Failed inside renderWithPolylines", exc));
1051        }
1052    }
1053
1054    /**
1055     * See render_GE below for comments
1056     *
1057     * @param tg
1058     * @param shapeInfos
1059     * @param modifierShapeInfos
1060     * @param converter
1061     * @param clipArea
1062     * @param context test android-gradle
1063     * @deprecated context not used
1064     */
1065    public static void render_GE(TGLight tg,
1066            ArrayList<ShapeInfo> shapeInfos,
1067            ArrayList<ShapeInfo> modifierShapeInfos,
1068            IPointConversion converter,
1069            Object clipArea,
1070            Context context) //was Rectangle2D
1071    {
1072        render_GE(tg, shapeInfos, modifierShapeInfos, converter, clipArea);
1073    }
1074
1075    /**
1076     * Google Earth renderer: Called by mapfragment-demo This is the public
1077     * interface for Google Earth renderer assumes tg.Pixels is filled assumes
1078     * the caller instantiated the ShapeInfo arrays
1079     *
1080     * @param tg tactical graphic
1081     * @param shapeInfos symbol ShapeInfo array
1082     * @param modifierShapeInfos modifier ShapeInfo array
1083     * @param converter geographic to pixels coordinate converter
1084     * @param clipArea clipping bounds in pixels
1085     */
1086    public static void render_GE(TGLight tg,
1087            ArrayList<ShapeInfo> shapeInfos,
1088            ArrayList<ShapeInfo> modifierShapeInfos,
1089            IPointConversion converter,
1090            Object clipArea) {
1091        try {
1092            reversePointsRevD(tg);
1093
1094            Rectangle2D clipBounds = null;
1095            CELineArray.setClient("ge");
1096//            ArrayList<POINT2> origPixels = null;
1097//            ArrayList<POINT2> origLatLongs = null;
1098//            if (clsUtilityGE.segmentColorsSet(tg)) {
1099//                origPixels=lineutility.getDeepCopy(tg.Pixels);
1100//                origLatLongs=lineutility.getDeepCopy(tg.LatLongs);
1101//            }
1102            ArrayList<POINT2> origFillPixels = lineutility.getDeepCopy(tg.Pixels);
1103
1104            if (tg.get_LineType() == TacticalLines.LC)
1105                armyc2.c5isr.JavaTacticalRenderer.clsUtility.SegmentLCPoints(tg, converter);
1106
1107//            boolean shiftLines = Channels.getShiftLines();
1108//            if (shiftLines) {
1109//                String affiliation = tg.get_Affiliation();
1110//                Channels.setAffiliation(affiliation);
1111//            }
1112            //CELineArray.setMinLength(2.5);    //2-27-2013
1113            ArrayList<Point2D> clipPoints = null;
1114            if (clipArea != null) {
1115                if (clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
1116                    clipBounds = (Rectangle2D.Double) clipArea;
1117                } else if (clipArea.getClass().isAssignableFrom(Rectangle.class)) {
1118                    Rectangle rectx = (Rectangle) clipArea;
1119                    clipBounds = new Rectangle2D.Double(rectx.x, rectx.y, rectx.width, rectx.height);
1120                } else if (clipArea.getClass().isAssignableFrom(ArrayList.class)) {
1121                    clipPoints = (ArrayList<Point2D>) clipArea;
1122                }
1123            }
1124            double zoomFactor = clsUtilityGE.getZoomFactor(clipBounds, clipPoints, tg.Pixels);
1125            //add sub-section to test clipArea if client passes the rectangle
1126            boolean useClipPoints = false;    //currently not used
1127            if (useClipPoints == true && clipBounds != null) {
1128                double x = clipBounds.getMinX();
1129                double y = clipBounds.getMinY();
1130                double width = clipBounds.getWidth();
1131                double height = clipBounds.getHeight();
1132                clipPoints = new ArrayList();
1133                clipPoints.add(new Point2D.Double(x, y));
1134                clipPoints.add(new Point2D.Double(x + width, y));
1135                clipPoints.add(new Point2D.Double(x + width, y + height));
1136                clipPoints.add(new Point2D.Double(x, y + height));
1137                clipPoints.add(new Point2D.Double(x, y));
1138                clipBounds = null;
1139            }
1140            //end section
1141
1142            if (tg.get_Client() == null || tg.get_Client().isEmpty()) {
1143                tg.set_client("ge");
1144            }
1145
1146            clsUtility.RemoveDuplicatePoints(tg);
1147
1148            int linetype = tg.get_LineType();
1149            if (linetype < 0) {
1150                linetype = armyc2.c5isr.JavaTacticalRenderer.clsUtility.GetLinetypeFromString(tg.get_SymbolId());
1151                //clsUtilityCPOF.SegmentGeoPoints(tg, converter);
1152                tg.set_LineType(linetype);
1153            }
1154
1155            Boolean isTextFlipped = false;
1156            ArrayList<Shape2> shapes = null;   //use this to collect all the shapes
1157            clsUtilityGE.setSplineLinetype(tg);
1158
1159            clsUtilityCPOF.SegmentGeoPoints(tg, converter, zoomFactor);
1160            if (clipBounds != null || clipPoints != null) {
1161                if (clsUtilityCPOF.canClipPoints(tg)) {
1162                    //check assignment
1163                    if (clipBounds != null) {
1164                        clsClipPolygon2.ClipPolygon(tg, clipBounds);
1165                    } else if (clipPoints != null) {
1166                        clsClipQuad.ClipPolygon(tg, clipPoints);
1167                    }
1168
1169                    clsUtilityGE.removeTrailingPoints(tg, clipArea);
1170                    tg.LatLongs = clsUtility.PixelsToLatLong(tg.Pixels, converter);
1171                }
1172            }
1173
1174            //if MSR segment data set use original pixels unless tg.Pixels is empty from clipping
1175//            if (origPixels != null) {
1176//                if (tg.Pixels.isEmpty()) {
1177//                    return;
1178//                } else {
1179//                    tg.Pixels = origPixels;
1180//                    tg.LatLongs = origLatLongs;
1181//                    clipArea = null;
1182//                }
1183//            }
1184            armyc2.c5isr.JavaTacticalRenderer.clsUtility.InterpolatePixels(tg);
1185
1186            tg.modifiers = new ArrayList();
1187            BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
1188            Graphics2D g2d = bi.createGraphics();
1189            g2d.setFont(tg.get_Font());
1190            Modifier2.AddModifiersGeo(tg, g2d, clipArea, converter);
1191
1192            clsUtilityCPOF.FilterPoints2(tg, converter);
1193            armyc2.c5isr.JavaTacticalRenderer.clsUtility.FilterVerticalSegments(tg);
1194            clsUtility.FilterAXADPoints(tg, converter);
1195            clsUtilityCPOF.ClearPixelsStyle(tg);
1196
1197            ArrayList<Shape2> linesWithFillShapes = null;
1198
1199            ArrayList<POINT2> savePixels = tg.Pixels;
1200            tg.Pixels = origFillPixels;
1201
1202            //check assignment
1203            if (clipBounds != null) {
1204                linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, clipBounds);
1205            } else if (clipPoints != null) {
1206                linesWithFillShapes = clsClipQuad.LinesWithFill(tg, clipPoints);
1207            } else if (clipArea == null) {
1208                linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, null);
1209            }
1210
1211            tg.Pixels = savePixels;
1212
1213            ArrayList<Shape2> rangeFanFillShapes = null;
1214            //do not fill the original shapes for circular range fans
1215            int savefillStyle = tg.get_FillStyle();
1216            if (linetype == TacticalLines.RANGE_FAN) {
1217                tg.set_Fillstyle(0);
1218            }
1219
1220            //check assignment (pass which clip object is not null)
1221            if (clipBounds != null) {
1222                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds); //takes clip object           
1223            } else if (clipPoints != null) {
1224                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipPoints);
1225            } else if (clipArea == null) {
1226                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, null);
1227            }
1228
1229            // Add Feint, decoy, or dummy indicator
1230            if (shapes != null
1231                    && SymbolID.getSymbolSet(tg.get_SymbolId()) == SymbolID.SymbolSet_ControlMeasure
1232                    && SymbolUtilities.hasFDI(tg.get_SymbolId())) {
1233                addFDI(tg, shapes);
1234            }
1235
1236            switch (linetype) {
1237                case TacticalLines.RANGE_FAN:
1238                case TacticalLines.RANGE_FAN_SECTOR:
1239                case TacticalLines.RADAR_SEARCH:
1240                    if (tg.get_FillColor() == null || tg.get_FillColor().getAlpha() < 2) {
1241                        break;
1242                    }
1243                    TGLight tg1 = clsUtilityCPOF.GetCircularRangeFanFillTG(tg);
1244                    tg1.set_Fillstyle(savefillStyle);
1245                    tg1.set_SymbolId(tg.get_SymbolId());
1246                    //check assignment (pass which clip object is not null)
1247                    if (clipBounds != null) {
1248                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, clipBounds);
1249                    } else if (clipPoints != null) {
1250                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, clipPoints);
1251                    } else if (clipArea == null) {
1252                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, null);
1253                    }
1254
1255                    if (rangeFanFillShapes != null) {
1256                        if (shapes == null) {
1257                            System.out.println("shapes is null");
1258                            break;
1259                        } else {
1260                            shapes.addAll(0, rangeFanFillShapes);
1261                        }
1262
1263                    }
1264                    break;
1265                default:
1266                    clsRenderer2.getAutoshapeFillShape(tg, shapes);
1267                    break;
1268            }
1269            //end section
1270
1271            //undo any fillcolor for lines with fill
1272            clsUtilityCPOF.LinesWithSeparateFill(tg.get_LineType(), shapes);
1273            clsClipPolygon2.addAbatisFill(tg, shapes);
1274
1275            //if this line is commented then the extra line in testbed goes away
1276            if (shapes != null && linesWithFillShapes != null && linesWithFillShapes.size() > 0) {
1277                shapes.addAll(0, linesWithFillShapes);
1278            }
1279
1280            if (clsUtilityCPOF.canClipPoints(tg) == false && clipBounds != null) {
1281                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipBounds);
1282            } else if (clsUtilityCPOF.canClipPoints(tg) == false && clipPoints != null) {
1283                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipPoints);
1284            }
1285            //returns early if textSpecs are null
1286            //currently the client is ignoring these
1287            if (modifierShapeInfos != null) {
1288                ArrayList<Shape2> textSpecs = new ArrayList();
1289                Modifier2.DisplayModifiers2(tg, g2d, textSpecs, isTextFlipped, converter);
1290                Shape2ToShapeInfo(modifierShapeInfos, textSpecs);
1291            }
1292            Shape2ToShapeInfo(shapeInfos, shapes);
1293            clsUtility.addHatchFills(tg, shapeInfos);
1294
1295            //check assignment (pass which clip object is not null)
1296            if (clipBounds != null) {
1297                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipBounds);//takes a clip object            
1298            } else if (clipPoints != null) {
1299                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipPoints);
1300            } else if (clipArea == null) {
1301                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, null);
1302            }
1303        } catch (Exception exc) {
1304            ErrorLogger.LogException(_className, "render_GE",
1305                    new RendererException("Failed inside render_GE", exc));
1306
1307        }
1308    }
1309    /**
1310     * creates a shape for known symbols. The intent is to use client points for
1311     * the shape and is intended for use with ellipse. If hatch &gt; 1 it creates 2 shapes
1312     * one for the hatch pattern, the second one is for the outline.
1313     *
1314     * @param milStd
1315     * @param ipc
1316     * @param clipArea
1317     * @param shapeType
1318     * @param lineColor
1319     * @param fillColor
1320     * @param hatch
1321     */
1322    public static void render_Shape(MilStdSymbol milStd,
1323            IPointConversion ipc,
1324            Object clipArea,
1325            int shapeType,
1326            Color lineColor,
1327            Color fillColor,
1328            int hatch) {
1329        try {
1330            Rectangle2D clipBounds = null;
1331            //CELineArray.setClient("ge");
1332            ArrayList<Point2D> clipPoints = null;
1333
1334            if (clipArea != null) {
1335                if (clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
1336                    clipBounds = (Rectangle2D.Double) clipArea;
1337                } else if (clipArea.getClass().isAssignableFrom(Rectangle.class)) {
1338                    clipBounds = (Rectangle2D) clipArea;
1339                } else if (clipArea.getClass().isAssignableFrom(ArrayList.class)) {
1340                    clipPoints = (ArrayList<Point2D>) clipArea;
1341                }
1342            }
1343            
1344            //can't use following line because it resets the pixels
1345            //TGLight tg = createTGLightFromMilStdSymbol(milStd, ipc);
1346            TGLight tg = new TGLight();
1347            tg.set_SymbolId(milStd.getSymbolID());
1348            //tg.set_VisibleModifiers(true);
1349            //set tg latlongs and pixels
1350            setClientCoords(milStd, tg);
1351            //build tg.Pixels
1352            tg.Pixels = clsUtility.LatLongToPixels(tg.LatLongs, ipc);            
1353            
1354            //int fillStyle = milStd.getPatternFillType();
1355            Shape2 shape = new Shape2(shapeType);
1356            shape.setFillColor(fillColor);
1357            if (lineColor != null) {
1358                shape.setLineColor(lineColor);
1359                shape.setStroke(new BasicStroke(milStd.getLineWidth()));
1360            }
1361            //the client has already set the coordinates for the shape
1362            POINT2 pt;
1363            for (int j = 0; j < tg.Pixels.size(); j++) {
1364                pt = tg.Pixels.get(j);
1365                if (j == 0) {
1366                    shape.moveTo(pt);
1367                } else {
1368                    shape.lineTo(pt);
1369                }
1370            }
1371
1372            //post clip the shape and set the polylines
1373            ArrayList<Shape2> shapes = new ArrayList();
1374            shapes.add(shape);
1375            //post-clip the shape
1376            if (clsUtilityCPOF.canClipPoints(tg) == false && clipBounds != null) {
1377                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipBounds);
1378            } else if (clsUtilityCPOF.canClipPoints(tg) == false && clipPoints != null) {
1379                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipPoints);
1380            }
1381            shape=shapes.get(0);
1382            if (hatch > 1) 
1383            {
1384                shape = clsUtility.buildHatchArea(tg, shape, hatch, 20);
1385                shape.setLineColor(lineColor);
1386                shape.setStroke(new BasicStroke(1));
1387                //shapes.clear();
1388                shapes.add(shape);
1389            }
1390            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1391            Shape2ToShapeInfo(shapeInfos, shapes);
1392            //set the shapeInfo polylines
1393            if (clipBounds != null) {
1394                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipBounds);
1395            } else if (clipPoints != null) {
1396                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipPoints);
1397            } else if (clipArea == null) {
1398                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, null);
1399            }
1400            //set milStd symbol shapes
1401            if (milStd.getSymbolShapes() == null) {
1402                milStd.setSymbolShapes(shapeInfos);
1403            } else {
1404                milStd.getSymbolShapes().addAll(shapeInfos);
1405            }
1406            return;
1407        } catch (Exception exc) {
1408            ErrorLogger.LogException(_className, "render_Shape",
1409                    new RendererException("Failed inside render_Shape", exc));
1410
1411        }
1412    }
1413
1414    /**
1415     * set the clip rectangle as an arraylist or a Rectangle2D depending on the
1416     * object
1417     *
1418     * @param clipBounds
1419     * @param clipRect
1420     * @param clipArray
1421     * @return
1422     */
1423    private static boolean setClip(Object clipBounds, Rectangle2D clipRect, ArrayList<Point2D> clipArray) {
1424        try {
1425            if (clipBounds == null) {
1426                return false;
1427            } else if (clipBounds.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
1428                clipRect.setRect((Rectangle2D) clipBounds);
1429            } else if (clipBounds.getClass().isAssignableFrom(Rectangle2D.class)) {
1430                clipRect.setRect((Rectangle2D) clipBounds);
1431            } else if (clipBounds.getClass().isAssignableFrom(Rectangle.class)) {
1432                //clipRect.setRect((Rectangle2D)clipBounds);
1433                Rectangle rectx = (Rectangle) clipBounds;
1434                //clipBounds=new Rectangle2D.Double(rectx.x,rectx.y,rectx.width,rectx.height);
1435                clipRect.setRect(rectx.x, rectx.y, rectx.width, rectx.height);
1436            } else if (clipBounds.getClass().isAssignableFrom(ArrayList.class)) {
1437                clipArray.addAll((ArrayList) clipBounds);
1438            }
1439        } catch (Exception exc) {
1440            ErrorLogger.LogException(_className, "setClip",
1441                    new RendererException("Failed inside setClip", exc));
1442
1443        }
1444        return true;
1445    }
1446
1447    /**
1448     * public render function transferred from JavaLineArrayCPOF project. Use
1449     * this function to replicate CPOF renderer functionality.
1450     *
1451     * @param mss the milStdSymbol object
1452     * @param converter the geographic to pixels coordinate converter
1453     * @param clipBounds the pixels based clip bounds
1454     */
1455    public static void render(MilStdSymbol mss,
1456            IPointConversion converter,
1457            Object clipBounds) {
1458        try {
1459            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1460            ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList();
1461            render(mss, converter, shapeInfos, modifierShapeInfos, clipBounds);
1462        } catch (Exception exc) {
1463            ErrorLogger.LogException(_className, "render",
1464                    new RendererException("render", exc));
1465
1466        }
1467    }
1468
1469    /**
1470     * Generic tester button says Tiger or use JavaRendererSample. Generic
1471     * renderer testers: called by JavaRendererSample and TestJavaLineArray
1472     * public render function transferred from JavaLineArrayCPOF project. Use
1473     * this function to replicate CPOF renderer functionality.
1474     *
1475     * @param mss
1476     * @param converter geographic to pixels converter
1477     * @param shapeInfos ShapeInfo array
1478     * @param modifierShapeInfos modifier ShapeInfo array
1479     * @param clipBounds clip bounds
1480     */
1481    public static void render(MilStdSymbol mss,
1482            IPointConversion converter,
1483            ArrayList<ShapeInfo> shapeInfos,
1484            ArrayList<ShapeInfo> modifierShapeInfos,
1485            Object clipBounds) {
1486        try {
1487            //boolean shiftLines = Channels.getShiftLines();
1488            //end section
1489
1490            Rectangle2D clipRect = new Rectangle2D.Double();
1491            ArrayList<Point2D> clipArray = new ArrayList();
1492            setClip(clipBounds, clipRect, clipArray);
1493
1494            TGLight tg = createTGLightFromMilStdSymbol(mss, converter);
1495            reversePointsRevD(tg);
1496            CELineArray.setClient("generic");
1497//            if (shiftLines) {
1498//                String affiliation = tg.get_Affiliation();
1499//                Channels.setAffiliation(affiliation);
1500//            }
1501            //CELineArray.setMinLength(2.5);    //2-27-2013
1502
1503            int linetype = tg.get_LineType();
1504            //replace calls to MovePixels
1505            clsUtility.RemoveDuplicatePoints(tg);
1506
1507            BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
1508            Graphics2D g2d = bi.createGraphics();
1509            g2d.setFont(tg.get_Font());
1510
1511            clsUtilityCPOF.SegmentGeoPoints(tg, converter, 1);
1512            clsUtility.FilterAXADPoints(tg, converter);
1513
1514            //prevent vertical segments for oneway, twoway, alt
1515            armyc2.c5isr.JavaTacticalRenderer.clsUtility.FilterVerticalSegments(tg);
1516            boolean isChange1Area = armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(linetype);
1517            boolean isTextFlipped = false;
1518            //for 3d change 1 symbols we do not transform the points
1519
1520            //if it is world view then we want to flip the far points about
1521            //the left and right sides to get two symbols
1522            ArrayList<POINT2> farLeftPixels = new ArrayList();
1523            ArrayList<POINT2> farRightPixels = new ArrayList();
1524            if (isChange1Area == false) {
1525                clsUtilityCPOF.GetFarPixels(tg, converter, farLeftPixels, farRightPixels);
1526            }
1527
1528            ArrayList<Shape2> shapesLeft = new ArrayList();
1529            ArrayList<Shape2> shapesRight = new ArrayList();
1530            ArrayList<Shape2> shapes = null;   //use this to collect all the shapes
1531
1532            //CPOF 6.0 diagnostic
1533            ArrayList<Shape2> textSpecsLeft = null;
1534            ArrayList<Shape2> textSpecsRight = null;
1535            //Note: DisplayModifiers3 returns early if textSpecs are null
1536            textSpecsLeft = new ArrayList();
1537            textSpecsRight = new ArrayList();
1538
1539            if (farLeftPixels.size() > 0) {
1540                tg.Pixels = farLeftPixels;
1541                shapesLeft = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds);
1542                //CPOF 6.0
1543                //returns early if textSpecs are null
1544                Modifier2.DisplayModifiers2(tg, g2d, textSpecsLeft, isTextFlipped, null);
1545            }
1546            if (farRightPixels.size() > 0) {
1547                tg.Pixels = farRightPixels;
1548                shapesRight = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds);
1549                //CPOF 6.0
1550                //returns early if textSpecs are null
1551                Modifier2.DisplayModifiers2(tg, g2d, textSpecsRight, isTextFlipped, null);
1552            }
1553
1554            //CPOF 6.0 diagnostic
1555            ArrayList<Shape2> textSpecs = new ArrayList();
1556
1557            if (shapesLeft.isEmpty() || shapesRight.isEmpty()) {
1558                ArrayList<Shape2> linesWithFillShapes = null;
1559                if (clipArray != null && !clipArray.isEmpty()) {
1560                    linesWithFillShapes = clsClipQuad.LinesWithFill(tg, clipArray);
1561                } else if (clipRect != null && clipRect.getWidth() != 0) {
1562                    linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, clipRect);
1563                } else {
1564                    linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, null);
1565                }
1566
1567                //diagnostic: comment two lines if using the WW tester
1568                if (clsUtilityCPOF.canClipPoints(tg) && clipBounds != null) {
1569                    if (clipArray != null && !clipArray.isEmpty()) {
1570                        clsClipQuad.ClipPolygon(tg, clipArray);
1571                    } else if (clipRect != null && clipRect.getWidth() != 0) {
1572                        clsClipPolygon2.ClipPolygon(tg, clipRect);
1573                    }
1574
1575                    tg.LatLongs = clsUtility.PixelsToLatLong(tg.Pixels, converter);
1576                }
1577
1578                //diagnostic 1-28-13
1579                armyc2.c5isr.JavaTacticalRenderer.clsUtility.InterpolatePixels(tg);
1580
1581                tg.modifiers = new ArrayList();
1582                Modifier2.AddModifiersGeo(tg, g2d, clipBounds, converter);
1583
1584                clsUtilityCPOF.FilterPoints2(tg, converter);
1585                clsUtilityCPOF.ClearPixelsStyle(tg);
1586                //add section to replace preceding line M. Deutch 11-4-2011
1587                ArrayList rangeFanFillShapes = null;
1588                //do not fill the original shapes for circular range fans
1589                int savefillStyle = tg.get_FillStyle();
1590                if (linetype == TacticalLines.RANGE_FAN) {
1591                    tg.set_Fillstyle(0);
1592                }
1593
1594                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds);
1595
1596                // Add Feint, decoy, or dummy indicator
1597                if (shapes != null
1598                        && SymbolID.getSymbolSet(tg.get_SymbolId()) == SymbolID.SymbolSet_ControlMeasure
1599                        && SymbolUtilities.hasFDI(tg.get_SymbolId())) {
1600                    addFDI(tg, shapes);
1601                }
1602
1603                switch (linetype) {
1604                    case TacticalLines.RANGE_FAN:
1605                    case TacticalLines.RANGE_FAN_SECTOR:
1606                    case TacticalLines.RADAR_SEARCH:
1607                        if (tg.get_FillColor() == null || tg.get_FillColor().getAlpha() < 2) {
1608                            break;
1609                        }
1610                        TGLight tg1 = clsUtilityCPOF.GetCircularRangeFanFillTG(tg);
1611                        tg1.set_Fillstyle(savefillStyle);
1612                        tg1.set_SymbolId(tg.get_SymbolId());
1613                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, clipBounds);
1614
1615                        if (rangeFanFillShapes != null) {
1616                            shapes.addAll(0, rangeFanFillShapes);
1617                        }
1618                        break;
1619                    default:
1620                        break;
1621                }
1622
1623                //undo any fillcolor for lines with fill
1624                clsUtilityCPOF.LinesWithSeparateFill(tg.get_LineType(), shapes);
1625                clsClipPolygon2.addAbatisFill(tg, shapes);
1626
1627                //if this line is commented then the extra line in testbed goes away
1628                if (shapes != null && linesWithFillShapes != null && linesWithFillShapes.size() > 0) {
1629                    shapes.addAll(0, linesWithFillShapes);
1630                }
1631
1632                if (shapes != null && shapes.size() > 0) {
1633                    Modifier2.DisplayModifiers2(tg, g2d, textSpecs, isTextFlipped, null);
1634                    Shape2ToShapeInfo(modifierShapeInfos, textSpecs);
1635                    mss.setModifierShapes(modifierShapeInfos);
1636                }
1637            } else //symbol was more than 180 degrees wide, use left and right symbols
1638            {
1639                shapes = shapesLeft;
1640                shapes.addAll(shapesRight);
1641
1642                if (textSpecs != null) {
1643                    textSpecs.addAll(textSpecsLeft);
1644                    textSpecs.addAll(textSpecsRight);
1645                }
1646            }
1647            //post-clip the points if the tg could not be pre-clipped
1648            if (clsUtilityCPOF.canClipPoints(tg) == false && clipBounds != null) {
1649                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipBounds);
1650            }
1651
1652            Shape2ToShapeInfo(shapeInfos, shapes);
1653            clsUtility.addHatchFills(tg, shapeInfos);
1654            mss.setSymbolShapes(shapeInfos);
1655        } catch (Exception exc) {
1656            ErrorLogger.LogException(_className, "render",
1657                    new RendererException("Failed inside render", exc));
1658
1659        }
1660    }
1661
1662    public static int getCMLineType(int version, int entityCode) {
1663        // Check if line type is specific to a version
1664        if (version == SymbolID.Version_2525E){
1665            switch (entityCode) {
1666                // Added in 2525E
1667                case 110400:
1668                    return TacticalLines.GENERIC_LINE;
1669                case 120700:
1670                    return TacticalLines.GENERIC_AREA;
1671                case 141800:
1672                    return TacticalLines.HOL;
1673                case 141900:
1674                    return TacticalLines.BHL;
1675                case 310800:
1676                    return TacticalLines.CSA;
1677                case 330500:
1678                    return TacticalLines.ROUTE;
1679                case 330501:
1680                    return TacticalLines.ROUTE_ONEWAY;
1681                case 330502:
1682                    return TacticalLines.ROUTE_ALT;
1683                case 344100:
1684                    return TacticalLines.FPOL;
1685                case 344200:
1686                    return TacticalLines.RPOL;
1687                // Updated in 2525E
1688                case 120500:
1689                    return TacticalLines.BASE_CAMP;
1690                case 120600:
1691                    return TacticalLines.GUERILLA_BASE;
1692                case 151000:
1693                    return TacticalLines.FORT;
1694                case 260400:
1695                    return TacticalLines.BCL;
1696                case 310100:
1697                    return TacticalLines.DHA;
1698            }
1699        } else { // 2525Dchange 1 and older
1700            switch (entityCode) {
1701                // Updated in 2525E
1702                case 120500:
1703                    return TacticalLines.BASE_CAMP_REVD;
1704                case 120600:
1705                    return TacticalLines.GUERILLA_BASE_REVD;
1706                case 151000:
1707                    return TacticalLines.FORT_REVD;
1708                case 260400:
1709                    return TacticalLines.BCL_REVD;
1710                case 310100:
1711                    return TacticalLines.DHA_REVD;
1712                    // Removed in 2525E
1713                case 150300:
1714                    return TacticalLines.ASSY;
1715                case 241601:
1716                    return TacticalLines.SENSOR;
1717                case 241602:
1718                    return TacticalLines.SENSOR_RECTANGULAR;
1719                case 241603:
1720                    return TacticalLines.SENSOR_CIRCULAR;
1721            }
1722        }
1723        // Line type isn't specific to a version or doesn't exist
1724        switch (entityCode) {
1725            case 200101:
1726                return TacticalLines.LAUNCH_AREA;
1727            case 200201:
1728                return TacticalLines.DEFENDED_AREA_CIRCULAR;
1729            case 200202:
1730                return TacticalLines.DEFENDED_AREA_RECTANGULAR;
1731            case 120100:
1732                return TacticalLines.AO;
1733            case 120200:
1734                return TacticalLines.NAI;
1735            case 120300:
1736                return TacticalLines.TAI;
1737            case 120400:
1738                return TacticalLines.AIRFIELD;
1739            case 151401:
1740                return TacticalLines.AIRAOA;
1741            case 151402:
1742                return TacticalLines.AAAAA;
1743            case 151403:
1744                return TacticalLines.MAIN;
1745            case 151404:
1746                return TacticalLines.SPT;
1747            case 110100:
1748                return TacticalLines.BOUNDARY;
1749            case 110200:
1750                return TacticalLines.LL;
1751            case 110300:
1752                return TacticalLines.EWL;
1753            case 140100:
1754                return TacticalLines.FLOT;
1755            case 140200:
1756                return TacticalLines.LC;
1757            case 140300:
1758                return TacticalLines.PL;
1759            case 140400:
1760                return TacticalLines.FEBA;
1761            case 140500:
1762                return TacticalLines.PDF;
1763            case 140601:
1764                return TacticalLines.DIRATKAIR;
1765            case 140602:
1766                return TacticalLines.DIRATKGND;
1767            case 140603:
1768                return TacticalLines.DIRATKSPT;
1769            case 140700:
1770                return TacticalLines.FCL;
1771            case 140800:
1772                return TacticalLines.IL;
1773            case 140900:
1774                return TacticalLines.LOA;
1775            case 141000:
1776                return TacticalLines.LOD;
1777            case 141100:
1778                return TacticalLines.LDLC;
1779            case 141200:
1780                return TacticalLines.PLD;
1781            case 150200:
1782                return TacticalLines.ASSY;
1783            case 150100:
1784                return TacticalLines.GENERAL;
1785            case 150501:
1786                return TacticalLines.JTAA;
1787            case 150502:
1788                return TacticalLines.SAA;
1789            case 150503:
1790                return TacticalLines.SGAA;
1791            case 150600:    //dz no eny
1792                return TacticalLines.DZ;
1793            case 150700:    //ez no eny
1794                return TacticalLines.EZ;
1795            case 150800:    //lz no eny
1796                return TacticalLines.LZ;
1797            case 150900:    //pz no eny
1798                return TacticalLines.PZ;
1799            case 151100:
1800                return TacticalLines.LAA;
1801            case 151200:
1802                return TacticalLines.BATTLE;
1803            case 151202:
1804                return TacticalLines.PNO;
1805            case 151204:
1806                return TacticalLines.CONTAIN;
1807            case 151205:
1808                return TacticalLines.RETAIN;
1809            case 151300:
1810                return TacticalLines.EA;
1811            case 151203:
1812                return TacticalLines.STRONG;
1813            case 151500:
1814                return TacticalLines.ASSAULT;
1815            case 151600:
1816                return TacticalLines.ATKPOS;
1817            case 151700:
1818                return TacticalLines.OBJ;
1819            case 151800:
1820                return TacticalLines.ENCIRCLE;
1821            case 151900:
1822                return TacticalLines.PEN;
1823            case 152000:
1824                return TacticalLines.ATKBYFIRE;
1825            case 152100:
1826                return TacticalLines.SPTBYFIRE;
1827            case 152200:
1828                return TacticalLines.SARA;
1829            case 141300:
1830                return TacticalLines.AIRHEAD;
1831            case 141400:
1832                return TacticalLines.BRDGHD;
1833            case 141500:
1834                return TacticalLines.HOLD;
1835            case 141600:
1836                return TacticalLines.RELEASE;
1837            case 141700:
1838                return TacticalLines.AMBUSH;
1839            case 170100:
1840                return TacticalLines.AC;
1841            case 170200:
1842                return TacticalLines.LLTR;
1843            case 170300:
1844                return TacticalLines.MRR;
1845            case 170400:
1846                return TacticalLines.SL;
1847            case 170500:
1848                return TacticalLines.SAAFR;
1849            case 170600:
1850                return TacticalLines.TC;
1851            case 170700:
1852                return TacticalLines.SC;
1853            case 170800:
1854                return TacticalLines.BDZ;
1855            case 170900:
1856                return TacticalLines.HIDACZ;
1857            case 171000:
1858                return TacticalLines.ROZ;
1859            case 171100:
1860                return TacticalLines.AARROZ;
1861            case 171200:
1862                return TacticalLines.UAROZ;
1863            case 171300:
1864                return TacticalLines.WEZ;
1865            case 171400:
1866                return TacticalLines.FEZ;
1867            case 171500:
1868                return TacticalLines.JEZ;
1869            case 171600:
1870                return TacticalLines.MEZ;
1871            case 171700:
1872                return TacticalLines.LOMEZ;
1873            case 171800:
1874                return TacticalLines.HIMEZ;
1875            case 171900:
1876                return TacticalLines.FAADZ;
1877            case 172000:
1878                return TacticalLines.WFZ;
1879            case 200401:
1880                return TacticalLines.SHIP_AOI_CIRCULAR;
1881            case 240804:
1882                return TacticalLines.RECTANGULAR_TARGET;
1883            case 220100:
1884                return TacticalLines.BEARING;
1885            case 220101:
1886                return TacticalLines.ELECTRO;
1887            case 220102:    //EW                //new label
1888                return TacticalLines.BEARING_EW;
1889            case 220103:
1890                return TacticalLines.ACOUSTIC;
1891            case 220104:
1892                return TacticalLines.ACOUSTIC_AMB;
1893            case 220105:
1894                return TacticalLines.TORPEDO;
1895            case 220106:
1896                return TacticalLines.OPTICAL;
1897            case 218400:
1898                return TacticalLines.NAVIGATION;
1899            case 220107:    //Jammer                //new label
1900                return TacticalLines.BEARING_J;
1901            case 220108:    //RDF                   //new label
1902                return TacticalLines.BEARING_RDF;
1903            case 240101:
1904                return TacticalLines.ACA;
1905            case 240102:
1906                return TacticalLines.ACA_RECTANGULAR;
1907            case 240103:
1908                return TacticalLines.ACA_CIRCULAR;
1909
1910            case 240201:
1911                return TacticalLines.FFA;
1912            case 240202:
1913                return TacticalLines.FFA_RECTANGULAR;
1914            case 240203:
1915                return TacticalLines.FFA_CIRCULAR;
1916
1917            case 240301:
1918                return TacticalLines.NFA;
1919            case 240302:
1920                return TacticalLines.NFA_RECTANGULAR;
1921            case 240303:
1922                return TacticalLines.NFA_CIRCULAR;
1923
1924            case 240401:
1925                return TacticalLines.RFA;
1926            case 240402:
1927                return TacticalLines.RFA_RECTANGULAR;
1928            case 240403:
1929                return TacticalLines.RFA_CIRCULAR;
1930            case 240503:
1931                return TacticalLines.PAA;
1932            case 240501:
1933                return TacticalLines.PAA_RECTANGULAR;
1934            case 240502:
1935                return TacticalLines.PAA_CIRCULAR;
1936            case 260100:
1937                return TacticalLines.FSCL;
1938            case 300100:
1939                return TacticalLines.ICL;
1940            case 190100:
1941                return TacticalLines.IFF_OFF;
1942            case 190200:
1943                return TacticalLines.IFF_ON;
1944            case 260200:
1945                return TacticalLines.CFL;
1946            case 260300:
1947                return TacticalLines.NFL;
1948            case 260500:
1949                return TacticalLines.RFL;
1950            case 260600:
1951                return TacticalLines.MFP;
1952            case 240701:
1953                return TacticalLines.LINTGT;
1954            case 240702:
1955                return TacticalLines.LINTGTS;
1956            case 240703:
1957                return TacticalLines.FPF;
1958            case 240801:
1959                return TacticalLines.AT;
1960            case 240802:
1961                return TacticalLines.RECTANGULAR;
1962            case 240803:
1963                return TacticalLines.CIRCULAR;
1964            case 240805:
1965                return TacticalLines.SERIES;
1966            case 240806:
1967                return TacticalLines.SMOKE;
1968            case 240808:
1969                return TacticalLines.BOMB;
1970            case 241001:
1971                return TacticalLines.FSA;
1972            case 241002:
1973                return TacticalLines.FSA_RECTANGULAR;
1974            case 200402:
1975                return TacticalLines.SHIP_AOI_RECTANGULAR;
1976            case 200600:
1977                return TacticalLines.CUED_ACQUISITION;
1978            case 200700:
1979                return TacticalLines.RADAR_SEARCH;
1980            case 241003:
1981                return TacticalLines.FSA_CIRCULAR;
1982            case 200300:
1983                return TacticalLines.NOTACK;
1984            case 241101:
1985                return TacticalLines.ATI;
1986            case 241102:
1987                return TacticalLines.ATI_RECTANGULAR;
1988            case 241103:
1989                return TacticalLines.ATI_CIRCULAR;
1990            case 241201:
1991                return TacticalLines.CFFZ;
1992            case 241202:
1993                return TacticalLines.CFFZ_RECTANGULAR;
1994            case 241203:
1995                return TacticalLines.CFFZ_CIRCULAR;
1996            case 241301:
1997                return TacticalLines.CENSOR;
1998            case 241302:
1999                return TacticalLines.CENSOR_RECTANGULAR;
2000            case 241303:
2001                return TacticalLines.CENSOR_CIRCULAR;
2002            case 241401:
2003                return TacticalLines.CFZ;
2004            case 241402:
2005                return TacticalLines.CFZ_RECTANGULAR;
2006            case 241403:
2007                return TacticalLines.CFZ_CIRCULAR;
2008            case 241501:
2009                return TacticalLines.DA;
2010            case 241502:
2011                return TacticalLines.DA_RECTANGULAR;
2012            case 241503:
2013                return TacticalLines.DA_CIRCULAR;
2014            case 241701:
2015                return TacticalLines.TBA;
2016            case 241702:
2017                return TacticalLines.TBA_RECTANGULAR;
2018            case 241703:
2019                return TacticalLines.TBA_CIRCULAR;
2020            case 241801:
2021                return TacticalLines.TVAR;
2022            case 241802:
2023                return TacticalLines.TVAR_RECTANGULAR;
2024            case 241803:
2025                return TacticalLines.TVAR_CIRCULAR;
2026            case 241901:
2027                return TacticalLines.ZOR;
2028            case 241902:
2029                return TacticalLines.ZOR_RECTANGULAR;
2030            case 241903:
2031                return TacticalLines.ZOR_CIRCULAR;
2032            case 242000:
2033                return TacticalLines.TGMF;
2034            case 242100:
2035                return TacticalLines.RANGE_FAN;
2036            case 242200:
2037                return TacticalLines.RANGE_FAN_SECTOR;
2038            case 242301:
2039                return TacticalLines.KILLBOXBLUE;
2040            case 242302:
2041                return TacticalLines.KILLBOXBLUE_RECTANGULAR;
2042            case 242303:
2043                return TacticalLines.KILLBOXBLUE_CIRCULAR;
2044            case 242304:
2045                return TacticalLines.KILLBOXPURPLE;
2046            case 242305:
2047                return TacticalLines.KILLBOXPURPLE_RECTANGULAR;
2048            case 242306:
2049                return TacticalLines.KILLBOXPURPLE_CIRCULAR;
2050            case 270100:
2051            case 270200:
2052                return TacticalLines.ZONE;
2053            case 270300:
2054                return TacticalLines.OBSFAREA;
2055            case 270400:
2056                return TacticalLines.OBSAREA;
2057            case 270501:
2058                return TacticalLines.MNFLDBLK;
2059            case 270502:
2060                return TacticalLines.MNFLDDIS;
2061            case 270503:
2062                return TacticalLines.MNFLDFIX;
2063            case 270504:
2064                return TacticalLines.TURN;
2065            case 270601:
2066                return TacticalLines.EASY;
2067            case 270602:
2068                return TacticalLines.BYDIF;
2069            case 270603:
2070                return TacticalLines.BYIMP;
2071            case 271100:
2072                return TacticalLines.GAP;
2073            case 271201:
2074                return TacticalLines.PLANNED;
2075            case 271202:
2076                return TacticalLines.ESR1;
2077            case 271203:
2078                return TacticalLines.ESR2;
2079            case 271204:
2080                return TacticalLines.ROADBLK;
2081            case 280100:
2082                return TacticalLines.ABATIS;
2083            case 290100:
2084                return TacticalLines.LINE;
2085            case 290201:
2086                return TacticalLines.ATDITCH;
2087            case 290202:
2088                return TacticalLines.ATDITCHC;
2089            case 290203:
2090                return TacticalLines.ATDITCHM;
2091            case 290204:
2092                return TacticalLines.ATWALL;
2093            case 290301:
2094                return TacticalLines.UNSP;
2095            case 290302:
2096                return TacticalLines.SFENCE;
2097            case 290303:
2098                return TacticalLines.DFENCE;
2099            case 290304:
2100                return TacticalLines.DOUBLEA;
2101            case 290305:
2102                return TacticalLines.LWFENCE;
2103            case 290306:
2104                return TacticalLines.HWFENCE;
2105            case 290307:
2106                return TacticalLines.SINGLEC;
2107            case 290308:
2108                return TacticalLines.DOUBLEC;
2109            case 290309:
2110                return TacticalLines.TRIPLE;
2111            case 290600:
2112                return TacticalLines.MFLANE;
2113            case 270707:
2114                return TacticalLines.DEPICT;
2115            case 270800:
2116                return TacticalLines.MINED;
2117            case 270801:
2118                return TacticalLines.FENCED;
2119            case 290101:
2120                return TacticalLines.MINE_LINE;
2121            case 271000:
2122                return TacticalLines.UXO;
2123            case 271700:
2124                return TacticalLines.BIO;
2125            case 271800:
2126                return TacticalLines.CHEM;
2127            case 271900:
2128                return TacticalLines.NUC;
2129            case 272000:
2130                return TacticalLines.RAD;
2131            case 290400:
2132                return TacticalLines.CLUSTER;
2133            case 290500:
2134                return TacticalLines.TRIP;
2135            case 282003:
2136                return TacticalLines.OVERHEAD_WIRE;
2137            case 271300:
2138                return TacticalLines.ASLTXING;
2139            case 271500:
2140                return TacticalLines.FORDSITE;
2141            case 271600:
2142                return TacticalLines.FORDIF;
2143            case 290700:
2144                return TacticalLines.FERRY;
2145            case 290800:
2146                return TacticalLines.RAFT;
2147            case 290900:
2148                return TacticalLines.FORTL;
2149            case 291000:
2150                return TacticalLines.FOXHOLE;
2151            case 272100:
2152                return TacticalLines.MSDZ;
2153            case 272200:
2154                return TacticalLines.DRCL;
2155
2156            case 310200:
2157                return TacticalLines.EPW;
2158            case 310300:
2159                return TacticalLines.FARP;
2160            case 310400:
2161                return TacticalLines.RHA;
2162            case 310500:
2163                return TacticalLines.RSA;
2164            case 310600:
2165                return TacticalLines.BSA;
2166            case 310700:
2167                return TacticalLines.DSA;
2168            case 330100:
2169                return TacticalLines.CONVOY;
2170            case 330200:
2171                return TacticalLines.HCONVOY;
2172            case 330300:
2173                return TacticalLines.MSR;
2174            case 330301:
2175                return TacticalLines.MSR_ONEWAY;
2176            case 330401:
2177                return TacticalLines.ASR_ONEWAY;
2178            case 330302:
2179                return TacticalLines.MSR_TWOWAY;
2180            case 330402:
2181                return TacticalLines.ASR_TWOWAY;
2182            case 330303:
2183                return TacticalLines.MSR_ALT;
2184            case 330403:
2185                return TacticalLines.ASR_ALT;
2186
2187            case 330400:
2188                return TacticalLines.ASR;
2189
2190            case 340100:
2191                return TacticalLines.BLOCK;
2192            case 340200:
2193                return TacticalLines.BREACH;
2194            case 340300:
2195                return TacticalLines.BYPASS;
2196            case 340400:
2197                return TacticalLines.CANALIZE;
2198            case 340500:
2199                return TacticalLines.CLEAR;
2200            case 340600:
2201                return TacticalLines.CATK;
2202            case 340700:
2203                return TacticalLines.CATKBYFIRE;
2204
2205            case 340800:
2206                return TacticalLines.DELAY;
2207            case 341000:
2208                return TacticalLines.DISRUPT;
2209            case 341100:
2210                return TacticalLines.FIX;
2211            case 341200:
2212                return TacticalLines.FOLLA;
2213            case 341300:
2214                return TacticalLines.FOLSP;
2215            case 341500:
2216                return TacticalLines.ISOLATE;
2217            case 341700:
2218                return TacticalLines.OCCUPY;
2219            case 341800:
2220                return TacticalLines.PENETRATE;
2221            case 341900:
2222                return TacticalLines.RIP;
2223            case 342000:
2224                return TacticalLines.RETIRE;
2225            case 342100:
2226                return TacticalLines.SECURE;
2227            case 342201:
2228                return TacticalLines.COVER;
2229            case 342202:
2230                return TacticalLines.GUARD;
2231            case 342203:
2232                return TacticalLines.SCREEN;
2233            case 342300:
2234                return TacticalLines.SEIZE;
2235            case 342400:
2236                return TacticalLines.WITHDRAW;
2237            case 342500:
2238                return TacticalLines.WDRAWUP;
2239            case 342600:
2240                return TacticalLines.CORDONKNOCK;
2241            case 342700:
2242                return TacticalLines.CORDONSEARCH;
2243            case 272101:
2244                return TacticalLines.STRIKWARN;
2245            default:
2246                break;
2247        }
2248        return -1;
2249    }
2250
2251    /**
2252     * Some symbol's points are reversed when moving from 2525C to 2525D. This method should be called at the start of each render.
2253     *
2254     * It's a simpler fix to reverse the points order at start than to reverse order when rendering.
2255     *
2256     * Note: Make sure to only call once to not reverse reversed points
2257     * @param tg
2258     */
2259    private static void reversePointsRevD(TGLight tg) {
2260        try {
2261            if (tg.get_SymbolId().length() < 20 || SymbolID.getSymbolSet(tg.get_SymbolId()) != 25) {
2262                return;
2263            }
2264            switch (tg.get_LineType()) {
2265                case TacticalLines.UNSP:
2266                case TacticalLines.LWFENCE:
2267                case TacticalLines.HWFENCE:
2268                case TacticalLines.SINGLEC:
2269                case TacticalLines.DOUBLEC:
2270                case TacticalLines.TRIPLE:
2271                case TacticalLines.LINE:
2272                    if (tg.Pixels != null) {
2273                        Collections.reverse(tg.Pixels);
2274                    }
2275                    if (tg.LatLongs != null) {
2276                        Collections.reverse(tg.LatLongs);
2277                    }
2278                    break;
2279                case TacticalLines.CLUSTER:
2280                    if (SymbolID.getVersion(tg.get_SymbolId()) < SymbolID.Version_2525E) {
2281                        if (tg.Pixels != null) {
2282                            Collections.reverse(tg.Pixels);
2283                        }
2284                        if (tg.LatLongs != null) {
2285                            Collections.reverse(tg.LatLongs);
2286                        }
2287                    }
2288                    break;
2289                default:
2290                    break;
2291            }
2292        } catch (Exception exc) {
2293            ErrorLogger.LogException("clsRenderer", "reversePointsRevD",
2294                    new RendererException("Failed inside reversePointsRevD", exc));
2295        }
2296    }
2297}