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