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