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                ArrayList<POINT2> points = shapes.get(0).getPoints();
1430                POINT2 ptA = new POINT2(points.get(points.size() / 2 - 1));
1431                POINT2 ptB = new POINT2(points.get(points.size() / 2));
1432                POINT2 ptC = new POINT2(points.get(points.size() / 2 + 1));
1433                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
1434            }
1435            // Direction of attack symbols
1436            else if (lineType == TacticalLines.DIRATKAIR) {
1437                ArrayList<POINT2> points = shapes.get(2).getPoints();
1438                POINT2 ptA = new POINT2(points.get(0));
1439                POINT2 ptB = new POINT2(points.get(1));
1440                POINT2 ptC = new POINT2(points.get(2));
1441                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
1442            } else if (lineType == TacticalLines.DIRATKGND) {
1443                ArrayList<POINT2> points = shapes.get(1).getPoints();
1444                POINT2 ptA = new POINT2(points.get(7));
1445                POINT2 ptB = new POINT2(points.get(4));
1446                POINT2 ptC = new POINT2(points.get(9));
1447                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
1448            } else if (lineType == TacticalLines.DIRATKSPT  || lineType == TacticalLines.EXFILTRATION || lineType == TacticalLines.INFILTRATION) {
1449                ArrayList<POINT2> points = shapes.get(1).getPoints();
1450                POINT2 ptA = new POINT2(points.get(0));
1451                POINT2 ptB = new POINT2(points.get(1));
1452                POINT2 ptC = new POINT2(points.get(2));
1453                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
1454            }
1455            else if (lineType == TacticalLines.EXPLOIT) {
1456                ArrayList<POINT2> points = shapes.get(1).getPoints();
1457                POINT2 ptA = new POINT2(points.get(0));
1458                POINT2 ptB = new POINT2(points.get(1));
1459                POINT2 ptC = new POINT2(points.get(2));
1460                shapes.add(DISMSupport.getFDIShape(tg, ptA, ptB, ptC));
1461            }
1462            else {
1463                // Shape has no arrow. Put on top of shape
1464                POINT2 firstPoint = shapes.get(0).getPoints().get(0);
1465                POINT2 ptUl = new POINT2(firstPoint);
1466                POINT2 ptUr = new POINT2(firstPoint);
1467                POINT2 ptLr = new POINT2(firstPoint);
1468                POINT2 ptLl = new POINT2(firstPoint);
1469                clsUtility.GetMBR(shapes, ptUl, ptUr, ptLr, ptLl);
1470                shapes.add(DISMSupport.getFDIShape(tg, ptUl, ptUr));
1471            }
1472        } catch (Exception exc) {
1473            ErrorLogger.LogException(_className, "addFDI", new RendererException("failed inside addFDI", exc));
1474        }
1475    }
1476
1477    /**
1478     * @param mss
1479     * @param converter
1480     * @param clipArea
1481     * @param context
1482     * @deprecated context not used
1483     */
1484    public static void renderWithPolylines(MilStdSymbol mss,
1485            IPointConversion converter,
1486            Object clipArea,
1487            Context context) {
1488        try {
1489            TGLight tg = clsRenderer.createTGLightFromMilStdSymbol(mss, converter);
1490            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1491            ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList();
1492            if (intersectsClipArea(tg, converter, clipArea)) {
1493                render_GE(tg, shapeInfos, modifierShapeInfos, converter, clipArea, context);
1494            }
1495            mss.setSymbolShapes(shapeInfos);
1496            mss.setModifierShapes(modifierShapeInfos);
1497        } catch (Exception exc) {
1498            ErrorLogger.LogException("clsRenderer", "renderWithPolylines",
1499                    new RendererException("Failed inside renderWithPolylines", exc));
1500        }
1501    }
1502
1503    /**
1504     * GoogleEarth renderer uses polylines for rendering
1505     *
1506     * @param mss MilStdSymbol object
1507     * @param converter the geographic to pixels coordinate converter
1508     * @param clipArea the clip bounds
1509     */
1510    public static void renderWithPolylines(MilStdSymbol mss,
1511            IPointConversion converter,
1512            Object clipArea) {
1513        try {
1514            TGLight tg = clsRenderer.createTGLightFromMilStdSymbol(mss, converter);
1515            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1516            ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList();
1517            if (intersectsClipArea(tg, converter, clipArea)) {
1518                render_GE(tg, shapeInfos, modifierShapeInfos, converter, clipArea);
1519            }
1520            mss.setSymbolShapes(shapeInfos);
1521            mss.setModifierShapes(modifierShapeInfos);
1522            mss.set_WasClipped(tg.get_WasClipped());
1523        } catch (Exception exc) {
1524            ErrorLogger.LogException("clsRenderer", "renderWithPolylines",
1525                    new RendererException("Failed inside renderWithPolylines", exc));
1526        }
1527    }
1528
1529    /**
1530     * See render_GE below for comments
1531     *
1532     * @param tg
1533     * @param shapeInfos
1534     * @param modifierShapeInfos
1535     * @param converter
1536     * @param clipArea
1537     * @param context test android-gradle
1538     * @deprecated context not used
1539     */
1540    public static void render_GE(TGLight tg,
1541            ArrayList<ShapeInfo> shapeInfos,
1542            ArrayList<ShapeInfo> modifierShapeInfos,
1543            IPointConversion converter,
1544            Object clipArea,
1545            Context context) //was Rectangle2D
1546    {
1547        render_GE(tg, shapeInfos, modifierShapeInfos, converter, clipArea);
1548    }
1549
1550    /**
1551     * Google Earth renderer: Called by mapfragment-demo This is the public
1552     * interface for Google Earth renderer assumes tg.Pixels is filled assumes
1553     * the caller instantiated the ShapeInfo arrays
1554     *
1555     * @param tg tactical graphic
1556     * @param shapeInfos symbol ShapeInfo array
1557     * @param modifierShapeInfos modifier ShapeInfo array
1558     * @param converter geographic to pixels coordinate converter
1559     * @param clipArea clipping bounds in pixels
1560     */
1561    public static void render_GE(TGLight tg,
1562            ArrayList<ShapeInfo> shapeInfos,
1563            ArrayList<ShapeInfo> modifierShapeInfos,
1564            IPointConversion converter,
1565            Object clipArea) {
1566        try {
1567            reversePointsRevD(tg);
1568
1569            Rectangle2D clipBounds = null;
1570            CELineArray.setClient("ge");
1571//            ArrayList<POINT2> origPixels = null;
1572//            ArrayList<POINT2> origLatLongs = null;
1573//            if (clsUtilityGE.segmentColorsSet(tg)) {
1574//                origPixels=lineutility.getDeepCopy(tg.Pixels);
1575//                origLatLongs=lineutility.getDeepCopy(tg.LatLongs);
1576//            }
1577            ArrayList<POINT2> origFillPixels = lineutility.getDeepCopy(tg.Pixels);
1578
1579            if (tg.get_LineType() == TacticalLines.LC)
1580                armyc2.c5isr.JavaTacticalRenderer.clsUtility.SegmentLCPoints(tg, converter);
1581
1582//            boolean shiftLines = Channels.getShiftLines();
1583//            if (shiftLines) {
1584//                String affiliation = tg.get_Affiliation();
1585//                Channels.setAffiliation(affiliation);
1586//            }
1587            //CELineArray.setMinLength(2.5);    //2-27-2013
1588            ArrayList<Point2D> clipPoints = null;
1589            if (clipArea != null) {
1590                if (clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
1591                    clipBounds = (Rectangle2D.Double) clipArea;
1592                } else if (clipArea.getClass().isAssignableFrom(Rectangle.class)) {
1593                    Rectangle rectx = (Rectangle) clipArea;
1594                    clipBounds = new Rectangle2D.Double(rectx.x, rectx.y, rectx.width, rectx.height);
1595                } else if (clipArea.getClass().isAssignableFrom(ArrayList.class)) {
1596                    clipPoints = (ArrayList<Point2D>) clipArea;
1597                }
1598            }
1599            double zoomFactor = clsUtilityGE.getZoomFactor(clipBounds, clipPoints, tg.Pixels);
1600            //add sub-section to test clipArea if client passes the rectangle
1601            boolean useClipPoints = false;    //currently not used
1602            if (useClipPoints == true && clipBounds != null) {
1603                double x = clipBounds.getMinX();
1604                double y = clipBounds.getMinY();
1605                double width = clipBounds.getWidth();
1606                double height = clipBounds.getHeight();
1607                clipPoints = new ArrayList();
1608                clipPoints.add(new Point2D.Double(x, y));
1609                clipPoints.add(new Point2D.Double(x + width, y));
1610                clipPoints.add(new Point2D.Double(x + width, y + height));
1611                clipPoints.add(new Point2D.Double(x, y + height));
1612                clipPoints.add(new Point2D.Double(x, y));
1613                clipBounds = null;
1614            }
1615            //end section
1616
1617            if (tg.get_Client() == null || tg.get_Client().isEmpty()) {
1618                tg.set_client("ge");
1619            }
1620
1621            clsUtility.RemoveDuplicatePoints(tg);
1622
1623            int linetype = tg.get_LineType();
1624            if (linetype < 0) {
1625                linetype = armyc2.c5isr.JavaTacticalRenderer.clsUtility.GetLinetypeFromString(tg.get_SymbolId());
1626                //clsUtilityCPOF.SegmentGeoPoints(tg, converter);
1627                tg.set_LineType(linetype);
1628            }
1629
1630            Boolean isTextFlipped = false;
1631            ArrayList<Shape2> shapes = null;   //use this to collect all the shapes
1632            clsUtilityGE.setSplineLinetype(tg);
1633
1634            clsUtilityCPOF.SegmentGeoPoints(tg, converter, zoomFactor);
1635            if (clipBounds != null || clipPoints != null) {
1636                if (clsUtilityCPOF.canClipPoints(tg)) {
1637                    //check assignment
1638                    if (clipBounds != null) {
1639                        clsClipPolygon2.ClipPolygon(tg, clipBounds);
1640                    } else if (clipPoints != null) {
1641                        clsClipQuad.ClipPolygon(tg, clipPoints);
1642                    }
1643
1644                    clsUtilityGE.removeTrailingPoints(tg, clipArea);
1645                    tg.LatLongs = clsUtility.PixelsToLatLong(tg.Pixels, converter);
1646                }
1647            }
1648
1649            //if MSR segment data set use original pixels unless tg.Pixels is empty from clipping
1650//            if (origPixels != null) {
1651//                if (tg.Pixels.isEmpty()) {
1652//                    return;
1653//                } else {
1654//                    tg.Pixels = origPixels;
1655//                    tg.LatLongs = origLatLongs;
1656//                    clipArea = null;
1657//                }
1658//            }
1659            armyc2.c5isr.JavaTacticalRenderer.clsUtility.InterpolatePixels(tg);
1660
1661            tg.modifiers = new ArrayList();
1662            BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
1663            Graphics2D g2d = bi.createGraphics();
1664            g2d.setFont(tg.get_Font());
1665            Modifier2.AddModifiersGeo(tg, g2d, clipArea, converter);
1666
1667            clsUtilityCPOF.FilterPoints2(tg, converter);
1668            armyc2.c5isr.JavaTacticalRenderer.clsUtility.FilterVerticalSegments(tg);
1669            clsUtility.FilterAXADPoints(tg, converter);
1670            clsUtilityCPOF.ClearPixelsStyle(tg);
1671
1672            ArrayList<Shape2> linesWithFillShapes = null;
1673
1674            ArrayList<POINT2> savePixels = tg.Pixels;
1675            tg.Pixels = origFillPixels;
1676
1677            //check assignment
1678            if (clipBounds != null) {
1679                linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, clipBounds);
1680            } else if (clipPoints != null) {
1681                linesWithFillShapes = clsClipQuad.LinesWithFill(tg, clipPoints);
1682            } else if (clipArea == null) {
1683                linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, null);
1684            }
1685
1686            tg.Pixels = savePixels;
1687
1688            ArrayList<Shape2> rangeFanFillShapes = null;
1689            //do not fill the original shapes for circular range fans
1690            int savefillStyle = tg.get_FillStyle();
1691            if (linetype == TacticalLines.RANGE_FAN) {
1692                tg.set_Fillstyle(0);
1693            }
1694
1695            //check assignment (pass which clip object is not null)
1696            if (clipBounds != null) {
1697                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds); //takes clip object           
1698            } else if (clipPoints != null) {
1699                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipPoints);
1700            } else if (clipArea == null) {
1701                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, null);
1702            }
1703
1704            // Add Feint, decoy, or dummy indicator
1705            if (shapes != null
1706                    && SymbolID.getSymbolSet(tg.get_SymbolId()) == SymbolID.SymbolSet_ControlMeasure
1707                    && SymbolUtilities.hasFDI(tg.get_SymbolId())) {
1708                addFDI(tg, shapes);
1709            }
1710
1711            switch (linetype) {
1712                case TacticalLines.RANGE_FAN:
1713                case TacticalLines.RANGE_FAN_SECTOR:
1714                case TacticalLines.RADAR_SEARCH:
1715                    if (tg.get_FillColor() == null || tg.get_FillColor().getAlpha() < 2) {
1716                        break;
1717                    }
1718                    TGLight tg1 = clsUtilityCPOF.GetCircularRangeFanFillTG(tg);
1719                    tg1.set_Fillstyle(savefillStyle);
1720                    tg1.set_SymbolId(tg.get_SymbolId());
1721                    //check assignment (pass which clip object is not null)
1722                    if (clipBounds != null) {
1723                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, clipBounds);
1724                    } else if (clipPoints != null) {
1725                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, clipPoints);
1726                    } else if (clipArea == null) {
1727                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, null);
1728                    }
1729
1730                    if (rangeFanFillShapes != null) {
1731                        if (shapes == null) {
1732                            System.out.println("shapes is null");
1733                            break;
1734                        } else {
1735                            shapes.addAll(0, rangeFanFillShapes);
1736                        }
1737
1738                    }
1739                    break;
1740                default:
1741                    clsRenderer2.getAutoshapeFillShape(tg, shapes);
1742                    break;
1743            }
1744            //end section
1745
1746            //undo any fillcolor for lines with fill
1747            clsUtilityCPOF.LinesWithSeparateFill(tg.get_LineType(), shapes);
1748            clsClipPolygon2.addAbatisFill(tg, shapes);
1749
1750            //if this line is commented then the extra line in testbed goes away
1751            if (shapes != null && linesWithFillShapes != null && linesWithFillShapes.size() > 0) {
1752                shapes.addAll(0, linesWithFillShapes);
1753            }
1754
1755            if (clsUtilityCPOF.canClipPoints(tg) == false && clipBounds != null) {
1756                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipBounds);
1757            } else if (clsUtilityCPOF.canClipPoints(tg) == false && clipPoints != null) {
1758                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipPoints);
1759            }
1760            resolvePostClippedShapes(tg,shapes);
1761            //returns early if textSpecs are null
1762            //currently the client is ignoring these
1763            if (modifierShapeInfos != null) {
1764                ArrayList<Shape2> textSpecs = new ArrayList();
1765                Modifier2.DisplayModifiers2(tg, g2d, textSpecs, isTextFlipped, converter);
1766                Shape2ToShapeInfo(modifierShapeInfos, textSpecs);
1767            }
1768            Shape2ToShapeInfo(shapeInfos, shapes);
1769            clsUtility.addHatchFills(tg, shapeInfos);
1770
1771            //check assignment (pass which clip object is not null)
1772            if (clipBounds != null) {
1773                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipBounds);//takes a clip object            
1774            } else if (clipPoints != null) {
1775                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipPoints);
1776            } else if (clipArea == null) {
1777                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, null);
1778            }
1779        } catch (Exception exc) {
1780            ErrorLogger.LogException(_className, "render_GE",
1781                    new RendererException("Failed inside render_GE", exc));
1782
1783        }
1784    }
1785    /**
1786     * creates a shape for known symbols. The intent is to use client points for
1787     * the shape and is intended for use with ellipse. If hatch &gt; 1 it creates 2 shapes
1788     * one for the hatch pattern, the second one is for the outline.
1789     *
1790     * @param milStd
1791     * @param ipc
1792     * @param clipArea
1793     * @param shapeType
1794     * @param lineColor
1795     * @param fillColor
1796     * @param hatch
1797     */
1798    public static void render_Shape(MilStdSymbol milStd,
1799            IPointConversion ipc,
1800            Object clipArea,
1801            int shapeType,
1802            Color lineColor,
1803            Color fillColor,
1804            int hatch) {
1805        try {
1806            Rectangle2D clipBounds = null;
1807            //CELineArray.setClient("ge");
1808            ArrayList<Point2D> clipPoints = null;
1809
1810            if (clipArea != null) {
1811                if (clipArea.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
1812                    clipBounds = (Rectangle2D.Double) clipArea;
1813                } else if (clipArea.getClass().isAssignableFrom(Rectangle.class)) {
1814                    clipBounds = (Rectangle2D) clipArea;
1815                } else if (clipArea.getClass().isAssignableFrom(ArrayList.class)) {
1816                    clipPoints = (ArrayList<Point2D>) clipArea;
1817                }
1818            }
1819            
1820            //can't use following line because it resets the pixels
1821            //TGLight tg = createTGLightFromMilStdSymbol(milStd, ipc);
1822            TGLight tg = new TGLight();
1823            tg.set_SymbolId(milStd.getSymbolID());
1824            //tg.set_VisibleModifiers(true);
1825            //set tg latlongs and pixels
1826            setClientCoords(milStd, tg);
1827            //build tg.Pixels
1828            tg.Pixels = clsUtility.LatLongToPixels(tg.LatLongs, ipc);            
1829            
1830            //int fillStyle = milStd.getPatternFillType();
1831            Shape2 shape = new Shape2(shapeType);
1832            shape.setFillColor(fillColor);
1833            if (lineColor != null) {
1834                shape.setLineColor(lineColor);
1835                shape.setStroke(new BasicStroke(milStd.getLineWidth()));
1836            }
1837            //the client has already set the coordinates for the shape
1838            POINT2 pt;
1839            for (int j = 0; j < tg.Pixels.size(); j++) {
1840                pt = tg.Pixels.get(j);
1841                if (j == 0) {
1842                    shape.moveTo(pt);
1843                } else {
1844                    shape.lineTo(pt);
1845                }
1846            }
1847
1848            //post clip the shape and set the polylines
1849            ArrayList<Shape2> shapes = new ArrayList();
1850            shapes.add(shape);
1851            //post-clip the shape
1852            if (clsUtilityCPOF.canClipPoints(tg) == false && clipBounds != null) {
1853                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipBounds);
1854            } else if (clsUtilityCPOF.canClipPoints(tg) == false && clipPoints != null) {
1855                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipPoints);
1856            }
1857            shape=shapes.get(0);
1858            if (hatch > 1) 
1859            {
1860                shape = clsUtility.buildHatchArea(tg, shape, hatch, 20);
1861                shape.setLineColor(lineColor);
1862                shape.setStroke(new BasicStroke(1));
1863                //shapes.clear();
1864                shapes.add(shape);
1865            }
1866            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1867            Shape2ToShapeInfo(shapeInfos, shapes);
1868            //set the shapeInfo polylines
1869            if (clipBounds != null) {
1870                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipBounds);
1871            } else if (clipPoints != null) {
1872                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, clipPoints);
1873            } else if (clipArea == null) {
1874                clsUtilityGE.SetShapeInfosPolylines(tg, shapeInfos, null);
1875            }
1876            //set milStd symbol shapes
1877            if (milStd.getSymbolShapes() == null) {
1878                milStd.setSymbolShapes(shapeInfos);
1879            } else {
1880                milStd.getSymbolShapes().addAll(shapeInfos);
1881            }
1882            return;
1883        } catch (Exception exc) {
1884            ErrorLogger.LogException(_className, "render_Shape",
1885                    new RendererException("Failed inside render_Shape", exc));
1886
1887        }
1888    }
1889
1890    private static void resolvePostClippedShapes(TGLight tg, ArrayList<Shape2> shapes) {
1891        try {
1892            //resolve the PBS and BBS shape properties after the post clip, regardless whether they were clipped
1893            switch (tg.get_LineType()) {
1894                case TacticalLines.BBS_RECTANGLE:
1895                case TacticalLines.BBS_POINT:
1896                case TacticalLines.BBS_LINE:
1897                case TacticalLines.BBS_AREA:
1898                case TacticalLines.PBS_RECTANGLE:
1899                case TacticalLines.PBS_SQUARE:
1900                    break;
1901                default:
1902                    return;
1903            }
1904            Color fillColor = tg.get_FillColor();
1905            shapes.get(0).setFillColor(fillColor);
1906            shapes.get(1).setFillColor(null);
1907            int fillStyle = tg.get_FillStyle();
1908            shapes.get(0).set_Fillstyle(0);
1909            shapes.get(1).set_Fillstyle(fillStyle);
1910            return;
1911
1912        } catch (Exception exc) {
1913            ErrorLogger.LogException(_className, "resolvePostClippedShapes",
1914                    new RendererException("Failed inside resolvePostClippedShapes", exc));
1915
1916        }
1917    }
1918
1919    /**
1920     * set the clip rectangle as an arraylist or a Rectangle2D depending on the
1921     * object
1922     *
1923     * @param clipBounds
1924     * @param clipRect
1925     * @param clipArray
1926     * @return
1927     */
1928    private static boolean setClip(Object clipBounds, Rectangle2D clipRect, ArrayList<Point2D> clipArray) {
1929        try {
1930            if (clipBounds == null) {
1931                return false;
1932            } else if (clipBounds.getClass().isAssignableFrom(Rectangle2D.Double.class)) {
1933                clipRect.setRect((Rectangle2D) clipBounds);
1934            } else if (clipBounds.getClass().isAssignableFrom(Rectangle2D.class)) {
1935                clipRect.setRect((Rectangle2D) clipBounds);
1936            } else if (clipBounds.getClass().isAssignableFrom(Rectangle.class)) {
1937                //clipRect.setRect((Rectangle2D)clipBounds);
1938                Rectangle rectx = (Rectangle) clipBounds;
1939                //clipBounds=new Rectangle2D.Double(rectx.x,rectx.y,rectx.width,rectx.height);
1940                clipRect.setRect(rectx.x, rectx.y, rectx.width, rectx.height);
1941            } else if (clipBounds.getClass().isAssignableFrom(ArrayList.class)) {
1942                clipArray.addAll((ArrayList) clipBounds);
1943            }
1944        } catch (Exception exc) {
1945            ErrorLogger.LogException(_className, "setClip",
1946                    new RendererException("Failed inside setClip", exc));
1947
1948        }
1949        return true;
1950    }
1951
1952    /**
1953     * public render function transferred from JavaLineArrayCPOF project. Use
1954     * this function to replicate CPOF renderer functionality.
1955     *
1956     * @param mss the milStdSymbol object
1957     * @param converter the geographic to pixels coordinate converter
1958     * @param clipBounds the pixels based clip bounds
1959     */
1960    public static void render(MilStdSymbol mss,
1961            IPointConversion converter,
1962            Object clipBounds) {
1963        try {
1964            ArrayList<ShapeInfo> shapeInfos = new ArrayList();
1965            ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList();
1966            render(mss, converter, shapeInfos, modifierShapeInfos, clipBounds);
1967        } catch (Exception exc) {
1968            ErrorLogger.LogException(_className, "render",
1969                    new RendererException("render", exc));
1970
1971        }
1972    }
1973
1974    /**
1975     * Generic tester button says Tiger or use JavaRendererSample. Generic
1976     * renderer testers: called by JavaRendererSample and TestJavaLineArray
1977     * public render function transferred from JavaLineArrayCPOF project. Use
1978     * this function to replicate CPOF renderer functionality.
1979     *
1980     * @param mss
1981     * @param converter geographic to pixels converter
1982     * @param shapeInfos ShapeInfo array
1983     * @param modifierShapeInfos modifier ShapeInfo array
1984     * @param clipBounds clip bounds
1985     */
1986    public static void render(MilStdSymbol mss,
1987            IPointConversion converter,
1988            ArrayList<ShapeInfo> shapeInfos,
1989            ArrayList<ShapeInfo> modifierShapeInfos,
1990            Object clipBounds) {
1991        try {
1992            //boolean shiftLines = Channels.getShiftLines();
1993            //end section
1994
1995            Rectangle2D clipRect = new Rectangle2D.Double();
1996            ArrayList<Point2D> clipArray = new ArrayList();
1997            setClip(clipBounds, clipRect, clipArray);
1998
1999            TGLight tg = createTGLightFromMilStdSymbol(mss, converter);
2000            reversePointsRevD(tg);
2001            CELineArray.setClient("generic");
2002//            if (shiftLines) {
2003//                String affiliation = tg.get_Affiliation();
2004//                Channels.setAffiliation(affiliation);
2005//            }
2006            //CELineArray.setMinLength(2.5);    //2-27-2013
2007
2008            int linetype = tg.get_LineType();
2009            //replace calls to MovePixels
2010            clsUtility.RemoveDuplicatePoints(tg);
2011
2012            BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
2013            Graphics2D g2d = bi.createGraphics();
2014            g2d.setFont(tg.get_Font());
2015
2016            clsUtilityCPOF.SegmentGeoPoints(tg, converter, 1);
2017            clsUtility.FilterAXADPoints(tg, converter);
2018
2019            //prevent vertical segments for oneway, twoway, alt
2020            armyc2.c5isr.JavaTacticalRenderer.clsUtility.FilterVerticalSegments(tg);
2021            boolean isChange1Area = armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(linetype);
2022            boolean isTextFlipped = false;
2023            //for 3d change 1 symbols we do not transform the points
2024
2025            //if it is world view then we want to flip the far points about
2026            //the left and right sides to get two symbols
2027            ArrayList<POINT2> farLeftPixels = new ArrayList();
2028            ArrayList<POINT2> farRightPixels = new ArrayList();
2029            if (isChange1Area == false) {
2030                clsUtilityCPOF.GetFarPixels(tg, converter, farLeftPixels, farRightPixels);
2031            }
2032
2033            ArrayList<Shape2> shapesLeft = new ArrayList();
2034            ArrayList<Shape2> shapesRight = new ArrayList();
2035            ArrayList<Shape2> shapes = null;   //use this to collect all the shapes
2036
2037            //CPOF 6.0 diagnostic
2038            ArrayList<Shape2> textSpecsLeft = null;
2039            ArrayList<Shape2> textSpecsRight = null;
2040            //Note: DisplayModifiers3 returns early if textSpecs are null
2041            textSpecsLeft = new ArrayList();
2042            textSpecsRight = new ArrayList();
2043
2044            if (farLeftPixels.size() > 0) {
2045                tg.Pixels = farLeftPixels;
2046                shapesLeft = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds);
2047                //CPOF 6.0
2048                //returns early if textSpecs are null
2049                Modifier2.DisplayModifiers2(tg, g2d, textSpecsLeft, isTextFlipped, null);
2050            }
2051            if (farRightPixels.size() > 0) {
2052                tg.Pixels = farRightPixels;
2053                shapesRight = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds);
2054                //CPOF 6.0
2055                //returns early if textSpecs are null
2056                Modifier2.DisplayModifiers2(tg, g2d, textSpecsRight, isTextFlipped, null);
2057            }
2058
2059            //CPOF 6.0 diagnostic
2060            ArrayList<Shape2> textSpecs = new ArrayList();
2061
2062            if (shapesLeft.isEmpty() || shapesRight.isEmpty()) {
2063                ArrayList<Shape2> linesWithFillShapes = null;
2064                if (clipArray != null && !clipArray.isEmpty()) {
2065                    linesWithFillShapes = clsClipQuad.LinesWithFill(tg, clipArray);
2066                } else if (clipRect != null && clipRect.getWidth() != 0) {
2067                    linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, clipRect);
2068                } else {
2069                    linesWithFillShapes = clsClipPolygon2.LinesWithFill(tg, null);
2070                }
2071
2072                //diagnostic: comment two lines if using the WW tester
2073                if (clsUtilityCPOF.canClipPoints(tg) && clipBounds != null) {
2074                    if (clipArray != null && !clipArray.isEmpty()) {
2075                        clsClipQuad.ClipPolygon(tg, clipArray);
2076                    } else if (clipRect != null && clipRect.getWidth() != 0) {
2077                        clsClipPolygon2.ClipPolygon(tg, clipRect);
2078                    }
2079
2080                    tg.LatLongs = clsUtility.PixelsToLatLong(tg.Pixels, converter);
2081                }
2082
2083                //diagnostic 1-28-13
2084                armyc2.c5isr.JavaTacticalRenderer.clsUtility.InterpolatePixels(tg);
2085
2086                tg.modifiers = new ArrayList();
2087                Modifier2.AddModifiersGeo(tg, g2d, clipBounds, converter);
2088
2089                clsUtilityCPOF.FilterPoints2(tg, converter);
2090                clsUtilityCPOF.ClearPixelsStyle(tg);
2091                //add section to replace preceding line M. Deutch 11-4-2011
2092                ArrayList rangeFanFillShapes = null;
2093                //do not fill the original shapes for circular range fans
2094                int savefillStyle = tg.get_FillStyle();
2095                if (linetype == TacticalLines.RANGE_FAN) {
2096                    tg.set_Fillstyle(0);
2097                }
2098
2099                shapes = clsRenderer2.GetLineArray(tg, converter, isTextFlipped, clipBounds);
2100
2101                // Add Feint, decoy, or dummy indicator
2102                if (shapes != null
2103                        && SymbolID.getSymbolSet(tg.get_SymbolId()) == SymbolID.SymbolSet_ControlMeasure
2104                        && SymbolUtilities.hasFDI(tg.get_SymbolId())) {
2105                    addFDI(tg, shapes);
2106                }
2107
2108                switch (linetype) {
2109                    case TacticalLines.RANGE_FAN:
2110                    case TacticalLines.RANGE_FAN_SECTOR:
2111                    case TacticalLines.RADAR_SEARCH:
2112                        if (tg.get_FillColor() == null || tg.get_FillColor().getAlpha() < 2) {
2113                            break;
2114                        }
2115                        TGLight tg1 = clsUtilityCPOF.GetCircularRangeFanFillTG(tg);
2116                        tg1.set_Fillstyle(savefillStyle);
2117                        tg1.set_SymbolId(tg.get_SymbolId());
2118                        rangeFanFillShapes = clsRenderer2.GetLineArray(tg1, converter, isTextFlipped, clipBounds);
2119
2120                        if (rangeFanFillShapes != null) {
2121                            shapes.addAll(0, rangeFanFillShapes);
2122                        }
2123                        break;
2124                    default:
2125                        break;
2126                }
2127
2128                //undo any fillcolor for lines with fill
2129                clsUtilityCPOF.LinesWithSeparateFill(tg.get_LineType(), shapes);
2130                clsClipPolygon2.addAbatisFill(tg, shapes);
2131
2132                //if this line is commented then the extra line in testbed goes away
2133                if (shapes != null && linesWithFillShapes != null && linesWithFillShapes.size() > 0) {
2134                    shapes.addAll(0, linesWithFillShapes);
2135                }
2136
2137                if (shapes != null && shapes.size() > 0) {
2138                    Modifier2.DisplayModifiers2(tg, g2d, textSpecs, isTextFlipped, null);
2139                    Shape2ToShapeInfo(modifierShapeInfos, textSpecs);
2140                    mss.setModifierShapes(modifierShapeInfos);
2141                }
2142            } else //symbol was more than 180 degrees wide, use left and right symbols
2143            {
2144                shapes = shapesLeft;
2145                shapes.addAll(shapesRight);
2146
2147                if (textSpecs != null) {
2148                    textSpecs.addAll(textSpecsLeft);
2149                    textSpecs.addAll(textSpecsRight);
2150                }
2151            }
2152            //post-clip the points if the tg could not be pre-clipped
2153            if (clsUtilityCPOF.canClipPoints(tg) == false && clipBounds != null) {
2154                shapes = clsUtilityCPOF.postClipShapes(tg, shapes, clipBounds);
2155            }
2156
2157            Shape2ToShapeInfo(shapeInfos, shapes);
2158            clsUtility.addHatchFills(tg, shapeInfos);
2159            mss.setSymbolShapes(shapeInfos);
2160        } catch (Exception exc) {
2161            ErrorLogger.LogException(_className, "render",
2162                    new RendererException("Failed inside render", exc));
2163
2164        }
2165    }
2166
2167    public static int getCMLineType(int version, int entityCode) {
2168        // Check if line type is specific to a version
2169        if (version >= SymbolID.Version_2525Ech1) {
2170            switch (entityCode) {
2171                // Added in 2525Ech1
2172
2173                // Updated in 2525Ech1
2174                case 172000:
2175                    return TacticalLines.WFZ;//extra modifiers
2176                // Removed in 2525Ech1
2177                case 240804:
2178                    return -1;
2179            }
2180        }
2181        if (version >= SymbolID.Version_2525E) {
2182            switch (entityCode) {
2183                // Added in 2525E
2184
2185                // Updated in 2525E
2186                case 120500:
2187                    return TacticalLines.BASE_CAMP;//labels B,T,H,N,W,W1
2188                case 120600:
2189                    return TacticalLines.GUERILLA_BASE;//labels B,T,H,N,W,W1
2190                case 260400:
2191                    return TacticalLines.BCL;//label like "BCL (T)"
2192                case 310100:
2193                    return TacticalLines.DHA;//label just DHA
2194                // Updated in 2525Ech1
2195                case 172000:
2196                    return TacticalLines.WFZ_REVD;//fewer modifiers
2197            }
2198        }
2199        else{ // 2525Dchange 1 and older
2200            switch (entityCode) {
2201                // Updated in 2525E
2202                case 120500:
2203                    return TacticalLines.BASE_CAMP_REVD;//just 'T' modiifer
2204                case 120600:
2205                    return TacticalLines.GUERILLA_BASE_REVD;//just 'T' modiifer
2206                case 260400:
2207                    return TacticalLines.BCL_REVD;//label like "BCL T"
2208                case 310100:
2209                    return TacticalLines.DHA_REVD;//label DHA spelled out
2210                // Removed in 2525E/APP6E
2211                case 150300:
2212                    return TacticalLines.ASSY;
2213                case 241601:
2214                    return TacticalLines.SENSOR;
2215                case 241602:
2216                    return TacticalLines.SENSOR_RECTANGULAR;
2217                case 241603:
2218                    return TacticalLines.SENSOR_CIRCULAR;
2219                // Updated in 2525Ech1
2220                case 172000:
2221                    return TacticalLines.WFZ_REVD;//fewer modifiers
2222            }
2223        }
2224        // Line type isn't specific to a version or doesn't exist
2225        switch (entityCode) {
2226            case 151000:
2227                return TacticalLines.FORT;
2228            case 110400:
2229                return TacticalLines.GENERIC_LINE;
2230            case 110500:
2231                return TacticalLines.DECISION_LINE;
2232            case 120700:
2233                return TacticalLines.GENERIC_AREA;
2234            case 141800:
2235                return TacticalLines.HOL;
2236            case 141900:
2237                return TacticalLines.BHL;
2238            case 310800:
2239                return TacticalLines.CSA;
2240            case 330500:
2241                return TacticalLines.TRAFFIC_ROUTE;
2242            case 330501:
2243                return TacticalLines.TRAFFIC_ROUTE_ONEWAY;
2244            case 330502:
2245                return TacticalLines.TRAFFIC_ROUTE_ALT;
2246            case 344100:
2247                return TacticalLines.FPOL;
2248            case 344200:
2249                return TacticalLines.RPOL;
2250            case 152600:
2251                return TacticalLines.AREA_DEFENSE;
2252            case 152700:
2253                return TacticalLines.FRONTAL_ATTACK;
2254            case 152900:
2255                return TacticalLines.TURNING_MOVEMENT;
2256            case 152800:
2257                return TacticalLines.MOBILE_DEFENSE;
2258            case 242800:
2259                return TacticalLines.KILL_ZONE;
2260            case 342900:
2261                return TacticalLines.MOVEMENT_TO_CONTACT;
2262            case 343100:
2263                return TacticalLines.EXPLOIT;
2264            case 343300:
2265                return TacticalLines.DEMONSTRATE;
2266            case 343500:
2267                return TacticalLines.ENVELOPMENT;
2268            case 343700:
2269                return TacticalLines.EXFILTRATION;
2270            case 343800:
2271                return TacticalLines.INFILTRATION;
2272            case 344000:
2273                return TacticalLines.PURSUIT;
2274            case 344400:
2275                return TacticalLines.DISENGAGE;
2276            case 344500:
2277                return TacticalLines.EVACUATE;
2278            case 344700:
2279                return TacticalLines.TURN;
2280            case 200101:
2281                return TacticalLines.LAUNCH_AREA;
2282            case 200201:
2283                return TacticalLines.DEFENDED_AREA_CIRCULAR;
2284            case 200202:
2285                return TacticalLines.DEFENDED_AREA_RECTANGULAR;
2286            case 120100:
2287                return TacticalLines.AO;
2288            case 120200:
2289                return TacticalLines.NAI;
2290            case 120300:
2291                return TacticalLines.TAI;
2292            case 120400:
2293                return TacticalLines.AIRFIELD;
2294            case 151401:
2295                return TacticalLines.AIRAOA;
2296            case 151402:
2297                return TacticalLines.AAAAA;
2298            case 151403:
2299                return TacticalLines.MAIN;
2300            case 151404:
2301                return TacticalLines.SPT;
2302            case 110100:
2303                return TacticalLines.BOUNDARY;
2304            case 110200:
2305                return TacticalLines.LL;
2306            case 110300:
2307                return TacticalLines.EWL;
2308            case 140100:
2309                return TacticalLines.FLOT;
2310            case 140200:
2311                return TacticalLines.LC;
2312            case 140300:
2313                return TacticalLines.PL;
2314            case 140400:
2315                return TacticalLines.FEBA;
2316            case 140500:
2317                return TacticalLines.PDF;
2318            case 140601:
2319                return TacticalLines.DIRATKAIR;
2320            case 140602:
2321                return TacticalLines.DIRATKGND;
2322            case 140603:
2323                return TacticalLines.DIRATKSPT;
2324            case 140700:
2325                return TacticalLines.FCL;
2326            case 140800:
2327                return TacticalLines.IL;
2328            case 140900:
2329                return TacticalLines.LOA;
2330            case 141000:
2331                return TacticalLines.LOD;
2332            case 141100:
2333                return TacticalLines.LDLC;
2334            case 141200:
2335                return TacticalLines.PLD;
2336            case 150200:
2337                return TacticalLines.ASSY;
2338            case 150100:
2339                return TacticalLines.GENERAL;
2340            case 150501:
2341                return TacticalLines.JTAA;
2342            case 150502:
2343                return TacticalLines.SAA;
2344            case 150503:
2345                return TacticalLines.SGAA;
2346            case 150600:    //dz no eny
2347                return TacticalLines.DZ;
2348            case 150700:    //ez no eny
2349                return TacticalLines.EZ;
2350            case 150800:    //lz no eny
2351                return TacticalLines.LZ;
2352            case 150900:    //pz no eny
2353                return TacticalLines.PZ;
2354            case 151100:
2355                return TacticalLines.LAA;
2356            case 151200:
2357                return TacticalLines.BATTLE;
2358            case 151202:
2359                return TacticalLines.PNO;
2360            case 151204:
2361                return TacticalLines.CONTAIN;
2362            case 151205:
2363                return TacticalLines.RETAIN;
2364            case 151300:
2365                return TacticalLines.EA;
2366            case 151203:
2367                return TacticalLines.STRONG;
2368            case 151500:
2369                return TacticalLines.ASSAULT;
2370            case 151600:
2371                return TacticalLines.ATKPOS;
2372            case 151700:
2373                return TacticalLines.OBJ;
2374            case 151800:
2375                return TacticalLines.ENCIRCLE;
2376            case 151900:
2377                return TacticalLines.PEN;
2378            case 152000:
2379                return TacticalLines.ATKBYFIRE;
2380            case 152100:
2381                return TacticalLines.SPTBYFIRE;
2382            case 152200:
2383                return TacticalLines.SARA;
2384            case 141300:
2385                return TacticalLines.AIRHEAD;
2386            case 141400:
2387                return TacticalLines.BRDGHD;
2388            case 141500:
2389                return TacticalLines.HOLD;
2390            case 141600:
2391                return TacticalLines.RELEASE;
2392            case 141700:
2393                return TacticalLines.AMBUSH;
2394            case 170100:
2395                return TacticalLines.AC;
2396            case 170200:
2397                return TacticalLines.LLTR;
2398            case 170300:
2399                return TacticalLines.MRR;
2400            case 170400:
2401                return TacticalLines.SL;
2402            case 170500:
2403                return TacticalLines.SAAFR;
2404            case 170600:
2405                return TacticalLines.TC;
2406            case 170700:
2407                return TacticalLines.SC;
2408            case 170800:
2409                return TacticalLines.BDZ;
2410            case 170900:
2411                return TacticalLines.HIDACZ;
2412            case 171000:
2413                return TacticalLines.ROZ;
2414            case 171100:
2415                return TacticalLines.AARROZ;
2416            case 171200:
2417                return TacticalLines.UAROZ;
2418            case 171300:
2419                return TacticalLines.WEZ;
2420            case 171400:
2421                return TacticalLines.FEZ;
2422            case 171500:
2423                return TacticalLines.JEZ;
2424            case 171600:
2425                return TacticalLines.MEZ;
2426            case 171700:
2427                return TacticalLines.LOMEZ;
2428            case 171800:
2429                return TacticalLines.HIMEZ;
2430            case 171900:
2431                return TacticalLines.FAADZ;
2432            case 200401:
2433                return TacticalLines.SHIP_AOI_CIRCULAR;
2434            case 240804:
2435                return TacticalLines.RECTANGULAR_TARGET;
2436            case 220100:
2437                return TacticalLines.BEARING;
2438            case 230100:
2439            case 230200:
2440                return TacticalLines.DECEIVE;
2441            case 220101:
2442                return TacticalLines.ELECTRO;
2443            case 220102:    //EW                //new label
2444                return TacticalLines.BEARING_EW;
2445            case 220103:
2446                return TacticalLines.ACOUSTIC;
2447            case 220104:
2448                return TacticalLines.ACOUSTIC_AMB;
2449            case 220105:
2450                return TacticalLines.TORPEDO;
2451            case 220106:
2452                return TacticalLines.OPTICAL;
2453            case 218400:
2454                return TacticalLines.NAVIGATION;
2455            case 220107:    //Jammer                //new label
2456                return TacticalLines.BEARING_J;
2457            case 220108:    //RDF                   //new label
2458                return TacticalLines.BEARING_RDF;
2459            case 240101:
2460                return TacticalLines.ACA;
2461            case 240102:
2462                return TacticalLines.ACA_RECTANGULAR;
2463            case 240103:
2464                return TacticalLines.ACA_CIRCULAR;
2465
2466            case 240201:
2467                return TacticalLines.FFA;
2468            case 240202:
2469                return TacticalLines.FFA_RECTANGULAR;
2470            case 240203:
2471                return TacticalLines.FFA_CIRCULAR;
2472
2473            case 240301:
2474                return TacticalLines.NFA;
2475            case 240302:
2476                return TacticalLines.NFA_RECTANGULAR;
2477            case 240303:
2478                return TacticalLines.NFA_CIRCULAR;
2479
2480            case 240401:
2481                return TacticalLines.RFA;
2482            case 240402:
2483                return TacticalLines.RFA_RECTANGULAR;
2484            case 240403:
2485                return TacticalLines.RFA_CIRCULAR;
2486            case 240503:
2487                return TacticalLines.PAA;
2488            case 240501:
2489                return TacticalLines.PAA_RECTANGULAR;
2490            case 240502:
2491                return TacticalLines.PAA_CIRCULAR;
2492            case 260100:
2493                return TacticalLines.FSCL;
2494            case 300100:
2495                return TacticalLines.ICL;
2496            case 190100:
2497                return TacticalLines.IFF_OFF;
2498            case 190200:
2499                return TacticalLines.IFF_ON;
2500            case 260200:
2501                return TacticalLines.CFL;
2502            case 260300:
2503                return TacticalLines.NFL;
2504            case 260500:
2505                return TacticalLines.RFL;
2506            case 260600:
2507                return TacticalLines.MFP;
2508            case 240701:
2509                return TacticalLines.LINTGT;
2510            case 240702:
2511                return TacticalLines.LINTGTS;
2512            case 240703:
2513                return TacticalLines.FPF;
2514            case 240801:
2515                return TacticalLines.AT;
2516            case 240802:
2517                return TacticalLines.RECTANGULAR;
2518            case 240803:
2519                return TacticalLines.CIRCULAR;
2520            case 240805:
2521                return TacticalLines.SERIES;
2522            case 240806:
2523                return TacticalLines.SMOKE;
2524            case 240808:
2525                return TacticalLines.BOMB;
2526            case 241001:
2527                return TacticalLines.FSA;
2528            case 241002:
2529                return TacticalLines.FSA_RECTANGULAR;
2530            case 200402:
2531                return TacticalLines.SHIP_AOI_RECTANGULAR;
2532            case 200600:
2533                return TacticalLines.CUED_ACQUISITION;
2534            case 200700:
2535                return TacticalLines.RADAR_SEARCH;
2536            case 241003:
2537                return TacticalLines.FSA_CIRCULAR;
2538            case 200300:
2539                return TacticalLines.NOTACK;
2540            case 241101:
2541                return TacticalLines.ATI;
2542            case 241102:
2543                return TacticalLines.ATI_RECTANGULAR;
2544            case 241103:
2545                return TacticalLines.ATI_CIRCULAR;
2546            case 241201:
2547                return TacticalLines.CFFZ;
2548            case 241202:
2549                return TacticalLines.CFFZ_RECTANGULAR;
2550            case 241203:
2551                return TacticalLines.CFFZ_CIRCULAR;
2552            case 241301:
2553                return TacticalLines.CENSOR;
2554            case 241302:
2555                return TacticalLines.CENSOR_RECTANGULAR;
2556            case 241303:
2557                return TacticalLines.CENSOR_CIRCULAR;
2558            case 241401:
2559                return TacticalLines.CFZ;
2560            case 241402:
2561                return TacticalLines.CFZ_RECTANGULAR;
2562            case 241403:
2563                return TacticalLines.CFZ_CIRCULAR;
2564            case 241501:
2565                return TacticalLines.DA;
2566            case 241502:
2567                return TacticalLines.DA_RECTANGULAR;
2568            case 241503:
2569                return TacticalLines.DA_CIRCULAR;
2570            case 241701:
2571                return TacticalLines.TBA;
2572            case 241702:
2573                return TacticalLines.TBA_RECTANGULAR;
2574            case 241703:
2575                return TacticalLines.TBA_CIRCULAR;
2576            case 241801:
2577                return TacticalLines.TVAR;
2578            case 241802:
2579                return TacticalLines.TVAR_RECTANGULAR;
2580            case 241803:
2581                return TacticalLines.TVAR_CIRCULAR;
2582            case 241901:
2583                return TacticalLines.ZOR;
2584            case 241902:
2585                return TacticalLines.ZOR_RECTANGULAR;
2586            case 241903:
2587                return TacticalLines.ZOR_CIRCULAR;
2588            case 242000:
2589                return TacticalLines.TGMF;
2590            case 242100:
2591                return TacticalLines.RANGE_FAN;
2592            case 242200:
2593                return TacticalLines.RANGE_FAN_SECTOR;
2594            case 242301:
2595                return TacticalLines.KILLBOXBLUE;
2596            case 242302:
2597                return TacticalLines.KILLBOXBLUE_RECTANGULAR;
2598            case 242303:
2599                return TacticalLines.KILLBOXBLUE_CIRCULAR;
2600            case 242304:
2601                return TacticalLines.KILLBOXPURPLE;
2602            case 242305:
2603                return TacticalLines.KILLBOXPURPLE_RECTANGULAR;
2604            case 242306:
2605                return TacticalLines.KILLBOXPURPLE_CIRCULAR;
2606            case 270100:
2607            case 270200:
2608                return TacticalLines.ZONE;
2609            case 270300:
2610                return TacticalLines.OBSFAREA;
2611            case 270400:
2612                return TacticalLines.OBSAREA;
2613            case 270501:
2614                return TacticalLines.MNFLDBLK;
2615            case 270502:
2616                return TacticalLines.MNFLDDIS;
2617            case 270503:
2618                return TacticalLines.MNFLDFIX;
2619            case 270504:
2620                return TacticalLines.TURN_REVD;
2621            case 270601:
2622                return TacticalLines.EASY;
2623            case 270602:
2624                return TacticalLines.BYDIF;
2625            case 270603:
2626                return TacticalLines.BYIMP;
2627            case 271100:
2628                return TacticalLines.GAP;
2629            case 271201:
2630                return TacticalLines.PLANNED;
2631            case 271202:
2632                return TacticalLines.ESR1;
2633            case 271203:
2634                return TacticalLines.ESR2;
2635            case 271204:
2636                return TacticalLines.ROADBLK;
2637            case 280100:
2638                return TacticalLines.ABATIS;
2639            case 290100:
2640                return TacticalLines.LINE;
2641            case 290201:
2642                return TacticalLines.ATDITCH;
2643            case 290202:
2644                return TacticalLines.ATDITCHC;
2645            case 290203:
2646                return TacticalLines.ATDITCHM;
2647            case 290204:
2648                return TacticalLines.ATWALL;
2649            case 290301:
2650                return TacticalLines.UNSP;
2651            case 290302:
2652                return TacticalLines.SFENCE;
2653            case 290303:
2654                return TacticalLines.DFENCE;
2655            case 290304:
2656                return TacticalLines.DOUBLEA;
2657            case 290305:
2658                return TacticalLines.LWFENCE;
2659            case 290306:
2660                return TacticalLines.HWFENCE;
2661            case 290307:
2662                return TacticalLines.SINGLEC;
2663            case 290308:
2664                return TacticalLines.DOUBLEC;
2665            case 290309:
2666                return TacticalLines.TRIPLE;
2667            case 290600:
2668                return TacticalLines.MFLANE;
2669            case 270707:
2670                return TacticalLines.DEPICT;
2671            case 270800:
2672                return TacticalLines.MINED;
2673            case 270801:
2674                return TacticalLines.FENCED;
2675            case 290101:
2676                return TacticalLines.MINE_LINE;
2677            case 271000:
2678                return TacticalLines.UXO;
2679            case 271700:
2680                return TacticalLines.BIO;
2681            case 271701:
2682                return TacticalLines.BIOT;
2683            case 271800:
2684                return TacticalLines.CHEM;
2685            case 271801:
2686                return TacticalLines.CHEMT;
2687            case 271900:
2688                return TacticalLines.NUC;
2689            case 272000:
2690                return TacticalLines.RAD;
2691            case 272001:
2692                return TacticalLines.RADT;
2693            case 290400:
2694                return TacticalLines.CLUSTER;
2695            case 290500:
2696                return TacticalLines.TRIP;
2697            case 282003:
2698                return TacticalLines.OVERHEAD_WIRE;
2699            case 271300:
2700                return TacticalLines.ASLTXING;
2701            case 271500:
2702                return TacticalLines.FORDSITE;
2703            case 271600:
2704                return TacticalLines.FORDIF;
2705            case 290700:
2706                return TacticalLines.FERRY;
2707            case 290800:
2708                return TacticalLines.RAFT;
2709            case 290900:
2710                return TacticalLines.FORTL;
2711            case 291000:
2712                return TacticalLines.FOXHOLE;
2713            case 272100:
2714                return TacticalLines.MSDZ;
2715            case 272200:
2716                return TacticalLines.DRCL;
2717
2718            case 310200:
2719                return TacticalLines.EPW;
2720            case 310300:
2721                return TacticalLines.FARP;
2722            case 310400:
2723                return TacticalLines.RHA;
2724            case 310500:
2725                return TacticalLines.RSA;
2726            case 310600:
2727                return TacticalLines.BSA;
2728            case 310700:
2729                return TacticalLines.DSA;
2730            case 330100:
2731                return TacticalLines.CONVOY;
2732            case 330200:
2733                return TacticalLines.HCONVOY;
2734            case 330300:
2735                return TacticalLines.MSR;
2736            case 330301:
2737                return TacticalLines.MSR_ONEWAY;
2738            case 330401:
2739                return TacticalLines.ASR_ONEWAY;
2740            case 330302:
2741                return TacticalLines.MSR_TWOWAY;
2742            case 330402:
2743                return TacticalLines.ASR_TWOWAY;
2744            case 330303:
2745                return TacticalLines.MSR_ALT;
2746            case 330403:
2747                return TacticalLines.ASR_ALT;
2748
2749            case 330400:
2750                return TacticalLines.ASR;
2751
2752            case 340100:
2753                return TacticalLines.BLOCK;
2754            case 340200:
2755                return TacticalLines.BREACH;
2756            case 340300:
2757                return TacticalLines.BYPASS;
2758            case 340400:
2759                return TacticalLines.CANALIZE;
2760            case 340500:
2761                return TacticalLines.CLEAR;
2762            case 340600:
2763                return TacticalLines.CATK;
2764            case 340700:
2765                return TacticalLines.CATKBYFIRE;
2766
2767            case 340800:
2768                return TacticalLines.DELAY;
2769            case 341000:
2770                return TacticalLines.DISRUPT;
2771            case 341100:
2772                return TacticalLines.FIX;
2773            case 341200:
2774                return TacticalLines.FOLLA;
2775            case 341300:
2776                return TacticalLines.FOLSP;
2777            case 341500:
2778                return TacticalLines.ISOLATE;
2779            case 341700:
2780                return TacticalLines.OCCUPY;
2781            case 341800:
2782                return TacticalLines.PENETRATE;
2783            case 341900:
2784                return TacticalLines.RIP;
2785            case 342000:
2786                return TacticalLines.RETIRE;
2787            case 342100:
2788                return TacticalLines.SECURE;
2789            case 343200:
2790                return TacticalLines.CONTROL;
2791            case 343900:
2792                return TacticalLines.LOCATE;
2793            case 342201:
2794                return TacticalLines.COVER;
2795            case 342202:
2796                return TacticalLines.GUARD;
2797            case 342203:
2798                return TacticalLines.SCREEN;
2799            case 342300:
2800                return TacticalLines.SEIZE;
2801            case 343000:
2802                return TacticalLines.CAPTURE;
2803            case 343600:
2804                return TacticalLines.ESCORT;
2805            case 342400:
2806                return TacticalLines.WITHDRAW;
2807            case 342500:
2808                return TacticalLines.WDRAWUP;
2809            case 342600:
2810                return TacticalLines.CORDONKNOCK;
2811            case 342700:
2812                return TacticalLines.CORDONSEARCH;
2813            case 343400:
2814                return TacticalLines.DENY;
2815            case 272101:
2816                return TacticalLines.STRIKWARN;
2817            default:
2818                break;
2819        }
2820        return -1;
2821    }
2822
2823    /**
2824     * Some symbol's points are reversed when moving from 2525C to 2525D. This method should be called at the start of each render.
2825     *
2826     * It's a simpler fix to reverse the points order at start than to reverse order when rendering.
2827     *
2828     * Note: Make sure to only call once to not reverse reversed points
2829     * @param tg
2830     */
2831    private static void reversePointsRevD(TGLight tg) {
2832        try {
2833            if (tg.get_SymbolId().length() < 20 || SymbolID.getSymbolSet(tg.get_SymbolId()) != 25) {
2834                return;
2835            }
2836            switch (tg.get_LineType()) {
2837                case TacticalLines.UNSP:
2838                case TacticalLines.LWFENCE:
2839                case TacticalLines.HWFENCE:
2840                case TacticalLines.SINGLEC:
2841                case TacticalLines.DOUBLEC:
2842                case TacticalLines.TRIPLE:
2843                case TacticalLines.LINE:
2844                    if (tg.Pixels != null) {
2845                        Collections.reverse(tg.Pixels);
2846                    }
2847                    if (tg.LatLongs != null) {
2848                        Collections.reverse(tg.LatLongs);
2849                    }
2850                    break;
2851                case TacticalLines.CLUSTER:
2852                    if (SymbolID.getVersion(tg.get_SymbolId()) < SymbolID.Version_2525E) {
2853                        if (tg.Pixels != null) {
2854                            Collections.reverse(tg.Pixels);
2855                        }
2856                        if (tg.LatLongs != null) {
2857                            Collections.reverse(tg.LatLongs);
2858                        }
2859                    }
2860                    break;
2861                default:
2862                    break;
2863            }
2864        } catch (Exception exc) {
2865            ErrorLogger.LogException("clsRenderer", "reversePointsRevD",
2866                    new RendererException("Failed inside reversePointsRevD", exc));
2867        }
2868    }
2869}