001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package armyc2.c5isr.JavaTacticalRenderer;
006
007import armyc2.c5isr.JavaLineArray.TacticalLines;
008import armyc2.c5isr.JavaLineArray.arraysupport;
009import armyc2.c5isr.JavaLineArray.lineutility;
010import armyc2.c5isr.JavaLineArray.POINT2;
011import armyc2.c5isr.JavaLineArray.ref;
012import java.util.ArrayList;
013import java.util.HashMap;
014
015import armyc2.c5isr.JavaLineArray.Shape2;
016import java.io.*;
017
018import armyc2.c5isr.RenderMultipoints.clsRenderer;
019import armyc2.c5isr.renderer.utilities.DrawRules;
020import armyc2.c5isr.renderer.utilities.IPointConversion;
021import armyc2.c5isr.renderer.utilities.MSInfo;
022import armyc2.c5isr.renderer.utilities.MSLookup;
023import armyc2.c5isr.renderer.utilities.RendererUtilities;
024import armyc2.c5isr.renderer.utilities.ErrorLogger;
025import armyc2.c5isr.renderer.utilities.RendererException;
026import armyc2.c5isr.renderer.utilities.Color;
027import armyc2.c5isr.graphics2d.BasicStroke;
028import armyc2.c5isr.graphics2d.BufferedImage;
029import armyc2.c5isr.graphics2d.Graphics2D;
030import armyc2.c5isr.graphics2d.Line2D;
031import armyc2.c5isr.graphics2d.Point2D;
032import armyc2.c5isr.graphics2d.Polygon;
033import armyc2.c5isr.graphics2d.Rectangle2D;
034import armyc2.c5isr.graphics2d.TexturePaint;
035import armyc2.c5isr.renderer.utilities.SymbolID;
036
037/**
038 * A general utility class for the tactical renderer
039*
040 */
041public final class clsUtility {
042    private static final String _className = "clsUtility";
043    protected static Point2D POINT2ToPoint2D(POINT2 pt2) {
044        if (pt2 == null) {
045            return null;
046        }
047
048        double x = pt2.x;
049        double y = pt2.y;
050        Point2D pt = new Point2D.Double(x, y);
051        return pt;
052    }
053    /**
054     * returns true if the line segments are all outside the bounds
055     * @param tg the tactical graphic
056     * @param clipBounds the pixels based clip bounds
057     * @return 
058     */
059    public static boolean linesOutsideClipBounds(TGLight tg,
060            Rectangle2D clipBounds)
061    {
062        try
063        {
064            boolean isAutoshape=isAutoshape(tg);
065            if(isAutoshape)
066                return false;
067
068            double xmin=clipBounds.getMinX();
069            double xmax=clipBounds.getMaxX();
070            double ymin=clipBounds.getMinY();
071            double ymax=clipBounds.getMaxY();
072            int j=0;
073            POINT2 pt0=null,pt1=null;
074            Line2D boundsEdge=null,ptsLine=null;
075            int n=tg.Pixels.size();
076            //for(j=0;j<tg.Pixels.size()-1;j++)
077            for(j=0;j<n-1;j++)
078            {
079                pt0=tg.Pixels.get(j);
080                pt1=tg.Pixels.get(j+1);
081                
082                //if either point is inside the bounds return false
083                if(clipBounds.contains(pt0.x, pt0.y))
084                    return false;
085                if(clipBounds.contains(pt1.x, pt1.y))
086                    return false;
087                
088                ptsLine=new Line2D.Double(pt0.x,pt0.y,pt1.x,pt1.y);
089                
090                //if the pt0-pt1 line intersects any clip bounds edge then return false
091                boundsEdge=new Line2D.Double(xmin,ymin,xmax,ymin);
092                if(ptsLine.intersectsLine(boundsEdge))
093                    return false;                
094                
095                boundsEdge=new Line2D.Double(xmax,ymin,xmax,ymax);
096                if(ptsLine.intersectsLine(boundsEdge))
097                    return false;                
098                
099                boundsEdge=new Line2D.Double(xmax,ymax,xmin,ymax);
100                if(ptsLine.intersectsLine(boundsEdge))
101                    return false;                
102                
103                boundsEdge=new Line2D.Double(xmin,ymax,xmin,ymin);
104                if(ptsLine.intersectsLine(boundsEdge))
105                    return false;                
106            }
107        }
108        catch (Exception exc) 
109        {
110            ErrorLogger.LogException(_className ,"linesOutsideClipBounds",
111                    new RendererException("Failed inside linesOutsideClipBounds", exc));
112        }    
113        return true;
114    }
115    /**
116     * Returns the minimum client points needed for the symbol
117     * @param lineType line type
118     * @return minimum number of clients required to render the line
119     * @deprecated use MSInfo.getMinPointCount()
120     */
121    public static int GetMinPoints(int lineType) {
122        int result = -1;
123        switch (lineType) {
124            case TacticalLines.RECTANGULAR:
125            case TacticalLines.CUED_ACQUISITION:
126            case TacticalLines.CIRCULAR:
127            case TacticalLines.PBS_CIRCLE:
128            case TacticalLines.BDZ:
129            case TacticalLines.FSA_CIRCULAR:
130            case TacticalLines.NOTACK:
131            case TacticalLines.FFA_CIRCULAR:
132            case TacticalLines.NFA_CIRCULAR:
133            case TacticalLines.RFA_CIRCULAR:
134            case TacticalLines.ACA_CIRCULAR:
135            case TacticalLines.PAA_CIRCULAR:
136            case TacticalLines.ATI_CIRCULAR:
137            case TacticalLines.CFFZ_CIRCULAR:
138            case TacticalLines.SENSOR_CIRCULAR:
139            case TacticalLines.CENSOR_CIRCULAR:
140            case TacticalLines.DA_CIRCULAR:
141            case TacticalLines.CFZ_CIRCULAR:
142            case TacticalLines.ZOR_CIRCULAR:
143            case TacticalLines.TBA_CIRCULAR:
144            case TacticalLines.TVAR_CIRCULAR:
145            case TacticalLines.KILLBOXBLUE_CIRCULAR:
146            case TacticalLines.KILLBOXPURPLE_CIRCULAR:
147            case TacticalLines.LAUNCH_AREA:
148            case TacticalLines.DEFENDED_AREA_CIRCULAR:
149            case TacticalLines.SHIP_AOI_CIRCULAR:
150            case TacticalLines.PBS_ELLIPSE:
151            case TacticalLines.RANGE_FAN:
152            case TacticalLines.RANGE_FAN_SECTOR:
153            case TacticalLines.RADAR_SEARCH:
154                result = 1;
155                break;
156            case TacticalLines.PAA_RECTANGULAR:
157            case TacticalLines.RECTANGULAR_TARGET:
158            case TacticalLines.FSA_RECTANGULAR:
159            case TacticalLines.SHIP_AOI_RECTANGULAR:
160            case TacticalLines.DEFENDED_AREA_RECTANGULAR:
161            case TacticalLines.FFA_RECTANGULAR:
162            case TacticalLines.RFA_RECTANGULAR:
163            case TacticalLines.NFA_RECTANGULAR:
164            case TacticalLines.ACA_RECTANGULAR:
165            case TacticalLines.ATI_RECTANGULAR:
166            case TacticalLines.CFFZ_RECTANGULAR:
167            case TacticalLines.SENSOR_RECTANGULAR:
168            case TacticalLines.CENSOR_RECTANGULAR:
169            case TacticalLines.DA_RECTANGULAR:
170            case TacticalLines.CFZ_RECTANGULAR:
171            case TacticalLines.ZOR_RECTANGULAR:
172            case TacticalLines.TBA_RECTANGULAR:
173            case TacticalLines.TVAR_RECTANGULAR:
174            case TacticalLines.KILLBOXBLUE_RECTANGULAR:
175            case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
176                result = 2; //was 3
177                break;
178            case TacticalLines.SPTBYFIRE:
179            case TacticalLines.RIP:
180            case TacticalLines.MOBILE_DEFENSE:
181            case TacticalLines.DEMONSTRATE:
182            case TacticalLines.GAP:
183            case TacticalLines.ASLTXING:
184            case TacticalLines.MSDZ:
185                result = 4;
186                break;
187            case TacticalLines.BYPASS:
188            case TacticalLines.BLOCK:
189            case TacticalLines.BREACH:
190            case TacticalLines.CANALIZE:
191            case TacticalLines.CLEAR:
192            case TacticalLines.CONTAIN:
193            case TacticalLines.DELAY:
194            case TacticalLines.DISRUPT:
195            case TacticalLines.PENETRATE:
196            case TacticalLines.RETIRE:
197            case TacticalLines.PURSUIT:
198            case TacticalLines.ENVELOPMENT:
199            case TacticalLines.FPOL:
200            case TacticalLines.RPOL:
201            case TacticalLines.SCREEN:
202            case TacticalLines.COVER:
203            case TacticalLines.GUARD:
204            case TacticalLines.SEIZE:
205            case TacticalLines.CAPTURE:
206            case TacticalLines.ESCORT:
207            case TacticalLines.EVACUATE:
208            case TacticalLines.WITHDRAW:
209            case TacticalLines.DISENGAGE:
210            case TacticalLines.WDRAWUP:
211            //non task autoshapes
212            case TacticalLines.SARA:
213            case TacticalLines.DECEIVE:
214            case TacticalLines.PDF:
215            case TacticalLines.IL:
216            case TacticalLines.ATKBYFIRE:
217            case TacticalLines.AMBUSH:
218            case TacticalLines.RELEASE:
219            case TacticalLines.HOL:
220            case TacticalLines.BHL:
221            case TacticalLines.MNFLDBLK:
222            case TacticalLines.MNFLDDIS:
223            case TacticalLines.TURN_REVD:
224            case TacticalLines.TURN:
225            case TacticalLines.PLANNED:
226            case TacticalLines.ESR1:
227            case TacticalLines.ESR2:
228            case TacticalLines.ROADBLK:
229            case TacticalLines.EASY:
230            case TacticalLines.BYDIF:
231            case TacticalLines.BYIMP:
232            case TacticalLines.FORDSITE:
233            case TacticalLines.FORDIF:
234            //METOCs
235            case TacticalLines.IFR:
236            case TacticalLines.MVFR:
237            case TacticalLines.TURBULENCE:
238            case TacticalLines.ICING:
239            case TacticalLines.NON_CONVECTIVE:
240            case TacticalLines.CONVECTIVE:
241            case TacticalLines.FROZEN:
242            case TacticalLines.THUNDERSTORMS:
243            case TacticalLines.FOG:
244            case TacticalLines.SAND:
245            case TacticalLines.FREEFORM:
246            case TacticalLines.DEPTH_AREA:
247            case TacticalLines.ISLAND:
248            case TacticalLines.BEACH:
249            case TacticalLines.WATER:
250            case TacticalLines.FISH_TRAPS:
251            case TacticalLines.SWEPT_AREA:
252            case TacticalLines.OIL_RIG_FIELD:
253            case TacticalLines.FOUL_GROUND:
254            case TacticalLines.KELP:
255            case TacticalLines.BEACH_SLOPE_MODERATE:
256            case TacticalLines.BEACH_SLOPE_STEEP:
257            case TacticalLines.ANCHORAGE_AREA:
258            case TacticalLines.TRAINING_AREA:
259            case TacticalLines.FORESHORE_AREA:
260            case TacticalLines.DRYDOCK:
261            case TacticalLines.LOADING_FACILITY_AREA:
262            case TacticalLines.PERCHES:
263            case TacticalLines.UNDERWATER_HAZARD:
264            case TacticalLines.DISCOLORED_WATER:
265            case TacticalLines.BEACH_SLOPE_FLAT:
266            case TacticalLines.BEACH_SLOPE_GENTLE:
267            case TacticalLines.MARITIME_AREA:
268            case TacticalLines.OPERATOR_DEFINED:
269            case TacticalLines.SUBMERGED_CRIB:
270            case TacticalLines.VDR_LEVEL_12:
271            case TacticalLines.VDR_LEVEL_23:
272            case TacticalLines.VDR_LEVEL_34:
273            case TacticalLines.VDR_LEVEL_45:
274            case TacticalLines.VDR_LEVEL_56:
275            case TacticalLines.VDR_LEVEL_67:
276            case TacticalLines.VDR_LEVEL_78:
277            case TacticalLines.VDR_LEVEL_89:
278            case TacticalLines.VDR_LEVEL_910:
279            case TacticalLines.SOLID_ROCK:
280            case TacticalLines.CLAY:
281            case TacticalLines.VERY_COARSE_SAND:
282            case TacticalLines.COARSE_SAND:
283            case TacticalLines.MEDIUM_SAND:
284            case TacticalLines.FINE_SAND:
285            case TacticalLines.VERY_FINE_SAND:
286            case TacticalLines.VERY_FINE_SILT:
287            case TacticalLines.FINE_SILT:
288            case TacticalLines.MEDIUM_SILT:
289            case TacticalLines.COARSE_SILT:
290            case TacticalLines.BOULDERS:
291            case TacticalLines.OYSTER_SHELLS:
292            case TacticalLines.PEBBLES:
293            case TacticalLines.SAND_AND_SHELLS:
294            case TacticalLines.BOTTOM_SEDIMENTS_LAND:
295            case TacticalLines.BOTTOM_SEDIMENTS_NO_DATA:
296            case TacticalLines.BOTTOM_ROUGHNESS_SMOOTH:
297            case TacticalLines.BOTTOM_ROUGHNESS_MODERATE:
298            case TacticalLines.BOTTOM_ROUGHNESS_ROUGH:
299            case TacticalLines.CLUTTER_LOW:
300            case TacticalLines.CLUTTER_MEDIUM:
301            case TacticalLines.CLUTTER_HIGH:
302            case TacticalLines.IMPACT_BURIAL_0:
303            case TacticalLines.IMPACT_BURIAL_10:
304            case TacticalLines.IMPACT_BURIAL_20:
305            case TacticalLines.IMPACT_BURIAL_75:
306            case TacticalLines.IMPACT_BURIAL_100:
307            case TacticalLines.BOTTOM_CATEGORY_A:
308            case TacticalLines.BOTTOM_CATEGORY_B:
309            case TacticalLines.BOTTOM_CATEGORY_C:
310            case TacticalLines.BOTTOM_TYPE_A1:
311            case TacticalLines.BOTTOM_TYPE_A2:
312            case TacticalLines.BOTTOM_TYPE_A3:
313            case TacticalLines.BOTTOM_TYPE_B1:
314            case TacticalLines.BOTTOM_TYPE_B2:
315            case TacticalLines.BOTTOM_TYPE_B3:
316            case TacticalLines.BOTTOM_TYPE_C1:
317            case TacticalLines.BOTTOM_TYPE_C2:
318            case TacticalLines.BOTTOM_TYPE_C3:
319                result = 3;
320                break;
321            case TacticalLines.MRR:
322            case TacticalLines.SL:
323            case TacticalLines.TC:
324            case TacticalLines.SC:
325            case TacticalLines.LLTR:
326            case TacticalLines.DIRATKAIR:
327            case TacticalLines.ABATIS:
328            case TacticalLines.CLUSTER:
329            case TacticalLines.MNFLDFIX:
330            case TacticalLines.FERRY:
331            case TacticalLines.MFLANE:
332            case TacticalLines.RAFT:
333            case TacticalLines.FOXHOLE:
334            case TacticalLines.LINTGT:
335            case TacticalLines.LINTGTS:
336            case TacticalLines.FPF:
337            case TacticalLines.CONVOY:
338            case TacticalLines.HCONVOY:
339                result = 2;
340                break;
341            default:
342                result = 2;
343                break;
344        }
345        if (isClosedPolygon(lineType)) {
346            result = 3;
347        }
348        //add code for change 1 areas
349        return result;
350    }
351    /**
352     * @param linetype line type
353     * @return true if the line is a closed area
354     */
355    public static boolean isClosedPolygon(int linetype) {
356        boolean result = false;
357        switch (linetype) {
358            case TacticalLines.BBS_AREA:
359            case TacticalLines.BS_BBOX:
360            case TacticalLines.AT:
361            case TacticalLines.DEPICT:
362            case TacticalLines.DZ:
363            case TacticalLines.MINED:
364            case TacticalLines.FENCED:
365            case TacticalLines.UXO:
366            case TacticalLines.ROZ:
367            case TacticalLines.AARROZ:
368            case TacticalLines.UAROZ:
369            case TacticalLines.WEZ:
370            case TacticalLines.FEZ:
371            case TacticalLines.JEZ:
372            case TacticalLines.FAADZ:
373            case TacticalLines.HIDACZ:
374            case TacticalLines.MEZ:
375            case TacticalLines.LOMEZ:
376            case TacticalLines.HIMEZ:
377            case TacticalLines.WFZ_REVD:
378            case TacticalLines.WFZ:
379            case TacticalLines.PNO:
380            case TacticalLines.BATTLE:
381            case TacticalLines.EA:
382            case TacticalLines.EZ:
383            case TacticalLines.LZ:
384            case TacticalLines.PZ:
385            case TacticalLines.GENERAL:
386            case TacticalLines.JTAA:
387            case TacticalLines.SAA:
388            case TacticalLines.SGAA:
389            case TacticalLines.BS_AREA:
390            case TacticalLines.ASSAULT:
391            case TacticalLines.ATKPOS:
392            case TacticalLines.OBJ:
393            case TacticalLines.AO:
394            case TacticalLines.AIRHEAD:
395            case TacticalLines.NAI:
396            case TacticalLines.TAI:
397            case TacticalLines.BASE_CAMP_REVD:
398            case TacticalLines.BASE_CAMP:
399            case TacticalLines.GUERILLA_BASE_REVD:
400            case TacticalLines.GUERILLA_BASE:
401            case TacticalLines.GENERIC_AREA:
402            case TacticalLines.OBSFAREA:
403            case TacticalLines.OBSAREA:
404            case TacticalLines.ZONE:
405            case TacticalLines.STRONG:
406            case TacticalLines.DRCL:
407            case TacticalLines.FSA:
408            case TacticalLines.ACA:
409            case TacticalLines.ASSY:
410            case TacticalLines.BSA:
411            case TacticalLines.NFA:
412            case TacticalLines.RFA:
413            case TacticalLines.FARP:
414            case TacticalLines.AIRFIELD:
415            case TacticalLines.LAA:
416            case TacticalLines.BOMB:
417            case TacticalLines.FFA:
418            case TacticalLines.SMOKE:
419            case TacticalLines.PAA:
420            case TacticalLines.ENCIRCLE:
421            case TacticalLines.DHA_REVD:
422            case TacticalLines.DHA:
423            case TacticalLines.KILL_ZONE:
424            case TacticalLines.EPW:
425            case TacticalLines.RHA:
426            case TacticalLines.DSA:
427            case TacticalLines.CSA:
428            case TacticalLines.RSA:
429            case TacticalLines.FORT_REVD:
430            case TacticalLines.FORT:
431            case TacticalLines.PEN:
432            case TacticalLines.BIO:
433            case TacticalLines.BIOT:
434            case TacticalLines.NUC:
435            case TacticalLines.RAD:
436            case TacticalLines.RADT:
437            case TacticalLines.CHEM:
438            case TacticalLines.CHEMT:
439            case TacticalLines.SERIES:
440            case TacticalLines.ATI:
441            case TacticalLines.TBA:
442            case TacticalLines.TVAR:
443            case TacticalLines.CFFZ:
444            case TacticalLines.CENSOR:
445            case TacticalLines.SENSOR:
446            case TacticalLines.ZOR:
447            case TacticalLines.DA:
448            case TacticalLines.CFZ:
449            case TacticalLines.KILLBOXBLUE:
450            case TacticalLines.KILLBOXPURPLE:
451            //METOCs
452            case TacticalLines.IFR:
453            case TacticalLines.MVFR:
454            case TacticalLines.TURBULENCE:
455            case TacticalLines.ICING:
456            case TacticalLines.NON_CONVECTIVE:
457            case TacticalLines.CONVECTIVE:
458            case TacticalLines.FROZEN:
459            case TacticalLines.THUNDERSTORMS:
460            case TacticalLines.FOG:
461            case TacticalLines.SAND:
462            case TacticalLines.FREEFORM:
463            case TacticalLines.DEPTH_AREA:
464            case TacticalLines.ISLAND:
465            case TacticalLines.BEACH:
466            case TacticalLines.WATER:
467            case TacticalLines.FISH_TRAPS:
468            case TacticalLines.SWEPT_AREA:
469            case TacticalLines.OIL_RIG_FIELD:
470            case TacticalLines.FOUL_GROUND:
471            case TacticalLines.KELP:
472            case TacticalLines.BEACH_SLOPE_MODERATE:
473            case TacticalLines.BEACH_SLOPE_STEEP:
474            case TacticalLines.ANCHORAGE_AREA:
475            case TacticalLines.TRAINING_AREA:
476            case TacticalLines.FORESHORE_AREA:
477            case TacticalLines.DRYDOCK:
478            case TacticalLines.LOADING_FACILITY_AREA:
479            case TacticalLines.PERCHES:
480            case TacticalLines.UNDERWATER_HAZARD:
481            case TacticalLines.DISCOLORED_WATER:
482            case TacticalLines.BEACH_SLOPE_FLAT:
483            case TacticalLines.BEACH_SLOPE_GENTLE:
484            case TacticalLines.MARITIME_AREA:
485            case TacticalLines.OPERATOR_DEFINED:
486            case TacticalLines.SUBMERGED_CRIB:
487            case TacticalLines.VDR_LEVEL_12:
488            case TacticalLines.VDR_LEVEL_23:
489            case TacticalLines.VDR_LEVEL_34:
490            case TacticalLines.VDR_LEVEL_45:
491            case TacticalLines.VDR_LEVEL_56:
492            case TacticalLines.VDR_LEVEL_67:
493            case TacticalLines.VDR_LEVEL_78:
494            case TacticalLines.VDR_LEVEL_89:
495            case TacticalLines.VDR_LEVEL_910:
496            case TacticalLines.SOLID_ROCK:
497            case TacticalLines.CLAY:
498            case TacticalLines.VERY_COARSE_SAND:
499            case TacticalLines.COARSE_SAND:
500            case TacticalLines.MEDIUM_SAND:
501            case TacticalLines.FINE_SAND:
502            case TacticalLines.VERY_FINE_SAND:
503            case TacticalLines.VERY_FINE_SILT:
504            case TacticalLines.FINE_SILT:
505            case TacticalLines.MEDIUM_SILT:
506            case TacticalLines.COARSE_SILT:
507            case TacticalLines.BOULDERS:
508            case TacticalLines.OYSTER_SHELLS:
509            case TacticalLines.PEBBLES:
510            case TacticalLines.SAND_AND_SHELLS:
511            case TacticalLines.BOTTOM_SEDIMENTS_LAND:
512            case TacticalLines.BOTTOM_SEDIMENTS_NO_DATA:
513            case TacticalLines.BOTTOM_ROUGHNESS_SMOOTH:
514            case TacticalLines.BOTTOM_ROUGHNESS_MODERATE:
515            case TacticalLines.BOTTOM_ROUGHNESS_ROUGH:
516            case TacticalLines.CLUTTER_LOW:
517            case TacticalLines.CLUTTER_MEDIUM:
518            case TacticalLines.CLUTTER_HIGH:
519            case TacticalLines.IMPACT_BURIAL_0:
520            case TacticalLines.IMPACT_BURIAL_10:
521            case TacticalLines.IMPACT_BURIAL_20:
522            case TacticalLines.IMPACT_BURIAL_75:
523            case TacticalLines.IMPACT_BURIAL_100:
524            case TacticalLines.BOTTOM_CATEGORY_A:
525            case TacticalLines.BOTTOM_CATEGORY_B:
526            case TacticalLines.BOTTOM_CATEGORY_C:
527            case TacticalLines.BOTTOM_TYPE_A1:
528            case TacticalLines.BOTTOM_TYPE_A2:
529            case TacticalLines.BOTTOM_TYPE_A3:
530            case TacticalLines.BOTTOM_TYPE_B1:
531            case TacticalLines.BOTTOM_TYPE_B2:
532            case TacticalLines.BOTTOM_TYPE_B3:
533            case TacticalLines.BOTTOM_TYPE_C1:
534            case TacticalLines.BOTTOM_TYPE_C2:
535            case TacticalLines.BOTTOM_TYPE_C3:
536            case TacticalLines.TGMF:
537                result = true;
538                break;
539            default:
540                break;
541        }
542        return result;
543    }
544
545    /**
546     * Closes the polygon for areas
547     * @param Pixels the client points
548     */
549    public static void ClosePolygon(ArrayList<POINT2> Pixels) {
550        try {
551            POINT2 pt0 = Pixels.get(0);
552            POINT2 pt1 = Pixels.get(Pixels.size() - 1);
553            if (pt0.x != pt1.x || pt0.y != pt1.y) {
554                Pixels.add(new POINT2(pt0.x, pt0.y));
555            }
556        } catch (Exception exc) {
557               ErrorLogger.LogException(_className ,"ClosePolygon",
558                    new RendererException("Failed inside ClosePolygon", exc));
559        }
560    }
561    /**
562     * for change 1 symbol the W/w1 modifiers run too close to the symbol outline
563     * so it shifts the line along the line away from the edge
564     * @param p1
565     * @param p2
566     * @param shift
567     */
568    protected static void shiftModifiersLeft(POINT2 p1, POINT2 p2, double shift)
569    {
570        try
571        {
572            POINT2 pt1=new POINT2(p1);
573            POINT2 pt2=new POINT2(p2);
574            double dist=lineutility.CalcDistanceDouble(pt1, pt2);
575            if(pt1.x<pt2.x || (pt1.x==pt2.x && pt1.y<pt2.y))
576            {
577                pt1=lineutility.ExtendAlongLineDouble(pt2, pt1, dist+shift);
578                pt2=lineutility.ExtendAlongLineDouble(pt1, pt2, dist-shift);
579            }
580            else
581            {
582                pt1=lineutility.ExtendAlongLineDouble(pt2, pt1, dist-shift);
583                pt2=lineutility.ExtendAlongLineDouble(pt1, pt2, dist+shift);
584            }
585            p1.x=pt1.x;
586            p1.y=pt1.y;
587            p2.x=pt2.x;
588            p2.y=pt2.y;
589        }
590        catch (Exception exc) {
591               ErrorLogger.LogException(_className ,"shiftModifiersLeft",
592                    new RendererException("Failed inside shiftModifiersLeft", exc));
593        }
594    }
595    /**
596     * Overrides shape properties for symbols based on Mil-Std-2525
597     * @param tg
598     * @param shape
599     */
600    protected static void ResolveModifierShape(TGLight tg, Shape2 shape) {
601        try {
602            //shape style was set by CELineArray and takes precedence
603            //whenever it is set
604            int shapeStyle = shape.get_Style();
605            int lineStyle = tg.get_LineStyle();
606            int lineType = tg.get_LineType();
607            boolean hasFill=LinesWithFill(lineType);
608            int bolMETOC=clsMETOC.IsWeather(tg.get_SymbolId());
609            if(bolMETOC>0)
610                return;
611            int fillStyle=0;
612            //for some of these the style must be dashed
613            switch (tg.get_LineType()) {
614                case TacticalLines.NFA:
615                case TacticalLines.NFA_CIRCULAR:
616                case TacticalLines.NFA_RECTANGULAR:
617                case TacticalLines.BIO:
618                case TacticalLines.BIOT:
619                case TacticalLines.NUC:
620                case TacticalLines.CHEM:
621                case TacticalLines.CHEMT:
622                case TacticalLines.RAD:
623                case TacticalLines.RADT:
624                case TacticalLines.WFZ_REVD:
625                case TacticalLines.WFZ:
626                //case TacticalLines.OBSAREA:
627                    fillStyle=3;
628                    if(tg.get_UseHatchFill())
629                        fillStyle=0;
630                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
631                        shape.set_Style(tg.get_LineStyle());
632                        shape.setLineColor(tg.get_LineColor());
633                        shape.set_Fillstyle(fillStyle /*GraphicProperties.FILL_TYPE_RIGHT_SLANTS*/);//was 3
634                        shape.setFillColor(tg.get_FillColor());
635                    }
636                    break;
637                case TacticalLines.OBSAREA:
638                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
639                        shape.set_Style(tg.get_LineStyle());
640                        shape.setLineColor(tg.get_LineColor());
641                        shape.set_Fillstyle(0 /*GraphicProperties.FILL_TYPE_RIGHT_SLANTS*/);
642                        shape.setFillColor(tg.get_FillColor());
643                    }
644                    break;
645                case TacticalLines.LAA:
646                    fillStyle=2;
647                    if(tg.get_UseHatchFill())
648                        fillStyle=0;
649                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
650                        shape.set_Style(tg.get_LineStyle());
651                        shape.setLineColor(tg.get_LineColor());
652                        shape.set_Fillstyle(fillStyle /*GraphicProperties.FILL_TYPE_LEFT_SLANTS*/);//was 2
653                        shape.setFillColor(tg.get_FillColor());
654                    }
655                    break;
656                case TacticalLines.DIRATKAIR:
657                case TacticalLines.ATDITCHC:
658                case TacticalLines.ATDITCHM:
659                case TacticalLines.SARA:
660                case TacticalLines.FOLSP:
661                case TacticalLines.FERRY:
662                case TacticalLines.MNFLDFIX:
663                case TacticalLines.TURN_REVD:
664                case TacticalLines.TURN:
665                case TacticalLines.MNFLDDIS:
666                case TacticalLines.EASY:
667                case TacticalLines.BYDIF:
668                case TacticalLines.BYIMP:
669                case TacticalLines.MOBILE_DEFENSE:
670                    tg.set_lineCap(BasicStroke.CAP_BUTT);
671                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_FILL) {
672                        shape.set_Fillstyle(1 /*GraphicProperties.FILL_TYPE_SOLID*/);
673                        shape.setFillColor(tg.get_LineColor());
674                    }
675                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
676                        shape.set_Style(tg.get_LineStyle());
677                        shape.setLineColor(tg.get_LineColor());
678                    }
679                    break;
680                case TacticalLines.DECEIVE:
681                case TacticalLines.CLUSTER:
682                case TacticalLines.CATK:
683                case TacticalLines.CATKBYFIRE:
684                case TacticalLines.PLD:
685                case TacticalLines.PLANNED:
686                case TacticalLines.CFL:
687                case TacticalLines.FORDSITE:
688                case TacticalLines.ACOUSTIC_AMB:
689                    //any shape for these symbols is dashed
690                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
691                        shape.set_Style(1 /*GraphicProperties.LINE_TYPE_DASHED*/);
692                        shape.setLineColor(tg.get_LineColor());
693                    }
694                    break;
695                case TacticalLines.PNO: //always dashed
696                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
697                        shape.set_Style(1 /*GraphicProperties.LINE_TYPE_DASHED*/);
698                        shape.setLineColor(tg.get_LineColor());
699                        shape.setFillColor(tg.get_FillColor());
700                        shape.set_Fillstyle(tg.get_FillStyle());
701                    }
702                    break;
703                case TacticalLines.FOLLA:
704                case TacticalLines.ESR1:
705                case TacticalLines.FORDIF:
706                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
707                        shape.setLineColor(tg.get_LineColor());
708                        if (shapeStyle != lineStyle) {
709                            if (shapeStyle != 1 /*GraphicProperties.LINE_TYPE_DASHED*/) {
710                                shape.set_Style(lineStyle);
711                            }
712                        }
713                    }
714                    break;
715                case TacticalLines.AREA_DEFENSE:
716                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_FILL) {
717                        shape.set_Fillstyle(tg.get_FillStyle());
718                        shape.setFillColor(tg.get_FillColor());
719                        // If there are 5 points and the first and last are the same this is
720                        // a triangle and should be filled with line color
721                        POINT2 firstPt = shape.getPoints().get(0);
722                        POINT2 lastPt = shape.getPoints().get(shape.getPoints().size() - 1);
723                        if (shape.getPoints().size() == 5 && firstPt.x == lastPt.x && firstPt.y == lastPt.y) {
724                            shape.set_Fillstyle(1);
725                            shape.setFillColor(tg.get_LineColor());
726                        }
727                    }
728                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
729                        shape.setLineColor(tg.get_LineColor());
730                        shape.set_Style(lineStyle);
731                        if (hasFill || clsUtility.isClosedPolygon(lineType) || clsUtility.IsChange1Area(lineType)) {
732                            shape.set_Fillstyle(tg.get_FillStyle());
733                            shape.setFillColor(tg.get_FillColor());
734                        }
735                    }
736                    break;
737                case TacticalLines.MOVEMENT_TO_CONTACT:
738                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_FILL) {
739                        shape.set_Fillstyle(tg.get_FillStyle());
740                        shape.setFillColor(tg.get_FillColor());
741                        // If there are 4 points and the first and last are the same this is
742                        // an arrow at the end of a jaggy line and should be filled with line color
743                        POINT2 firstPt = shape.getPoints().get(0);
744                        POINT2 lastPt = shape.getPoints().get(shape.getPoints().size() - 1);
745                        if (shape.getPoints().size() == 4 && firstPt.x == lastPt.x && firstPt.y == lastPt.y)
746                            shape.setFillColor(tg.get_LineColor());
747                    }
748                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
749                        shape.setLineColor(tg.get_LineColor());
750                        shape.set_Style(lineStyle);
751                    }
752                    break;
753                case TacticalLines.EXPLOIT:
754                    // Some shapes have solid lines some have dashed
755                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_FILL) {
756                        shape.set_Fillstyle(tg.get_FillStyle());
757                        shape.setFillColor(tg.get_FillColor());
758                    }
759                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
760                        shape.setLineColor(tg.get_LineColor());
761                        if (shapeStyle != 1 /*GraphicProperties.LINE_TYPE_DASHED*/) {
762                            shape.set_Style(lineStyle);
763                        }
764                    }
765                    break;
766                default:
767                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_FILL) {
768                        shape.set_Fillstyle(tg.get_FillStyle());
769                        shape.setFillColor(tg.get_FillColor());
770                    }
771                    if (shape.getShapeType() == Shape2.SHAPE_TYPE_POLYLINE) {
772                        if (lineType != TacticalLines.LC) {
773                            shape.setLineColor(tg.get_LineColor());
774                        } else {
775                            SetLCColor(tg, shape);
776                        }
777                        shape.set_Style(lineStyle);
778                        if (hasFill || clsUtility.isClosedPolygon(lineType) || clsUtility.IsChange1Area(lineType))
779                        {
780                            switch(lineType)
781                            {
782                                case TacticalLines.RANGE_FAN:
783                                case TacticalLines.RANGE_FAN_SECTOR:
784                                case TacticalLines.RADAR_SEARCH:
785                                case TacticalLines.BBS_AREA:
786                                case TacticalLines.BBS_RECTANGLE:
787                                    shape.setFillColor(null);
788                                    break;
789                                default:
790                                    shape.set_Fillstyle(tg.get_FillStyle());
791                                    shape.setFillColor(tg.get_FillColor());
792                                    break;
793                            }
794                        }
795                        switch(lineType)
796                        {
797                            case TacticalLines.BS_ELLIPSE:
798                            case TacticalLines.BS_RECTANGLE:
799                                //case TacticalLines.BBS_RECTANGLE:
800                                shape.set_Fillstyle(tg.get_FillStyle());
801                                shape.setFillColor(tg.get_FillColor());
802                                break;
803                            case TacticalLines.BBS_RECTANGLE:
804                            case TacticalLines.PBS_RECTANGLE:
805                            case TacticalLines.PBS_SQUARE:
806                                shape.setFillColor(null);
807                                break;
808                            default:
809                                break;
810                        }
811                    }
812                    break;
813            }
814
815        } catch (Exception exc) {
816               ErrorLogger.LogException(_className ,"ResolveModifierShape",
817                    new RendererException("Failed inside ResolveModifierShape", exc));
818        }
819    }
820    public static Color GetOpaqueColor(Color color)
821    {
822        int r=color.getRed();
823        int g=color.getGreen();
824        int b=color.getBlue();
825        return new Color(r,g,b);
826    }
827    /**
828     * These lines allow fill
829     * @param linetype
830     * @return
831     */
832    public static boolean LinesWithFill(int linetype)
833    {
834        boolean result=false;
835        try
836        {
837            switch(linetype)
838            {
839                case TacticalLines.BS_LINE:
840                case TacticalLines.PAA_RECTANGULAR:
841                case TacticalLines.RECTANGULAR_TARGET:
842                case TacticalLines.CFL:
843                case TacticalLines.TRIP:
844                case TacticalLines.DIRATKAIR:
845                case TacticalLines.BOUNDARY:
846                case TacticalLines.ISOLATE:
847                case TacticalLines.CORDONKNOCK:
848                case TacticalLines.CORDONSEARCH:
849                case TacticalLines.DENY:
850                case TacticalLines.OCCUPY:
851                case TacticalLines.RETAIN:
852                case TacticalLines.SECURE:
853                case TacticalLines.CONTROL:
854                case TacticalLines.LOCATE:
855                case TacticalLines.AREA_DEFENSE:
856                case TacticalLines.MOBILE_DEFENSE:
857                case TacticalLines.FLOT:
858                case TacticalLines.LC:
859                case TacticalLines.PL:
860                case TacticalLines.FEBA:
861                case TacticalLines.LL:
862                case TacticalLines.EWL:
863//                case TacticalLines.AC:
864//                case TacticalLines.SAAFR:
865                case TacticalLines.DIRATKGND:
866                case TacticalLines.DIRATKSPT:
867                case TacticalLines.INFILTRATION:
868                case TacticalLines.FCL:
869                case TacticalLines.HOLD:
870                case TacticalLines.BRDGHD:
871                case TacticalLines.HOLD_GE:
872                case TacticalLines.BRDGHD_GE:
873                case TacticalLines.LOA:
874                case TacticalLines.LOD:
875                case TacticalLines.LDLC:
876                case TacticalLines.RELEASE:
877                case TacticalLines.HOL:
878                case TacticalLines.BHL:
879                case TacticalLines.LINE:
880                case TacticalLines.ABATIS:
881                case TacticalLines.ATDITCH:
882                case TacticalLines.ATWALL:
883                case TacticalLines.SFENCE:
884                case TacticalLines.DFENCE:
885                case TacticalLines.UNSP:
886                case TacticalLines.PLD:
887                case TacticalLines.DOUBLEA:
888                case TacticalLines.LWFENCE:
889                case TacticalLines.HWFENCE:
890                case TacticalLines.SINGLEC:
891                case TacticalLines.DOUBLEC:
892                case TacticalLines.TRIPLE:
893                case TacticalLines.FORTL:
894                case TacticalLines.LINTGT:
895                case TacticalLines.LINTGTS:
896                case TacticalLines.FSCL:
897                case TacticalLines.BCL_REVD:
898                case TacticalLines.BCL:
899                case TacticalLines.ICL:
900                case TacticalLines.IFF_OFF:
901                case TacticalLines.IFF_ON:
902                case TacticalLines.GENERIC_LINE:
903                case TacticalLines.NFL:
904                case TacticalLines.MFP:
905                case TacticalLines.RFL:
906                case TacticalLines.CONVOY:
907                case TacticalLines.HCONVOY:
908                case TacticalLines.MSR:
909                case TacticalLines.MSR_ONEWAY:
910                case TacticalLines.MSR_TWOWAY:
911                case TacticalLines.MSR_ALT:
912                case TacticalLines.ASR:
913                case TacticalLines.ASR_ONEWAY:
914                case TacticalLines.ASR_TWOWAY:
915                case TacticalLines.ASR_ALT:
916                case TacticalLines.TRAFFIC_ROUTE:
917                case TacticalLines.TRAFFIC_ROUTE_ONEWAY:
918                case TacticalLines.TRAFFIC_ROUTE_ALT:
919                    result = true;
920                    break;
921                default:
922                    result = false;
923                    break;
924            }
925        }
926        catch(Exception exc)
927        {
928               ErrorLogger.LogException(_className ,"LinesWithFill",
929                    new RendererException("Failed inside LinesWithFill", exc));
930        }
931        return result;
932    }
933    /**
934     * @deprecated
935     * if the line color and fill color are the same or very close then we want to
936     * tweak the fill color a bit to make the line appear distinct from the fill.
937     * @param tg
938     */
939    public static void tweakFillColor(TGLight tg)
940    {
941        try
942        {
943            if(isSameColor(tg.get_LineColor(),tg.get_FillColor())==false)
944                return;
945
946            Color fillColor=tg.get_FillColor();
947            int r=fillColor.getRed(),g=fillColor.getGreen(),b=fillColor.getBlue();
948            int alpha=fillColor.getAlpha();
949
950            r*=0.9;
951            g*=0.9;
952            b*=0.9;
953            alpha*=0.8;
954
955            fillColor=new Color(r,g,b,alpha);
956            tg.set_FillColor(fillColor);
957        }
958        catch(Exception exc)
959        {
960               ErrorLogger.LogException(_className ,"tweakFillColor",
961                    new RendererException("Failed inside tweakFillColor", exc));
962        }
963    }
964    /**
965     * @deprecated
966     * Test to see if two colors are similar
967     * @param c1
968     * @param c2
969     * @return true is same (or similar) color
970     */
971    public static Boolean isSameColor(Color c1, Color c2)
972    {
973        try
974        {
975            if(c1==null || c2==null)
976                return true;
977
978            int r1=c1.getRed(),r2=c2.getRed(),g1=c1.getGreen(),g2=c2.getGreen(),
979                    b1=c1.getBlue(),b2=c2.getBlue();
980
981            if(Math.abs(r1-r2)<5)
982                if(Math.abs(g1-g2)<5)
983                    if(Math.abs(b1-b2)<5)
984                        return true;
985        }
986        catch(Exception exc)
987        {
988               ErrorLogger.LogException(_className ,"isSameColor",
989                    new RendererException("Failed inside isSameColor", exc));
990        }
991        return false;
992    }
993    /**
994     * Customer requested routine for setting the stroke dash pattern
995     * Scales dash length with line width and DPI
996     * @param width
997     * @param style
998     * @param cap
999     * @param join
1000     * @return
1001     */
1002    public static BasicStroke getLineStroke(int width, int style, int cap, int join) {
1003        // Some segments are of length 0.1 because the Java2D renderer adds line caps of
1004        // width/2 size to both ends of the segment when "round" is one of BasicStroke.CAP_ROUND
1005        // or BasicStroke.CAP_SQUARE. This value is small enough not to affect the
1006        // stipple bit pattern calculation for the 3d map and still look good on the
1007        // 2d map.
1008
1009        // NOTE: The dash arrays below do not supportBasisStroke.CAP_BUTT line capping,
1010        // although it would be relatively simple to change them such that they would.
1011        BasicStroke stroke=null;
1012        try {
1013            final float dashLength = 2 * width;
1014            final float dotLength = 1f;
1015            final float dotSpace = 2 * width;
1016            switch (style) {
1017                case 0://GraphicProperties.LINE_TYPE_SOLID:
1018                    stroke = new BasicStroke(width, cap, join);
1019                    break;
1020                case 1://GraphicProperties.LINE_TYPE_DASHED:
1021                    float[] dash = {dashLength, dashLength};
1022                    stroke = new BasicStroke(width, cap, join, 4f, dash, 0f);
1023                    break;
1024                case 2://GraphicProperties.LINE_TYPE_DOTTED:
1025                    float[] dot = {dotLength, dotSpace};
1026                    stroke = new BasicStroke(width, cap, join, 4f, dot, 0f);
1027                    break;
1028                case 3://GraphicProperties.LINE_TYPE_DASHDOT:
1029                    float[] dashdot = {2 * dashLength, dotSpace, dotLength, dotSpace};
1030                    stroke = new BasicStroke(width, cap, join, 4f, dashdot,0f );
1031                    break;
1032                case 4://GraphicProperties.LINE_TYPE_DASHDOTDOT:
1033                    float[] dashdotdot = {dashLength, dotSpace, dotLength, dotSpace, dotLength, dotSpace};
1034                    stroke = new BasicStroke(width, cap, join, 4f,dashdotdot, 0f );
1035                    break;
1036                default:
1037                    stroke = new BasicStroke(width, cap, join);
1038                    break;
1039            }
1040        } catch(Exception exc) {
1041               ErrorLogger.LogException(_className ,"getLineStroke",
1042                    new RendererException("Failed inside getLineStroke", exc));
1043        }
1044        return stroke;
1045    }
1046    /**
1047     * Sets shape properties based on other properties which were set by JavaLineArray
1048     * @param tg tactical graphic
1049     * @param shapes the ShapeInfo array
1050     * @param bi BufferedImage to use for setting shape TexturePaint
1051     */
1052    public static void SetShapeProperties(TGLight tg, ArrayList<Shape2> shapes,
1053            BufferedImage bi) {
1054        try
1055        {
1056            if (shapes == null)
1057            {
1058                return;
1059            }
1060            
1061            int j = 0;
1062            Shape2 shape = null;
1063            BasicStroke stroke = null;
1064            float[] dash = null;
1065            int lineThickness = tg.get_LineThickness();
1066            int shapeType = -1;
1067            int lineType = tg.get_LineType();
1068            boolean hasFill=LinesWithFill(lineType);
1069            boolean isChange1Area = clsUtility.IsChange1Area(lineType);
1070            boolean isClosedPolygon = clsUtility.isClosedPolygon(lineType);
1071            //int n=shapes.size();
1072            //remove air corridors fill shapes if fill is null
1073            if(tg.get_FillColor()==null)
1074            {
1075                switch(tg.get_LineType())
1076                {
1077                    case TacticalLines.AC:
1078                    case TacticalLines.SAAFR:
1079                    case TacticalLines.MRR:
1080                    case TacticalLines.SL:
1081                    case TacticalLines.TC:
1082                    case TacticalLines.SC:
1083                    case TacticalLines.LLTR:
1084                        shape=shapes.get(shapes.size()-1);
1085                        shapes.clear();
1086                        shapes.add(shape);
1087                        break;
1088                    case TacticalLines.CATK:
1089                    case TacticalLines.AIRAOA:
1090                    case TacticalLines.AAAAA:
1091                    case TacticalLines.SPT:
1092                    case TacticalLines.FRONTAL_ATTACK:
1093                    case TacticalLines.TURNING_MOVEMENT:
1094                    case TacticalLines.MOVEMENT_TO_CONTACT:
1095                    case TacticalLines.MAIN:
1096                    case TacticalLines.CATKBYFIRE:      //80
1097                        ArrayList<Shape2> tempShapes=new ArrayList();
1098                        for(j=0;j<shapes.size();j++)
1099                        {
1100                            shape=shapes.get(j);
1101                            if(shape.getShapeType() != Shape2.SHAPE_TYPE_FILL)
1102                                tempShapes.add(shape);
1103                        }
1104                        shapes=tempShapes;
1105                        break;
1106                    default:
1107                        break;
1108                }
1109            }
1110            for (j = 0; j < shapes.size(); j++) 
1111            {
1112                shape = shapes.get(j);
1113                if (shape == null || shape.getShape() == null) {
1114                    continue;
1115                }
1116
1117                if (shape.getShapeType() == Shape2.SHAPE_TYPE_FILL) 
1118                {
1119                    switch(tg.get_LineType())
1120                    {
1121                        case TacticalLines.DEPTH_AREA:
1122                            break;
1123                        default:
1124                            shape.setFillColor(tg.get_FillColor());
1125                            break;
1126                    }
1127                }
1128
1129                //if(lineType != TacticalLines.LEADING_LINE)
1130                ResolveModifierShape(tg, shape);
1131                if(lineType==TacticalLines.AIRFIELD)
1132                    if(j==1)
1133                        shape.setFillColor(null);
1134                //diagnostic
1135                if(lineType==TacticalLines.BBS_POINT)
1136                    if(j==0)
1137                        shape.setLineColor(null);
1138                //end section
1139
1140                shapeType = shape.getShapeType();
1141
1142                Rectangle2D.Double rect = null;
1143                Graphics2D grid = null;
1144                TexturePaint tp = tg.get_TexturePaint();
1145
1146                if(lineThickness==0)
1147                    lineThickness=1;
1148                //set the shape with the default properties
1149                //the switch statement below will override specific properties as needed
1150                stroke = getLineStroke(lineThickness,shape.get_Style(),tg.get_lineCap(),BasicStroke.JOIN_ROUND);
1151                if(shape.getShapeType()==Shape2.SHAPE_TYPE_FILL)
1152                {
1153                    stroke = new BasicStroke(lineThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
1154                    //shape.setStroke(new BasicStroke(0));
1155                }
1156                shape.setStroke(stroke);
1157            } // end loop over shapes
1158           if (tg.get_LineType() == TacticalLines.DIRATKAIR) {
1159               // Make arrowhead and bowtie shapes solid even if tg.get_LineStyle() isn't
1160               for (int i = 2; i < shapes.size(); i++) {
1161                   Shape2 arrowHeadShape = shapes.get(i);
1162                   arrowHeadShape.set_Style(0);
1163                   stroke = getLineStroke(lineThickness, 0, tg.get_lineCap(), BasicStroke.JOIN_ROUND);
1164                   arrowHeadShape.setStroke(stroke);
1165               }
1166           } else if (tg.get_LineType() == TacticalLines.DIRATKGND || tg.get_LineType() == TacticalLines.DIRATKSPT || tg.get_LineType() == TacticalLines.EXPLOIT || lineType == TacticalLines.INFILTRATION) {
1167                // Make arrowhead shape solid even if tg.get_LineStyle() isn't
1168                Shape2 arrowHeadShape = shapes.get(1);
1169                arrowHeadShape.set_Style(0);
1170                stroke = getLineStroke(lineThickness,0,tg.get_lineCap(),BasicStroke.JOIN_ROUND);
1171                arrowHeadShape.setStroke(stroke);
1172           } else if (tg.get_LineType() == TacticalLines.PDF) {
1173               Shape2 rectShape = shapes.get(1);
1174               rectShape.set_Style(0);
1175               stroke = getLineStroke(lineThickness, 0, tg.get_lineCap(), BasicStroke.JOIN_ROUND);
1176               rectShape.setStroke(stroke);
1177               rectShape.setFillColor(rectShape.getLineColor());
1178           }
1179        }
1180        catch (Exception exc) {
1181               ErrorLogger.LogException(_className ,"SetShapeProperties",
1182                    new RendererException("Failed inside SetShapeProperties", exc));
1183        }
1184    }
1185    /**
1186     * Returns a boolean indicating whether the line type is a change 1 area
1187     * @param lineType the line type
1188     * @return true if change 1 area
1189     */
1190    public static boolean IsChange1Area(int lineType) {
1191        try {
1192            switch (lineType) {
1193                case TacticalLines.LAUNCH_AREA:
1194                case TacticalLines.DEFENDED_AREA_CIRCULAR:
1195                case TacticalLines.SHIP_AOI_CIRCULAR:
1196                case TacticalLines.PBS_ELLIPSE:
1197                case TacticalLines.RECTANGULAR:
1198                case TacticalLines.CUED_ACQUISITION:
1199                case TacticalLines.PBS_RECTANGLE:
1200                case TacticalLines.PBS_SQUARE:
1201                case TacticalLines.CIRCULAR:
1202                case TacticalLines.PBS_CIRCLE:
1203                case TacticalLines.BDZ:
1204                case TacticalLines.BBS_POINT:
1205                case TacticalLines.FSA_CIRCULAR:
1206                case TacticalLines.NOTACK:
1207                case TacticalLines.FFA_CIRCULAR:
1208                case TacticalLines.NFA_CIRCULAR:
1209                case TacticalLines.RFA_CIRCULAR:
1210                case TacticalLines.ACA_CIRCULAR:
1211                case TacticalLines.PAA_CIRCULAR:
1212                case TacticalLines.ATI_CIRCULAR:
1213                case TacticalLines.CFFZ_CIRCULAR:
1214                case TacticalLines.SENSOR_CIRCULAR:
1215                case TacticalLines.CENSOR_CIRCULAR:
1216                case TacticalLines.DA_CIRCULAR:
1217                case TacticalLines.CFZ_CIRCULAR:
1218                case TacticalLines.ZOR_CIRCULAR:
1219                case TacticalLines.TBA_CIRCULAR:
1220                case TacticalLines.TVAR_CIRCULAR:
1221                case TacticalLines.KILLBOXBLUE_CIRCULAR:
1222                case TacticalLines.KILLBOXPURPLE_CIRCULAR:
1223                case TacticalLines.RANGE_FAN:
1224                case TacticalLines.RANGE_FAN_FILL:
1225                case TacticalLines.RANGE_FAN_SECTOR:
1226                case TacticalLines.RADAR_SEARCH:
1227                case TacticalLines.BS_RADARC:
1228                case TacticalLines.BS_CAKE:
1229                case TacticalLines.PAA_RECTANGULAR:
1230                case TacticalLines.RECTANGULAR_TARGET:
1231                case TacticalLines.FSA_RECTANGULAR:
1232                case TacticalLines.SHIP_AOI_RECTANGULAR:
1233                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
1234                case TacticalLines.BS_ROUTE:
1235                case TacticalLines.BS_TRACK:
1236                case TacticalLines.FFA_RECTANGULAR:
1237                case TacticalLines.RFA_RECTANGULAR:
1238                case TacticalLines.NFA_RECTANGULAR:
1239                case TacticalLines.ACA_RECTANGULAR:
1240                case TacticalLines.ATI_RECTANGULAR:
1241                case TacticalLines.CFFZ_RECTANGULAR:
1242                case TacticalLines.SENSOR_RECTANGULAR:
1243                case TacticalLines.CENSOR_RECTANGULAR:
1244                case TacticalLines.DA_RECTANGULAR:
1245                case TacticalLines.CFZ_RECTANGULAR:
1246                case TacticalLines.ZOR_RECTANGULAR:
1247                case TacticalLines.TBA_RECTANGULAR:
1248                case TacticalLines.TVAR_RECTANGULAR:
1249                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
1250                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
1251                case TacticalLines.BS_ORBIT:
1252                case TacticalLines.BS_POLYARC:
1253                    return true;
1254                default:
1255                    return false;
1256            }
1257        } catch (Exception exc) {
1258            //clsUtility.WriteFile("Error in clsUtility.IsChange1Area");
1259               ErrorLogger.LogException(_className ,"IsChange1Area",
1260                    new RendererException("Failed inside IsChange1Area", exc));
1261        }
1262        return false;
1263    }
1264
1265    public static void WriteFile(String str) {
1266        try {
1267            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("Test.txt"));
1268            bufferedWriter.write(str);
1269            //bufferedWriter.newLine();
1270            //bufferedWriter.write(pointType);
1271            bufferedWriter.close();
1272            bufferedWriter = null;
1273        } 
1274        catch (Exception exc) {
1275               ErrorLogger.LogException(_className ,"WriteFile",
1276                    new RendererException("Failed inside WriteFile", exc));
1277        }
1278    }
1279
1280    /**
1281     * Calculates point where two lines intersect.
1282     * First line defined by pt1, m1.
1283     * Second line defined by pt2, m2.
1284     * result will be written to ptIntersect.
1285     * @param pt1 first line point
1286     * @param m1 slope of first line
1287     * @param pt2 second line point
1288     * @param m2 slope of second line
1289     * @param ptIntersect OUT - intersection point
1290     */
1291    protected static void CalcIntersectPt(POINT2 pt1,
1292            double m1,
1293            POINT2 pt2,
1294            double m2,
1295            POINT2 ptIntersect) {
1296        try {
1297            if (m1 == m2) {
1298                return;
1299            }
1300
1301            double x1 = pt1.x;
1302            double y1 = pt1.y;
1303            double x2 = pt2.x;
1304            double y2 = pt2.y;
1305            //formula for the intersection of two lines
1306            double dx2 = (double) ((y1 - y2 + m1 * x2 - m1 * x1) / (m2 - m1));
1307            double x3 = x2 + dx2;
1308            double y3 = (double) (y2 + m2 * dx2);
1309
1310            ptIntersect.x = x3;
1311            ptIntersect.y = y3;
1312        } catch (Exception exc) {
1313            //clsUtility.WriteFile("Error in clsUtility.CalcIntersectPt");
1314            ErrorLogger.LogException(_className, "CalcIntersectPt",
1315                    new RendererException("Failed inside CalcIntersectPt", exc));
1316        }
1317    }
1318
1319    /**
1320     * Calculates the channel width in pixels for channel types
1321     * @param pixels the client points as 2-tuples x,y in pixels
1322     * @param distanceToChannelPOINT2 OUT - the calculated distance in pixels from the tip of the
1323     * arrowhead to the back of the arrowhead.
1324     * @return the channel width in pixels
1325     */
1326    protected static int ChannelWidth(double[] pixels,
1327            ref<double[]> distanceToChannelPOINT2) {
1328        int width = 0;
1329        try {
1330            int numPOINT2s = pixels.length / 2;
1331            if (numPOINT2s < 3) {
1332                return 0;
1333            }
1334
1335            POINT2 channelWidthPOINT2 = new POINT2(0, 0);
1336            POINT2 lastSegmentPt1 = new POINT2(0, 0);
1337            POINT2 lastSegmentPt2 = new POINT2(0, 0);
1338
1339            lastSegmentPt1.x = (double) pixels[2 * numPOINT2s - 6];
1340            lastSegmentPt1.y = (double) pixels[2 * numPOINT2s - 5];
1341            lastSegmentPt2.x = (double) pixels[2 * numPOINT2s - 4];
1342            lastSegmentPt2.y = (double) pixels[2 * numPOINT2s - 3];
1343            channelWidthPOINT2.x = (double) pixels[2 * numPOINT2s - 2];
1344            channelWidthPOINT2.y = (double) pixels[2 * numPOINT2s - 1];
1345
1346            ref<double[]> m = new ref();
1347            double m1 = 0;
1348            //m1.value=new double[1];
1349            double distance = 0;
1350            POINT2 ptIntersect = new POINT2(0, 0);
1351            //boolean bolVertical = TrueSlope(lastSegmentPt1, lastSegmentPt2, ref m);
1352            boolean bolVertical = lineutility.CalcTrueSlopeDouble2(lastSegmentPt1, lastSegmentPt2, m);
1353            if (bolVertical == true && m.value[0] != 0) {
1354                m1 = -1 / m.value[0];
1355                CalcIntersectPt(channelWidthPOINT2, m1, lastSegmentPt2, m.value[0], ptIntersect);
1356                distance = lineutility.CalcDistanceDouble(channelWidthPOINT2, ptIntersect);
1357            }
1358            if (bolVertical == true && m.value[0] == 0) //horizontal segment
1359            {
1360                distance = Math.abs(channelWidthPOINT2.y - lastSegmentPt1.y);
1361            }
1362            if (bolVertical == false) //vertical segment
1363            {
1364                distance = Math.abs(channelWidthPOINT2.x - lastSegmentPt1.x);
1365                distanceToChannelPOINT2.value = new double[1];
1366                distanceToChannelPOINT2.value[0] = distance;
1367                return (int) distance * 4;
1368            }
1369
1370            width = (int) distance * 8;
1371            if (width < 2) {
1372                width = 2;
1373            }
1374
1375            double hypotenuse = lineutility.CalcDistanceDouble(lastSegmentPt2, channelWidthPOINT2);
1376            distanceToChannelPOINT2.value = new double[1];
1377            distanceToChannelPOINT2.value[0] = Math.sqrt(hypotenuse * hypotenuse - distance * distance);
1378
1379        } catch (Exception exc) {
1380            //clsUtility.WriteFile("Error in clsUtility.ChannelWidth");
1381            ErrorLogger.LogException(_className, "ChannelWidth",
1382                    new RendererException("Failed inside ChannelWidth", exc));
1383        }
1384        return width;
1385    }
1386
1387    private static boolean InYOrder(POINT2 pt0,
1388            POINT2 pt1,
1389            POINT2 pt2) {
1390        try {
1391            if (pt0.y <= pt1.y && pt1.y <= pt2.y) {
1392                return true;
1393            }
1394
1395            if (pt2.y <= pt1.y && pt1.y <= pt0.y) {
1396                return true;
1397            }
1398
1399        } catch (Exception exc) {
1400            //clsUtility.WriteFile("Error in clsUtility.InYOrder");
1401            ErrorLogger.LogException(_className, "InYOrder",
1402                    new RendererException("Failed inside InYOrder", exc));
1403        }
1404        return false;
1405    }
1406    /// <summary>
1407    /// tests if POINT2s have successively increasing or decreasing x values.
1408    /// </summary>
1409    /// <param name="pt0"></param>
1410    /// <param name="pt1"></param>
1411    /// <param name="pt2"></param>
1412    /// <returns>true if POINT2s are in X order</returns>
1413
1414    private static boolean InXOrder(POINT2 pt0,
1415            POINT2 pt1,
1416            POINT2 pt2) {
1417        try {
1418            if (pt0.x <= pt1.x && pt1.x <= pt2.x) {
1419                return true;
1420            }
1421
1422            if (pt2.x <= pt1.x && pt1.x <= pt0.x) {
1423                return true;
1424            }
1425
1426        } catch (Exception exc) {
1427            //clsUtility.WriteFile("Error in clsUtility.InXOrder");
1428            ErrorLogger.LogException(_className, "InXOrder",
1429                    new RendererException("Failed inside InXOrder", exc));
1430        }
1431        return false;
1432    }
1433
1434    /**
1435     * For each sector calculates left azimuth, right azimuth, min radius, max radius
1436     * and stuff H2 with the string delimited result. The function is public, called by JavaRendererServer
1437     * @param tg tactical graphic
1438     */
1439    public static void GetSectorRadiiFromPoints(TGLight tg) {
1440        try {
1441            if(tg.get_LineType()==TacticalLines.RANGE_FAN_FILL)
1442                return;
1443            POINT2 ptCenter = tg.LatLongs.get(0);
1444            POINT2 ptLeftMin = new POINT2(), ptRightMax = new POINT2();
1445            int k = 0;
1446            String strLeft = "", strRight = "", strMin = "", strMax = "", temp = "";
1447            double nLeft = 0, nRight = 0, nMin = 0, nMax = 0;
1448            //if tg.PointCollection has more than one point
1449            //we use the points to calculate left,right,min,max
1450            //and then stuff tg.H2 with the comma delimited string
1451            double dist = 0;
1452            ref<double[]> a12 = new ref(), a21 = new ref();
1453            int numSectors = 0;
1454            if (tg.LatLongs.size() > 2) {
1455                numSectors = (tg.LatLongs.size() - 2) / 2;
1456                for (k = 0; k < numSectors; k++) {
1457                    //get the sector points
1458                    ptLeftMin = tg.LatLongs.get(2 * k + 2);
1459                    ptRightMax = tg.LatLongs.get(2 * k + 3);
1460
1461                    dist = mdlGeodesic.geodesic_distance(ptCenter, ptLeftMin, a12, a21);
1462                    nLeft = a12.value[0];
1463                    strLeft = Double.toString(nLeft);
1464
1465                    nMin = dist;
1466                    strMin = Double.toString(nMin);
1467
1468                    dist = mdlGeodesic.geodesic_distance(ptCenter, ptRightMax, a12, a21);
1469                    nRight = a12.value[0];
1470                    strRight = Double.toString(nRight);
1471
1472                    nMax = dist;
1473                    strMax = Double.toString(nMax);
1474
1475                    if (k == 0) {
1476                        temp = strLeft + "," + strRight + "," + strMin + "," + strMax;
1477                    } else {
1478                        temp += "," + strLeft + "," + strRight + "," + strMin + "," + strMax;
1479                    }
1480                }
1481                if (!temp.equals("")) {
1482                    tg.set_LRMM(temp);
1483                }
1484            }
1485        } catch (Exception exc) {
1486            //clsUtility.WriteFile("Error in clsUtility.GetSectorRadiiFromPoints");
1487            ErrorLogger.LogException(_className, "GetSectorRadiiFromPoints",
1488                    new RendererException("Failed inside GetSectorRadiiFromPoints", exc));
1489        }
1490    }
1491
1492    /**
1493     * Reverses the pixels except for the last point. This is used for
1494     * the axis of advance type routes. The pixels are 2-tuples x,y
1495     *
1496     * @param pixels OUT - Array of client points
1497     */
1498    protected static void ReorderPixels(double[] pixels) {
1499        try {
1500            double[] tempPixels;
1501            //reverse the pixels
1502            int j;
1503            double x;
1504            double y;
1505            int counter;
1506            int numPoints;
1507            counter = 0;
1508            numPoints = pixels.length / 2;
1509            tempPixels = new double[pixels.length];
1510            for (j = 0; j < numPoints - 1; j++) {
1511                x = pixels[pixels.length - 2 * j - 4];
1512                y = pixels[pixels.length - 2 * j - 3];
1513                tempPixels[counter] = x;
1514                tempPixels[counter + 1] = y;
1515                counter += 2;
1516            }
1517            //put the last pixel point into the last temppixels point
1518            int intPixelSize = pixels.length;
1519            tempPixels[counter] = pixels[intPixelSize - 2];
1520            tempPixels[counter + 1] = pixels[intPixelSize - 1];
1521            //stuff the pixels
1522            int n=pixels.length;
1523            //for (j = 0; j < pixels.length; j++) 
1524            for (j = 0; j < n; j++) 
1525            {
1526                pixels[j] = tempPixels[j];
1527            }
1528            //tempPixels = null;
1529        } catch (Exception exc) {
1530            ErrorLogger.LogException(_className, "ReorderPixels",
1531                    new RendererException("Failed inside ReorderPixels", exc));
1532        }
1533    }
1534    /**
1535     * do not allow vertical segments for these, move the point x value by 1 pixel
1536     * @param tg tactical graphic
1537     */
1538    public static void FilterVerticalSegments(TGLight tg)
1539    {
1540        try
1541        {
1542            switch(tg.get_LineType())
1543            {
1544                case TacticalLines.MAIN:
1545                case TacticalLines.CATK:
1546                case TacticalLines.CATKBYFIRE:
1547                case TacticalLines.AIRAOA:
1548                case TacticalLines.AAAAA:
1549                case TacticalLines.SPT:
1550                case TacticalLines.FRONTAL_ATTACK:
1551                case TacticalLines.TURNING_MOVEMENT:
1552                case TacticalLines.MOVEMENT_TO_CONTACT:
1553                case TacticalLines.LC:
1554                case TacticalLines.UNSP:
1555                case TacticalLines.DFENCE:
1556                case TacticalLines.SFENCE:
1557                case TacticalLines.DOUBLEA:
1558                case TacticalLines.LWFENCE:
1559                case TacticalLines.HWFENCE:
1560                case TacticalLines.BBS_LINE:
1561                case TacticalLines.SINGLEC:
1562                case TacticalLines.DOUBLEC:
1563                case TacticalLines.TRIPLE:
1564                case TacticalLines.MSR_ONEWAY:
1565                case TacticalLines.MSR_TWOWAY:
1566                case TacticalLines.MSR_ALT:
1567                case TacticalLines.ASR_ONEWAY:
1568                case TacticalLines.ASR_TWOWAY:
1569                case TacticalLines.ASR_ALT:
1570                case TacticalLines.TRAFFIC_ROUTE_ONEWAY:
1571                case TacticalLines.TRAFFIC_ROUTE_ALT:
1572                case TacticalLines.ATWALL:
1573                    break;
1574                default:
1575                    return;
1576            }
1577            POINT2 ptCurrent=null;
1578            POINT2 ptLast=null;
1579            int n=tg.Pixels.size();
1580            //for(int j=1;j<tg.Pixels.size();j++)
1581            for(int j=1;j<n;j++)
1582            {
1583                ptLast=new POINT2(tg.Pixels.get(j-1));
1584                ptCurrent=new POINT2(tg.Pixels.get(j));
1585                //if(Math.round(ptCurrent.x)==Math.round(ptLast.x))
1586                if(Math.abs(ptCurrent.x-ptLast.x)<1)
1587                {
1588                    if (ptCurrent.x>=ptLast.x)
1589                        ptCurrent.x += 1;
1590                    else
1591                        ptCurrent.x -= 1;
1592                    tg.Pixels.set(j, ptCurrent);
1593                }
1594            }
1595        }
1596        catch(Exception exc)
1597        {
1598            ErrorLogger.LogException("clsUtility", "FilterVerticalSegments",
1599                    new RendererException("Failed inside FilterVerticalSegments", exc));
1600
1601        }
1602    }
1603    /**
1604     * Client utility to calculate the channel points for channel types.
1605     * This code was ported from CJMTK.
1606     * @param arrLocation the client points
1607     * @return the channel point
1608     */
1609    public static POINT2 ComputeLastPoint(ArrayList<POINT2> arrLocation) {
1610        POINT2 locD = new POINT2(0, 0);
1611        try {
1612            POINT2 locA = arrLocation.get(1);
1613            //Get the first point (b) in pixels.
1614            //var locB:Point=new Point(arrLocation[0].x,arrLocation[0].y);
1615            POINT2 locB = arrLocation.get(0);
1616
1617            //Compute the distance in pixels from (a) to (b).
1618            double dblDx = locB.x - locA.x;
1619            double dblDy = locB.y - locA.y;
1620
1621            //Compute the dblAngle in radians from (a) to (b).
1622            double dblTheta = Math.atan2(-dblDy, dblDx);
1623
1624            //Compute a reasonable intermediate point along the line from (a) to (b).
1625            POINT2 locC = new POINT2(0, 0);
1626            locC.x = (int) (locA.x + 0.85 * dblDx);
1627            locC.y = (int) (locA.y + 0.85 * dblDy);
1628            //Put the last point on the left side of the line from (a) to (b).
1629            double dblAngle = dblTheta + Math.PI / 2.0;
1630            if (dblAngle > Math.PI) {
1631                dblAngle = dblAngle - 2.0 * Math.PI;
1632            }
1633            if (dblAngle < -Math.PI) {
1634                dblAngle = dblAngle + 2.0 * Math.PI;
1635            }
1636
1637            //Set the magnitude of the dblWidth in pixels.  Make sure it is at least 15 pixels.
1638            double dblWidth = 30;//was 15
1639
1640            //Compute the last point in pixels.
1641            locD.x = (locC.x + dblWidth * Math.cos(dblAngle));
1642            locD.y = (locC.y - dblWidth * Math.sin(dblAngle));
1643        } catch (Exception exc) {
1644            //clsUtility.WriteFile("Error in clsUtility.ComputeLatPoint");
1645            ErrorLogger.LogException(_className, "ComputeLastPoint",
1646                    new RendererException("Failed inside ComputeLastPoint", exc));
1647        }
1648        return locD;
1649    }
1650
1651    /**
1652     * Called by clsChannelUtility. The segments are used for managing double-backed segments
1653     * for channel types. If the new point is double-backed then the segment at that index will be false.
1654     *
1655     * @param pixels the client points as 2-tuples x,y in pixels
1656     * @param segments OUT - the segments
1657     * @param factor a steepness factor for calculating whether the segment is double-backed
1658     */
1659    protected static void GetSegments(double[] pixels,
1660            boolean[] segments,
1661            double factor) {
1662        try
1663        {
1664            int j = 0;
1665            ref<double[]> m1 = new ref();
1666            ref<double[]> m2 = new ref();
1667            long numPoints = 0;
1668            boolean bolVertical1 = false;
1669            boolean bolVertical2 = false;
1670
1671            POINT2 pt0F = new POINT2(0, 0);
1672            POINT2 pt1F = new POINT2(0, 0);
1673            POINT2 pt2F = new POINT2(0, 0);
1674
1675            segments[0] = true;
1676            
1677            numPoints = pixels.length / 2;
1678            for (j = 0; j < numPoints - 2; j++)
1679            {
1680                pt0F.x = (double) pixels[2 * j];
1681                pt0F.y = (double) pixels[2 * j + 1];
1682
1683                pt1F.x = (double) pixels[2 * j + 2];
1684                pt1F.y = (double) pixels[2 * j + 3];
1685
1686                pt2F.x = (double) pixels[2 * j + 4];
1687                pt2F.y = (double) pixels[2 * j + 5];
1688
1689                bolVertical1 = lineutility.CalcTrueSlopeDoubleForRoutes(pt0F, pt1F, m1);
1690                bolVertical2 = lineutility.CalcTrueSlopeDoubleForRoutes(pt1F, pt2F, m2);
1691
1692                segments[j + 1] = true;
1693                if (bolVertical1 == true && bolVertical2 == true)
1694                {
1695                    if (Math.abs(Math.atan(m1.value[0]) - Math.atan(m2.value[0])) < 1 / factor && InXOrder(pt0F, pt1F, pt2F) == false) //was 0.1
1696                    {
1697                        segments[j + 1] = false;
1698                    }
1699                }
1700
1701                if ((bolVertical1 == false || Math.abs(m1.value[0]) > factor) && (bolVertical2 == false || Math.abs(m2.value[0]) > factor) && InYOrder(pt0F, pt1F, pt2F) == false) //was 10
1702                {
1703                    segments[j + 1] = false;
1704                }
1705            }   //end for
1706            //int n=segments.length;
1707        }
1708        catch (Exception exc)
1709        {
1710            //System.out.println(e.getMessage());
1711            //clsUtility.WriteFile("Error in clsUtility.GetSegments");
1712            ErrorLogger.LogException(_className, "GetSegments",
1713                    new RendererException("Failed inside GetSegments", exc));
1714        }
1715    }
1716
1717    protected static void GetLCPartitions(double[] pixels,
1718                                          double LCChannelWith,
1719                                          ArrayList<P1> partitions,
1720                                          ArrayList<P1> singleLinePartitions) {
1721        try
1722        {
1723            int numPoints = pixels.length / 2;
1724            POINT2 pt0F = new POINT2(0, 0);
1725            POINT2 pt1F = new POINT2(0, 0);
1726            POINT2 pt2F = new POINT2(0, 0);
1727
1728            P1 nextP = new P1();
1729            nextP.start = 0;
1730
1731            //used for debugging
1732            double[] angles = new double[numPoints - 1];
1733
1734            for (int i = 0; i < numPoints - 2; i++) {
1735                pt0F.x = (double) pixels[2 * i];
1736                pt0F.y = (double) pixels[2 * i + 1];
1737
1738                pt1F.x = (double) pixels[2 * i + 2];
1739                pt1F.y = (double) pixels[2 * i + 3];
1740
1741                pt2F.x = (double) pixels[2 * i + 4];
1742                pt2F.y = (double) pixels[2 * i + 5];
1743
1744                double angle1 = Math.atan2(pt1F.y - pt0F.y, pt1F.x - pt0F.x);
1745                double angle2 = Math.atan2(pt1F.y - pt2F.y, pt1F.x - pt2F.x);
1746                double angle = angle1-angle2;// * 180/Math.PI;
1747                double degrees = angle * 180/Math.PI;
1748                if (angle < 0) {
1749                    degrees = 360 + degrees;
1750                }
1751
1752                if (degrees > 270) {
1753                    boolean angleTooSmall = false;
1754
1755                    if (lineutility.CalcDistanceDouble(pt0F, pt1F) < lineutility.CalcDistanceDouble(pt1F, pt2F)) {
1756                        POINT2 newPt = lineutility.ExtendAlongLineDouble2(pt1F, pt2F, lineutility.CalcDistanceDouble(pt1F, pt0F));
1757                        if (lineutility.CalcDistanceDouble(pt0F, newPt) < LCChannelWith)
1758                            angleTooSmall = true;
1759                    } else {
1760                        POINT2 newPt = lineutility.ExtendAlongLineDouble2(pt1F, pt0F, lineutility.CalcDistanceDouble(pt1F, pt2F));
1761                        if (lineutility.CalcDistanceDouble(pt2F, newPt) < LCChannelWith)
1762                            angleTooSmall = true;
1763                    }
1764                    if (angleTooSmall) {
1765                        // Angle is too small to fit channel, make it a single line partition
1766                        nextP.end_Renamed = i - 1;
1767                        partitions.add(nextP);
1768                        nextP = new P1();
1769                        nextP.start = i;
1770                        nextP.end_Renamed=i + 2;
1771                        singleLinePartitions.add(nextP);
1772                        i++;
1773                        nextP = new P1();
1774                        nextP.start = i + 1;
1775                    }
1776                } else if(degrees < 90) {
1777                    // new Partition
1778                    nextP.end_Renamed = i;
1779                    partitions.add(nextP);
1780                    nextP = new P1();
1781                    nextP.start = i + 1;
1782                }
1783                angles[i] = degrees;
1784            } //end for
1785            nextP.end_Renamed = numPoints - 2;
1786            partitions.add(nextP);
1787        } catch (Exception exc) {
1788            ErrorLogger.LogException(_className, "GetLCPartitions",
1789                    new RendererException("Failed inside GetLCPartitions", exc));
1790        }
1791    }
1792
1793    /**
1794     * Sets the color for the current shape depending on the affiliation
1795     * @param tg
1796     * @param shape
1797     */
1798    protected static void SetLCColor(TGLight tg, Shape2 shape) {
1799        try {
1800            if (tg.isHostile()) {
1801                if (shape.getLineColor() == Color.RED) {
1802                    shape.setLineColor(tg.get_LineColor());
1803                } else {
1804                    shape.setLineColor(Color.RED);
1805                }
1806            } else {
1807                if (shape.getLineColor() != Color.RED) {
1808                    shape.setLineColor(tg.get_LineColor());
1809                } else {
1810                    shape.setLineColor(Color.RED);
1811                }
1812            }
1813
1814        } catch (Exception exc) {
1815            //WriteFile("Error in clsUtility.SetLCColor");
1816            ErrorLogger.LogException(_className, "SetLCColor",
1817                    new RendererException("Failed inside SetLCColor", exc));
1818        }
1819    }
1820    /**
1821     * USAS requires a left-right orientation for ENY, which negates the upper-lower
1822     * orientation we used for Mil-Std-2525 ENY compliance. Therefore we must reverse
1823     * the client points for two of the quadrants
1824     * @param tg tactical graphic
1825     */
1826    public static void ReverseUSASLCPointsByQuadrant(TGLight tg)
1827    {
1828        try
1829        {
1830            if(tg.Pixels.size()<2)
1831                return;
1832            int quadrant=lineutility.GetQuadrantDouble(tg.Pixels.get(0), tg.Pixels.get(1));
1833            switch(tg.get_LineType())
1834            {
1835                case TacticalLines.LC:
1836                    if(tg.isHostile())
1837                    {
1838                        switch(quadrant)
1839                        {
1840                            case 2:
1841                            case 3:
1842                                break;
1843                            case 1://reverse the points for these two quadrants
1844                            case 4:
1845                                int n=tg.Pixels.size();
1846                                ArrayList<POINT2> pts2=(ArrayList<POINT2>)tg.Pixels.clone();
1847                                        //for(int j=0;j<tg.Pixels.size();j++)
1848                                        for(int j=0;j<n;j++)
1849                                            tg.Pixels.set(j, pts2.get(n-j-1));
1850                                break;
1851                        }//end switch quadrant
1852                    }//end if
1853                    else
1854                    {
1855                        switch(quadrant)
1856                        {
1857                            case 1:
1858                            case 4:
1859                                break;
1860                            case 2://reverse the points for these two quadrants
1861                            case 3:
1862                                int n=tg.Pixels.size();
1863                                ArrayList<POINT2> pts2=(ArrayList<POINT2>)tg.Pixels.clone();
1864                                        //for(int j=0;j<tg.Pixels.size();j++)
1865                                        for(int j=0;j<n;j++)
1866                                            tg.Pixels.set(j, pts2.get(n-j-1));
1867                                break;
1868                        }//end switch quadrant
1869                    }//end else
1870                    break;
1871                default:
1872                    break;
1873            }//end switch linetype
1874        }
1875        catch (Exception exc) {
1876            //WriteFile("Error in clsUtility.SetLCColor");
1877            ErrorLogger.LogException(_className, "ReverseUSASLCPointsByQuadrant",
1878                    new RendererException("Failed inside ReverseUSASLCPointsByQuadrant", exc));
1879        }
1880    }//end ReverseUSASLCPointsByQuadrant
1881
1882    /**
1883     * use str if tg is null
1884     * @param symbolId Mil=Standard-2525 symbol id
1885     * @return line type
1886     */
1887    public static int GetLinetypeFromString(String symbolId)
1888    {
1889        try
1890        {
1891            if (symbolId.length() < 16){
1892                return -1;
1893            }
1894            int symbolSet = SymbolID.getSymbolSet(symbolId);
1895            int entityCode = SymbolID.getEntityCode(symbolId);
1896            int version = SymbolID.getVersion(symbolId);
1897            if (symbolSet == 25) {
1898                return clsRenderer.getCMLineType(version, entityCode);
1899            } else if (symbolSet == 45 || symbolSet == 46) {
1900                return clsMETOC.getWeatherLinetype(version, entityCode);
1901            }
1902        }
1903        catch (Exception exc) {
1904            ErrorLogger.LogException(_className ,"GetLinetypeFromString",
1905                    new RendererException("Failed inside GetLinetypeFromString", exc));
1906        }
1907        return -1;
1908    }
1909
1910    /**
1911     * An auto-shape is a symbol with a fixed number of anchor points
1912     *
1913     * @param tg tactical graphic
1914     * @return true if auto-shape
1915     */
1916    public static boolean isAutoshape(TGLight tg) {
1917        try {
1918            switch(tg.get_LineType())
1919            {
1920                case TacticalLines.BBS_RECTANGLE:
1921                case TacticalLines.BS_RECTANGLE:
1922                case TacticalLines.BS_ELLIPSE:
1923                case TacticalLines.PBS_CIRCLE:
1924                case TacticalLines.BS_CROSS:
1925                case TacticalLines.BS_BBOX:
1926                case TacticalLines.BBS_POINT:
1927                    return true;
1928            }
1929            MSInfo msInfo = MSLookup.getInstance().getMSLInfo(tg.get_SymbolId());
1930            if (msInfo == null || IsChange1Area(tg.get_LineType())) {
1931                return false;
1932            }
1933            switch (tg.get_LineType()) {
1934                case TacticalLines.DIRATKAIR:
1935                case TacticalLines.DIRATKGND:
1936                case TacticalLines.DIRATKSPT:
1937                case TacticalLines.INFILTRATION:
1938                    // Direction of attack symbols only have two points but can handle more
1939                    return false;
1940                default:
1941                    break;
1942            }
1943            switch (msInfo.getDrawRule()) {
1944                case DrawRules.LINE26: // Two ways to draw but fixed points
1945                case DrawRules.LINE27: // Two ways to draw but fixed points
1946                case DrawRules.AREA26: // Need same number of points in first half and second half to make two shapes
1947                case DrawRules.CORRIDOR1: // Each point represents an Air Control Point or Communications Checkpoint
1948                    return true;
1949                default:
1950                    return msInfo.getMaxPointCount() == msInfo.getMinPointCount();
1951            }
1952        } catch (Exception exc) {
1953            ErrorLogger.LogException(_className, "isAutoshape",
1954                    new RendererException("Failed inside isAutoshape", exc));
1955        }
1956        return false;
1957    }
1958    /**
1959     * Client will send the segment colors within a modifier.
1960     * Format is 0:FFBBBB,4:FFAAAA,...
1961     * For the time being will assume the modifier being used is the H modifier
1962     * @param tg
1963     * @return 
1964     */
1965    public static HashMap<Integer,Color> getMSRSegmentColors(TGLight tg)
1966    {
1967        HashMap<Integer,Color> hMap=null;
1968        try
1969        {
1970            int linetype=tg.get_LineType();
1971            switch(linetype)
1972            {
1973                case TacticalLines.MSR:
1974                case TacticalLines.ASR:
1975                case TacticalLines.TRAFFIC_ROUTE:
1976                case TacticalLines.BOUNDARY:
1977                    if(tg.get_H()==null || tg.get_H().isEmpty())
1978                        return null;
1979                    hMap=new HashMap<Integer,Color>();
1980                    break;
1981                default:
1982                    return null;
1983            }
1984            String[]colorStrs=tg.get_H().split(",");
1985            int j=0,numSegs=colorStrs.length;
1986            String segPlusColor="";
1987            String[]seg=null;     
1988            Color color=null;
1989            int index=-1;
1990            for(j=0;j<numSegs;j++)
1991            {
1992                segPlusColor=colorStrs[j];
1993                if(!segPlusColor.contains(":"))
1994                    continue;
1995                seg=segPlusColor.split(":");
1996                color= RendererUtilities.getColorFromHexString(seg[1]);
1997                index=Integer.parseInt(seg[0]);
1998                hMap.put(index, color);
1999            }
2000        }
2001        catch (Exception exc)
2002        {
2003            ErrorLogger.LogException(_className ,"getMSRSegmentColors",
2004                    new RendererException("Failed inside getMSRSegmentColors", exc));
2005        }
2006        return hMap;
2007    }
2008    public static HashMap<Integer,String> getMSRSegmentColorStrings(TGLight tg)
2009    {
2010        HashMap<Integer,String> hMap=null;
2011        try
2012        {
2013            int linetype = tg.get_LineType();
2014            switch (linetype) {
2015                case TacticalLines.MSR:
2016                case TacticalLines.ASR:
2017                case TacticalLines.TRAFFIC_ROUTE:
2018                case TacticalLines.BOUNDARY:
2019                    if (tg.get_H() == null || tg.get_H().isEmpty())
2020                        return null;
2021                    hMap = new HashMap<>();
2022                    break;
2023                default:
2024                    return null;
2025            }
2026            String[] colorStrs = tg.get_H().split(",");
2027            int j = 0;
2028            int numSegs = colorStrs.length;
2029            String segPlusColor = "";
2030            String[] seg = null;
2031            //Color color = null;
2032            int index = -1;
2033            for (j = 0; j < numSegs; j++) {
2034                segPlusColor = colorStrs[j];
2035                if (!segPlusColor.contains(":"))
2036                    continue;
2037                seg = segPlusColor.split(":");
2038                //color = armyc2.c5isr.renderer.utilities.SymbolUtilitiesD.getColorFromHexString(seg[1]);
2039                index = Integer.parseInt(seg[0]);
2040                //hMap.put(new Integer(index), color);
2041                hMap.put(new Integer(index), seg[1]);
2042            }            
2043        }
2044        catch (Exception exc)
2045        {
2046            ErrorLogger.LogException(_className ,"getMSRSegmentColorStrings",
2047                    new RendererException("Failed inside getMSRSegmentColorStrings", exc));
2048        }
2049        return hMap;
2050    }
2051    /**
2052     * tg.H must be revised for clipped MSR, ASR and Boundary
2053     * This function is called after the pixels were clipped
2054     * @param originalPixels the tactical graphic pixels before clipping
2055     * @param tg
2056     * @deprecated
2057     */
2058    public static void reviseHModifier(ArrayList<POINT2>originalPixels, 
2059            TGLight tg)
2060    {
2061        try
2062        {
2063            //only revise tg.H if it is not null or empty
2064            //and the linetype is bounday, MSR, or ASR
2065            if(tg.get_H()==null || tg.get_H().isEmpty())
2066                return;
2067            int linetype=tg.get_LineType();
2068            switch(linetype)
2069            {
2070                case TacticalLines.ASR:
2071                case TacticalLines.MSR:
2072                case TacticalLines.TRAFFIC_ROUTE:
2073                case TacticalLines.BOUNDARY:
2074                    break;
2075                default:
2076                    return;
2077            }
2078            int j=0,k=0;
2079            //Line2D line=new Line2D.Double();
2080            
2081            //get the first common point between the original points and tg.Pixels
2082            //if it is n then n segments will have been dropped at the front end of
2083            //the clipped array (from the original pixels) so then we would want to
2084            //set the start index to n for the loop through the original points
2085            int n=-1; 
2086            boolean foundPt=false;
2087            int t=originalPixels.size();
2088            int u=tg.Pixels.size();
2089            //for(j=0;j<originalPixels.size();j++)
2090            for(j=0;j<t;j++)
2091            {
2092                //for(k=0;k<tg.Pixels.size();k++)
2093                for(k=0;k<u;k++)
2094                {
2095                    if(originalPixels.get(j).x==tg.Pixels.get(k).x && originalPixels.get(j).y==tg.Pixels.get(k).y)
2096                    {
2097                        n=j;
2098                        foundPt=true;
2099                        break;
2100                    }
2101                }
2102                if(foundPt)
2103                    break;
2104            }
2105            HashMap<Integer,Color> hmap=getMSRSegmentColors(tg);
2106            //use a 2nd hashmap to store the revised segment numbers, and exisitng Colors
2107            HashMap<Integer,Color> hmap2=new HashMap<Integer,Color>();
2108            POINT2 segPt0=null,segPt1=null; //the original segments
2109            POINT2 pt0=null,pt1=null;   //the clipped segments
2110            Color color=null;
2111            if(n<1)
2112                n=1;
2113            for(Integer key : hmap.keySet()) //keys can begin at 0
2114            {
2115                if(key<n-1)
2116                    continue;
2117                if(key+1>originalPixels.size()-1)
2118                    break;
2119                color=hmap.get(key);
2120                segPt0=originalPixels.get(key);
2121                segPt1=originalPixels.get(key+1);
2122                u=tg.Pixels.size();
2123                //for(j=0;j<tg.Pixels.size()-1;j++)
2124                for(j=0;j<u-1;j++)
2125                {
2126                    pt0=tg.Pixels.get(j);//clipped pixels
2127                    pt1=tg.Pixels.get(j+1);
2128                    if(segPt0.x==pt0.x && segPt0.y==pt0.y)
2129                    {
2130                        hmap2.put(j, color);
2131                        break;
2132                    }
2133                    else if(segPt1.x==pt1.x && segPt1.y==pt1.y)
2134                    {
2135                        hmap2.put(j, color);
2136                        break;
2137                    }
2138                    else
2139                    {
2140                        if(pt0.x==segPt1.x && pt0.y==segPt1.y)
2141                            continue;
2142                        if(pt1.x==segPt0.x && pt1.y==segPt0.y)
2143                            continue;
2144                        else    
2145                        {       
2146                            //if the original segment straddles or clips the clipping area
2147                            //then the original segment will contain the clipped segment
2148                            double dist0=lineutility.CalcDistanceToLineDouble(segPt0, segPt1, pt0);
2149                            double dist1=lineutility.CalcDistanceToLineDouble(segPt0, segPt1, pt1);
2150                            Line2D lineOrigPts=new Line2D.Double(segPt0.x,segPt0.y, segPt1.x,segPt1.y);
2151                            Rectangle2D rectOrigPts=lineOrigPts.getBounds2D();
2152                            Line2D lineClipPts=new Line2D.Double(pt0.x,pt0.y, pt1.x, pt1.y);
2153                            Rectangle2D rectClipPts=lineClipPts.getBounds2D();
2154                            //test if the lines coincide and the clipped segment is within the original segment
2155                            if(dist0<1 && dist1<1 && rectOrigPts.contains(rectClipPts))
2156                            {
2157                                hmap2.put(j, color);                                
2158                            }
2159                        }
2160                    }
2161                }
2162            }        
2163            if(hmap2.isEmpty())
2164            {
2165                tg.set_H("");
2166                return;
2167            }
2168           
2169            String h="",temp="";
2170            for(Integer key : hmap2.keySet()) 
2171            {
2172                color=hmap2.get(key);
2173                temp=Integer.toHexString(color.toARGB());
2174                h+=key.toString()+":"+temp+",";
2175            }
2176            h=h.substring(0, h.length()-1);
2177            tg.set_H(h);
2178        }
2179        catch (Exception exc) {
2180            ErrorLogger.LogException(_className, "reviseHModifer",
2181                    new RendererException("Failed inside reviseHModifier", exc));
2182        }
2183    }
2184
2185    /**
2186     * Adds extra points to LC if there are angles too small to fit the channel
2187     * @param tg
2188     * @param converter
2189     */
2190    public static void SegmentLCPoints(TGLight tg, IPointConversion converter) {
2191        try {
2192            if (tg.get_LineType() != TacticalLines.LC)
2193                return;
2194
2195            ArrayList<POINT2> points = tg.get_Pixels();
2196
2197            double LCChannelWith = arraysupport.getScaledSize(40, tg.get_LineThickness(), tg.get_patternScale());
2198
2199            for (int i = 0; i < points.size() - 2; i++) {
2200                POINT2 ptA = new POINT2(points.get(i).x, points.get(i).y);
2201                POINT2 ptB = new POINT2(points.get(i+1).x, points.get(i+1).y);
2202                POINT2 ptC = new POINT2(points.get(i+2).x, points.get(i+2).y);
2203
2204                double angle1 = Math.atan2(ptB.y - ptA.y, ptB.x - ptA.x);
2205                double angle2 = Math.atan2(ptB.y - ptC.y, ptB.x - ptC.x);
2206                double angle = angle1 - angle2;
2207                double degrees = angle * 180/Math.PI;
2208
2209                if(angle < 0) {
2210                    degrees = 360 + degrees;
2211                }
2212
2213                if (degrees > 270) {
2214                    // For acute angles where red is the outer line
2215                    // Determine shorter segment (BA or BC)
2216                    // On longer segment calculate potential new point (newPt) that is length of smaller segment from B
2217                    // If distance between smaller segment end point (A or C) and newPt is smaller than the channel width add newPt to points
2218                    // In GetLCPartitions() the black line won't be included between the smaller line and newPt since there isn't enough space to fit the channel
2219                    if (lineutility.CalcDistanceDouble(ptB, ptA) < lineutility.CalcDistanceDouble(ptB, ptC)) {
2220                        // BA is smaller segment
2221                        POINT2 newPt = lineutility.ExtendAlongLineDouble2(ptB, ptC, lineutility.CalcDistanceDouble(ptB, ptA));
2222                        if (lineutility.CalcDistanceDouble(ptA, newPt) < LCChannelWith) {
2223                            points.add(i + 2, new POINT2(newPt.x, newPt.y));
2224                            i++;
2225                        }
2226                    } else {
2227                        // BC is smaller segment
2228                        POINT2 newPt = lineutility.ExtendAlongLineDouble2(ptB, ptA, lineutility.CalcDistanceDouble(ptB, ptC));
2229                        if (lineutility.CalcDistanceDouble(ptC, newPt) < LCChannelWith) {
2230                            points.add(i + 1, new POINT2(newPt.x, newPt.y));
2231                            i++;
2232                        }
2233                    }
2234                }
2235            }
2236            tg.Pixels = points;
2237            tg.LatLongs = armyc2.c5isr.RenderMultipoints.clsUtility.PixelsToLatLong(points, converter);
2238        } catch (Exception exc) {
2239            ErrorLogger.LogException(_className, "segmentLCPoints",
2240                    new RendererException("Failed inside segmentLCPoints", exc));
2241        }
2242    }
2243    /**
2244     * Interpolate pixels for lines with points too close together.
2245     * Drops successive points until the next point is at least 10 pixels from the preceding point
2246     * @param tg 
2247     */
2248    public static void InterpolatePixels(TGLight tg)
2249    {
2250        try
2251        {
2252            if(tg.get_UseLineInterpolation()==false)
2253                return;
2254            
2255            int linetype=tg.get_LineType();
2256            double glyphSize=10;
2257            switch(linetype)
2258            {
2259                case TacticalLines.ATDITCH:
2260                case TacticalLines.ATDITCHC:
2261                    glyphSize=25;
2262                    break;
2263                case TacticalLines.ATDITCHM:
2264                    glyphSize=50;
2265                    break;
2266                case TacticalLines.FLOT:
2267                case TacticalLines.LC:
2268                case TacticalLines.FORT_REVD:
2269                case TacticalLines.FORT:
2270                case TacticalLines.FORTL:
2271                case TacticalLines.ENCIRCLE:
2272                case TacticalLines.ZONE:
2273                case TacticalLines.OBSFAREA:
2274                case TacticalLines.OBSAREA:
2275                case TacticalLines.DOUBLEA:
2276                case TacticalLines.LWFENCE:
2277                case TacticalLines.HWFENCE:
2278                case TacticalLines.BBS_LINE:
2279                case TacticalLines.SINGLEC:
2280                case TacticalLines.DOUBLEC:
2281                case TacticalLines.TRIPLE:
2282                case TacticalLines.STRONG:
2283                    glyphSize= arraysupport.getScaledSize(30, tg.get_LineThickness(), tg.get_patternScale());
2284                    break;
2285                case TacticalLines.UNSP:
2286                case TacticalLines.LINE:
2287                case TacticalLines.ATWALL:
2288                case TacticalLines.SFENCE:
2289                    glyphSize=arraysupport.getScaledSize(40, tg.get_LineThickness(), tg.get_patternScale());
2290                    break;
2291                case TacticalLines.DFENCE:
2292                    glyphSize=arraysupport.getScaledSize(50, tg.get_LineThickness(), tg.get_patternScale());
2293                    break;
2294                default:
2295                    return;
2296            }
2297            HashMap<Integer,POINT2> hmapPixels=new HashMap<Integer,POINT2>();
2298            HashMap<Integer,POINT2> hmapGeo=new HashMap<Integer,POINT2>();
2299            int j=0,currentIndex=0;
2300            double dist=0,dist2=0;
2301            double direction1=0,direction2=0,delta=0;
2302            POINT2 pt0=null,pt1=null,pt2=null;
2303            int n=tg.Pixels.size();
2304            //for(j=0;j<tg.Pixels.size();j++)
2305            for(j=0;j<n;j++)
2306            {
2307                if(j==0)
2308                {
2309                    hmapPixels.put(j, tg.Pixels.get(j));
2310                    hmapGeo.put(j, tg.LatLongs.get(j));
2311                    currentIndex=0;
2312                }
2313                else if(j==tg.Pixels.size()-1)
2314                {
2315                    hmapPixels.put(j, tg.Pixels.get(j));
2316                    hmapGeo.put(j, tg.LatLongs.get(j));                    
2317                }
2318                else
2319                {
2320                    dist=lineutility.CalcDistanceDouble(tg.Pixels.get(currentIndex), tg.Pixels.get(j));
2321                    dist2=lineutility.CalcDistanceDouble(tg.Pixels.get(j), tg.Pixels.get(j+1));
2322                    
2323                    //change of direction test 2-28-13
2324                    pt0=tg.Pixels.get(currentIndex);
2325                    pt1=tg.Pixels.get(j);
2326                    pt2=tg.Pixels.get(j+1);
2327                    direction1=(180/Math.PI)*Math.atan((pt0.y-pt1.y)/(pt0.x-pt1.x));
2328                    direction2=(180/Math.PI)*Math.atan((pt1.y-pt2.y)/(pt1.x-pt2.x));
2329                    delta=Math.abs(direction1-direction2);
2330                    if(dist>glyphSize || dist2>glyphSize || delta>20)
2331                    {
2332                        hmapPixels.put(j, tg.Pixels.get(j));
2333                        hmapGeo.put(j, tg.LatLongs.get(j));
2334                        currentIndex=j;
2335                    }
2336                }
2337            }
2338            ArrayList<POINT2>pixels=new ArrayList();
2339            ArrayList<POINT2>geo=new ArrayList();
2340            n=tg.Pixels.size();
2341            //for(j=0;j<tg.Pixels.size();j++)
2342            for(j=0;j<n;j++)
2343            {
2344                if(hmapPixels.containsKey(j))
2345                    pixels.add((POINT2)hmapPixels.get(j));
2346                if(hmapGeo.containsKey(j))
2347                    geo.add((POINT2)hmapGeo.get(j));
2348            }
2349            switch(linetype)
2350            {
2351                case TacticalLines.FORT_REVD:
2352                case TacticalLines.FORT:
2353                case TacticalLines.ENCIRCLE:
2354                case TacticalLines.ZONE:
2355                case TacticalLines.OBSFAREA:
2356                case TacticalLines.OBSAREA:
2357                case TacticalLines.STRONG:
2358                    if(pixels.size()==2)
2359                    {
2360                        n=tg.Pixels.size();
2361                        //for(j=0;j<tg.Pixels.size();j++)
2362                        for(j=0;j<n;j++)
2363                        {
2364                            if(hmapPixels.containsKey(j)==false && hmapGeo.containsKey(j)==false)
2365                            {
2366                                pixels.add(j,tg.Pixels.get(j));
2367                                geo.add(j,tg.LatLongs.get(j));
2368                                break;
2369                            }
2370                        }                        
2371                    }
2372                    break;
2373                default:
2374                    break;
2375            }            
2376            tg.Pixels=pixels;
2377            tg.LatLongs=geo;
2378        }
2379        catch (Exception exc) {
2380            ErrorLogger.LogException(_className, "InterpolatePixels",
2381                    new RendererException("Failed inside InterpolatePixels", exc));
2382        }
2383    }
2384    /**
2385     * construct a line segment outside the polygon corresponding to some index
2386     * @param tg
2387     * @param index
2388     * @param dist
2389     * @return 
2390     */
2391    protected static Line2D getExtendedLine(TGLight tg,
2392            int index,
2393            double dist)
2394    {
2395        Line2D line=null;
2396        try
2397        {
2398            Polygon polygon=new Polygon();
2399            int j=0;
2400            int n=tg.Pixels.size();
2401            //for(j=0;j<tg.Pixels.size();j++)
2402            for(j=0;j<n;j++)
2403            {
2404                polygon.addPoint((int)tg.Pixels.get(j).x, (int)tg.Pixels.get(j).y);
2405            }
2406            POINT2 pt0=null; 
2407            POINT2 pt1=null; 
2408            if(tg.Pixels.size()>3)
2409            {
2410                pt0=tg.Pixels.get(index);
2411                pt1=tg.Pixels.get(index+1);
2412            }
2413            else
2414            {
2415                pt0=tg.Pixels.get(1);
2416                pt1=tg.Pixels.get(2);                
2417            }
2418            
2419            POINT2 ptExtend=null;
2420            int extend=-1;
2421            POINT2 midPt=lineutility.MidPointDouble(pt0, pt1,0);
2422            double slope=Math.abs(pt1.y-pt0.y)/(pt1.x-pt0.x);
2423            if(slope<=1)
2424            {
2425                ptExtend=lineutility.ExtendDirectedLine(pt0, pt1, midPt, lineutility.extend_above, 2);
2426                if(polygon.contains(ptExtend.x,ptExtend.y))
2427                    extend=lineutility.extend_below;
2428                else
2429                    extend=lineutility.extend_above;
2430            }
2431            else
2432            {
2433                ptExtend=lineutility.ExtendDirectedLine(pt0, pt1, midPt, lineutility.extend_left, 2);
2434                if(polygon.contains(ptExtend.x,ptExtend.y))
2435                    extend=lineutility.extend_right;
2436                else
2437                    extend=lineutility.extend_left;
2438                
2439            }
2440            POINT2 pt3=null;
2441            POINT2 pt4=null;
2442            pt3=lineutility.ExtendDirectedLine(pt0, pt1, pt0, extend, dist);
2443            pt4=lineutility.ExtendDirectedLine(pt0, pt1, pt1, extend, dist);
2444            line=new Line2D.Double(pt3.x, pt3.y, pt4.x, pt4.y);
2445        }
2446        catch (Exception exc) {            
2447            ErrorLogger.LogException(_className, "getExtendedLine",
2448                    new RendererException("Failed inside getExtendedLine", exc));
2449        }
2450        return line;
2451    }
2452
2453}//end clsUtility