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