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