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