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