001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005
006package armyc2.c5isr.RenderMultipoints;
007import static armyc2.c5isr.JavaTacticalRenderer.clsUtility.isAutoshape;
008
009import armyc2.c5isr.graphics2d.Area;
010import armyc2.c5isr.graphics2d.BasicStroke;
011import armyc2.c5isr.graphics2d.Rectangle;
012import armyc2.c5isr.renderer.PatternFillRenderer;
013import armyc2.c5isr.renderer.utilities.IPointConversion;
014import armyc2.c5isr.JavaTacticalRenderer.TGLight;
015import armyc2.c5isr.JavaLineArray.TacticalLines;
016import armyc2.c5isr.JavaLineArray.lineutility;
017import armyc2.c5isr.JavaLineArray.POINT2;
018import java.util.ArrayList;
019import armyc2.c5isr.renderer.utilities.ErrorLogger;
020import armyc2.c5isr.renderer.utilities.RendererException;
021import armyc2.c5isr.JavaLineArray.Shape2;
022
023import android.graphics.BitmapShader;
024import android.graphics.Shader;
025import armyc2.c5isr.renderer.utilities.Color;
026import armyc2.c5isr.renderer.utilities.ShapeInfo;
027import armyc2.c5isr.graphics2d.Point;
028import armyc2.c5isr.graphics2d.Point2D;
029import armyc2.c5isr.graphics2d.Rectangle2D;
030
031/**
032 * Server general utility class
033*
034 */
035public final class clsUtility {
036    private static final String _className="clsUtility";
037    public static final int Hatch_ForwardDiagonal=2;
038    public static final int Hatch_BackwardDiagonal=3;
039    public static final int Hatch_Vertical=4;
040    public static final int Hatch_Horizontal=5;
041    public static final int Hatch_Cross=8;
042
043    /**
044     * Adds hatch fill to shapes via PatternFillRendererD.MakeHatchPatternFill() or buildHatchFill()
045     * @param tg
046     * @param shapes
047     */
048    protected static void addHatchFills(TGLight tg, ArrayList<ShapeInfo>shapes)
049    {
050        try
051        {
052            if(shapes==null || shapes.size()==0)
053                return;
054
055            int lineType=tg.get_LineType();
056            int hatchStyle=tg.get_FillStyle();
057            int j=0,hatch2=0;
058            Shape2 shape2=null;
059            int index=0;
060            float hatchLineThickness = 1.5f + ((tg.get_LineThickness() / 2f) - 1.5f) * (float) tg.get_patternScale();
061            Color hatchColor = tg.get_LineColor();
062            int hatchSpacing = (int) (hatchLineThickness * 10);
063
064//            if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(lineType)==false)
065//                if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(lineType, null)==false)
066//                    return;
067            if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(lineType)==false)
068            {
069                if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(lineType)==false)
070                {
071                    switch(lineType)
072                    {
073                        case TacticalLines.BBS_AREA:
074                        case TacticalLines.BBS_LINE:
075                        case TacticalLines.BBS_RECTANGLE:
076                            break;
077                        default:
078                            return;
079                    }
080                }
081            }
082
083            switch(lineType)
084            {
085                case TacticalLines.NFA:
086                case TacticalLines.NFA_CIRCULAR:
087                case TacticalLines.NFA_RECTANGULAR:
088                case TacticalLines.LAA:
089                    hatchStyle = Hatch_BackwardDiagonal;
090                    break;
091                case TacticalLines.BIO:
092                case TacticalLines.NUC:
093                case TacticalLines.CHEM:
094                case TacticalLines.RAD:
095                    hatchStyle=Hatch_BackwardDiagonal;
096                    hatchColor = Color.yellow;
097                    hatchLineThickness = 3 + (tg.get_LineThickness() - 3) * (float) tg.get_patternScale();
098                    break;
099                case TacticalLines.WFZ_REVD:
100                case TacticalLines.WFZ:
101                    hatchStyle=Hatch_BackwardDiagonal;
102                    if (tg.get_LineColor() == Color.BLACK)
103                        hatchColor = Color.GRAY;
104                    hatchSpacing /= 2;
105                    break;
106                case TacticalLines.OBSAREA:
107                    //CPOF client required adding a simple shape for
108                    //setting texturepaint which WebRenderer does not use
109                    for(j=0;j<shapes.size();j++)
110                    {
111                        ShapeInfo shape=shapes.get(j);
112                        Color color=shape.getLineColor();
113                        if(color==null)
114                            continue;
115                        //if(shape.getLineColor().getRGB()==0)
116                        if(shape.getLineColor().toARGB()==0)
117                            shapes.remove(j);
118                    }
119                    hatchStyle = Hatch_BackwardDiagonal;
120                    hatchSpacing *= 1.25;
121                    break;
122                default:
123                    if(hatchStyle<=0)
124                        return;
125                    break;
126            }
127            //get the index of the shape with the same fillstyle
128            int n=shapes.size();
129            //for(j=0;j<shapes.size();j++)
130            for(j=0;j<n;j++)
131            {
132                shape2=(Shape2)shapes.get(j);
133                hatch2=shape2.get_FillStyle();
134                if(hatch2==hatchStyle)
135                {
136                    index=j;
137                    break;
138                }
139            }
140            n=shapes.size();
141            //for(int k=0;k<shapes.size();k++)
142            for(int k=0;k<n;k++)
143            {
144                //the outline should always be the 0th shape for areas
145                ShapeInfo shape=null;
146                if(lineType==TacticalLines.RANGE_FAN || lineType==TacticalLines.RANGE_FAN_SECTOR || lineType==TacticalLines.RADAR_SEARCH)
147                {
148                    shape=shapes.get(k);
149                    shape2=(Shape2)shapes.get(k);
150                    hatchStyle=shape2.get_FillStyle();
151                }
152                else
153                    shape=shapes.get(index);
154
155                if(hatchStyle<Hatch_ForwardDiagonal)//Hatch_ForwardDiagonal is the 0th hatch element
156                    continue;
157
158                if (tg.get_UseHatchFill())
159                {
160                    shape.setPatternFillImage(PatternFillRenderer.MakeHatchPatternFill(hatchStyle, hatchSpacing, (int) hatchLineThickness, hatchColor));
161                    shape.setShader(new BitmapShader(shape.getPatternFillImage(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
162                }
163                else if(hatchStyle != Hatch_Cross)
164                {
165                    Shape2 shape3= buildHatchArea(tg, shape,hatchStyle, hatchSpacing);
166                    //shape.setStroke(new BasicStroke(1));
167                    shape3.setStroke(new BasicStroke(hatchLineThickness));
168                    shape3.setLineColor(hatchColor);
169                    shapes.add(shape3);
170                }
171                else    //cross hatch
172                {
173                    Shape2 shapeBk= buildHatchArea(tg, shape,Hatch_BackwardDiagonal,hatchSpacing);
174                    Shape2 shapeFwd= buildHatchArea(tg, shape,Hatch_ForwardDiagonal,hatchSpacing);
175                    //shapeBk.setStroke(new BasicStroke(1));
176                    shapeBk.setStroke(new BasicStroke(hatchLineThickness));
177                    shapeBk.setLineColor(hatchColor);
178                    shapes.add(shapeBk);
179                    //shapeFwd.setStroke(new BasicStroke(1));
180                    shapeFwd.setStroke(new BasicStroke(hatchLineThickness));
181                    shapeFwd.setLineColor(hatchColor);
182                    shapes.add(shapeFwd);
183                }
184                if(lineType != TacticalLines.RANGE_FAN && lineType != TacticalLines.RANGE_FAN_SECTOR && lineType != TacticalLines.RADAR_SEARCH)
185                    break;
186            }
187        }
188        catch (Exception exc) {
189            ErrorLogger.LogException(_className, "addHatchFills",
190                    new RendererException("Failed inside addHatchFills", exc));
191        }
192    }
193
194    /**
195     * Build Hatch fill. Does not use texture paint or shader.
196     * @param tg
197     * @param shape
198     * @param hatchStyle
199     * @return
200     */
201    protected static Shape2 buildHatchArea(TGLight tg, ShapeInfo shape, int hatchStyle, double spacing)
202    {
203        Shape2 hatchLineShape=null;
204        try
205        {
206            hatchLineShape=new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
207            Area hatchLineArea=null;
208            Rectangle rect=shape.getBounds();
209            double x0=rect.getX();
210            double y0=rect.getY();
211            double width=rect.getWidth();
212            double height=rect.getHeight();
213            //we need a square
214            if(width>height)
215                height=width;
216            else
217                width=height;
218
219            //diagnostic
220            if(tg.get_UseHatchFill())
221            {
222//                hatchLineShape.moveTo(new POINT2(x0,y0));
223//                hatchLineShape.lineTo(new POINT2(x0+width,y0));
224//                hatchLineShape.lineTo(new POINT2(x0+width,y0+width));
225//                hatchLineShape.lineTo(new POINT2(x0,y0+width));
226                hatchLineShape.set_Fillstyle(hatchStyle);
227//                hatchLineShape.lineTo(new POINT2(x0,y0));
228//                Area shapeArea=new Area(shape.getShape());
229//                hatchLineArea=new Area(hatchLineShape.getShape());
230//                //intersect the hatch lines with the original shape area to get the fill
231//                hatchLineArea.intersect(shapeArea);
232//                hatchLineShape.setShape(hatchLineArea);
233                hatchLineShape.setShape(lineutility.createStrokedShape(shape.getShape()));
234                return hatchLineShape;
235            }
236            //end section
237
238            width *= 2;
239            height *= 2;
240            //the next two values should be equal
241            int horizLimit=0;
242            int vertLimit=0;
243            int j=0;
244            ArrayList<POINT2>vertPts=new ArrayList();
245            ArrayList<POINT2>horizPts=new ArrayList();
246            POINT2 vertPt=null,horizPt=null;
247            if(hatchStyle==Hatch_BackwardDiagonal)
248            {
249                horizLimit=(int)(width/spacing);
250                vertLimit=(int)(height/spacing);
251                for(j=0;j<vertLimit;j++)
252                {
253                    vertPt=new POINT2(x0,y0+spacing*j);
254                    vertPts.add(vertPt);
255                }
256                for(j=0;j<horizLimit;j++)
257                {
258                    horizPt=new POINT2(x0+spacing*j,y0);
259                    horizPts.add(horizPt);
260                }
261
262                hatchLineShape.moveTo(new POINT2(x0-spacing/2,y0-spacing/2));
263                hatchLineShape.lineTo(new POINT2(x0,y0));
264                for(j=0;j<vertLimit;j++)
265                {
266                    if(j%2==0)
267                    {
268                        hatchLineShape.lineTo(vertPts.get(j));
269                        hatchLineShape.lineTo(horizPts.get(j));
270                    }
271                    else
272                    {
273                        hatchLineShape.lineTo(horizPts.get(j));
274                        hatchLineShape.lineTo(vertPts.get(j));
275                    }
276                }
277                //go outside the bottom right corner to complete a valid area
278                hatchLineShape.lineTo(new POINT2(x0+width+spacing/2,y0+height+spacing/2));
279                hatchLineShape.lineTo(new POINT2(x0+width+spacing,y0+height+spacing/2));
280                hatchLineShape.lineTo(new POINT2(x0+width+spacing,y0-spacing/2));
281                hatchLineShape.lineTo(new POINT2(x0-spacing/2,y0-spacing/2));
282            }
283            if(hatchStyle==Hatch_ForwardDiagonal)
284            {
285                horizLimit=(int)(width/spacing);
286                vertLimit=(int)(height/spacing);
287                width /= 2;
288                for(j=0;j<vertLimit;j++)
289                {
290                    vertPt=new POINT2(x0+width,y0+spacing*j);
291                    vertPts.add(vertPt);
292                }
293                for(j=0;j<horizLimit;j++)
294                {
295                    horizPt=new POINT2(x0+width-spacing*j,y0);
296                    horizPts.add(horizPt);
297                }
298
299                hatchLineShape.moveTo(new POINT2(x0+width+spacing/2,y0-spacing/2));
300                hatchLineShape.lineTo(new POINT2(x0,y0));
301                for(j=0;j<vertLimit;j++)
302                {
303                    if(j%2==0)
304                    {
305                        hatchLineShape.lineTo(vertPts.get(j));
306                        hatchLineShape.lineTo(horizPts.get(j));
307                    }
308                    else
309                    {
310                        hatchLineShape.lineTo(horizPts.get(j));
311                        hatchLineShape.lineTo(vertPts.get(j));
312                    }
313                }
314                //go outside the bottom left corner to complete a valid area
315                hatchLineShape.lineTo(new POINT2(x0-spacing/2,y0+height+spacing/2));
316                hatchLineShape.lineTo(new POINT2(x0-spacing,y0+height+spacing/2));
317                hatchLineShape.lineTo(new POINT2(x0-spacing,y0-spacing/2));
318                hatchLineShape.lineTo(new POINT2(x0+width+spacing/2,y0-spacing/2));
319            }
320            if(hatchStyle==Hatch_Vertical)
321            {
322                horizLimit=(int)(width/(spacing/2));
323                vertLimit=(int)(height/(spacing/2));
324                for(j=0;j<horizLimit;j++)
325                {
326                    if(j%2==0)
327                    {
328                        vertPt=new POINT2(x0+spacing/2*j,y0);
329                        vertPts.add(vertPt);
330                        vertPt=new POINT2(x0+spacing/2*j,y0+height);
331                        vertPts.add(vertPt);
332                    }
333                    else
334                    {
335                        vertPt=new POINT2(x0+spacing/2*j,y0+height);
336                        vertPts.add(vertPt);
337                        vertPt=new POINT2(x0+spacing/2*j,y0);
338                        vertPts.add(vertPt);
339                    }
340                }
341                hatchLineShape.moveTo(new POINT2(x0-spacing/2,y0-spacing/2));
342                hatchLineShape.lineTo(new POINT2(x0,y0));
343                for(j=0;j<vertLimit-1;j++)
344                {
345                    hatchLineShape.lineTo(vertPts.get(j));
346                }
347                //go outside the bottom right corner to complete a valid area
348                hatchLineShape.lineTo(new POINT2(x0+width+spacing/2,y0+height+spacing/2));
349                hatchLineShape.lineTo(new POINT2(x0+width+spacing,y0+height+spacing/2));
350                hatchLineShape.lineTo(new POINT2(x0+width+spacing,y0-spacing/2));
351                hatchLineShape.lineTo(new POINT2(x0-spacing/2,y0-spacing/2));
352            }
353            if(hatchStyle==Hatch_Horizontal)
354            {
355                horizLimit=(int)(width/(spacing/2));
356                vertLimit=(int)(height/(spacing/2));
357                for(j=0;j<vertLimit;j++)
358                {
359                    if(j%2==0)
360                    {
361                        horizPt=new POINT2(x0,y0+spacing/2*j);
362                        horizPts.add(horizPt);
363                        horizPt=new POINT2(x0+width,y0+spacing/2*j);
364                        horizPts.add(horizPt);
365                    }
366                    else
367                    {
368                        horizPt=new POINT2(x0+width,y0+spacing/2*j);
369                        horizPts.add(horizPt);
370                        horizPt=new POINT2(x0,y0+spacing/2*j);
371                        horizPts.add(horizPt);
372                    }
373                }
374                hatchLineShape.moveTo(new POINT2(x0-spacing/2,y0-spacing/2));
375                hatchLineShape.lineTo(new POINT2(x0,y0));
376                for(j=0;j<vertLimit-1;j++)
377                {
378                    hatchLineShape.lineTo(horizPts.get(j));
379                }
380                //go outside the bottom left corner to complete a valid area
381                hatchLineShape.lineTo(new POINT2(x0-spacing/2,y0+height+spacing/2));
382                hatchLineShape.lineTo(new POINT2(x0-spacing,y0+height+spacing/2));
383                hatchLineShape.lineTo(new POINT2(x0-spacing,y0-spacing/2));
384                hatchLineShape.lineTo(new POINT2(x0+width+spacing/2,y0-spacing/2));
385            }
386
387            Area shapeArea=new Area(shape.getShape());
388            hatchLineArea=new Area(hatchLineShape.getShape());
389            //intersect the hatch lines with the original shape area to get the fill
390            hatchLineArea.intersect(shapeArea);
391            hatchLineShape.setShape(hatchLineArea);
392            //return null;
393        }
394        catch(Exception exc)
395        {
396            ErrorLogger.LogException(_className, "buildHatchArea",
397                    new RendererException("Failed inside buildHatchArea", exc));
398        }
399        return hatchLineShape;
400    }
401
402    protected static Point POINT2ToPoint(POINT2 pt2)
403    {
404        Point pt=new Point();
405        pt.x=(int)pt2.x;
406        pt.y=(int)pt2.y;
407        return pt;
408    }
409    protected static POINT2 PointToPOINT2(Point pt)
410    {
411        POINT2 pt2=new POINT2(pt.x,pt.y);
412        return pt2;
413    }
414    protected static Point2D.Double POINT2ToPoint2D(POINT2 pt2)
415    {
416        Point2D.Double pt2d=new Point2D.Double(pt2.x,pt2.y);
417        return pt2d;
418    }
419    protected static ArrayList<POINT2> Points2DToPOINT2(ArrayList<Point2D>pts2d)
420    {
421        ArrayList<POINT2>pts=new ArrayList();
422        POINT2 pt=null;
423        int n=pts2d.size();
424        //for(int j=0;j<pts2d.size();j++)        
425        for(int j=0;j<n;j++)        
426        {
427            pt=new POINT2(pts2d.get(j).getX(),pts2d.get(j).getY());
428            pts.add(pt);
429        }        
430        return pts;
431    }
432    protected static POINT2 Point2DToPOINT2(Point2D pt2d)
433    {
434        POINT2 pt2=new POINT2(pt2d.getX(),pt2d.getY());
435        return pt2;
436    }
437    /**
438     * @deprecated   
439     * @param tg
440     * @return 
441     */
442    protected static boolean addModifiersBeforeClipping(TGLight tg)
443    {
444        boolean result=false;
445        int linetype=tg.get_LineType();
446        switch(linetype)
447        {
448            case TacticalLines.TORPEDO:
449            case TacticalLines.OPTICAL:
450            case TacticalLines.ELECTRO:
451            case TacticalLines.BEARING_EW:
452            case TacticalLines.ACOUSTIC:
453            case TacticalLines.ACOUSTIC_AMB:
454            case TacticalLines.BEARING:
455            case TacticalLines.BEARING_J:
456            case TacticalLines.BEARING_RDF:
457            case TacticalLines.MSR:
458            case TacticalLines.MSR_ONEWAY:
459            case TacticalLines.MSR_TWOWAY:
460            case TacticalLines.MSR_ALT:
461            case TacticalLines.ASR:
462            case TacticalLines.ASR_ONEWAY:
463            case TacticalLines.ASR_TWOWAY:
464            case TacticalLines.ASR_ALT:
465            case TacticalLines.ROUTE:
466            case TacticalLines.ROUTE_ONEWAY:
467            case TacticalLines.ROUTE_ALT:
468            case TacticalLines.HCONVOY:
469            case TacticalLines.CONVOY:
470            case TacticalLines.MFP:
471            case TacticalLines.RFL:
472            case TacticalLines.NFL:
473            case TacticalLines.CFL:
474            case TacticalLines.TRIP:
475            case TacticalLines.FSCL:
476            case TacticalLines.BCL_REVD:
477            case TacticalLines.BCL:
478            case TacticalLines.ICL:
479            case TacticalLines.IFF_OFF:
480            case TacticalLines.IFF_ON:
481            case TacticalLines.GENERIC_LINE:
482            case TacticalLines.FPF:
483            case TacticalLines.LINTGT:
484            case TacticalLines.LINTGTS:
485            case TacticalLines.MSDZ:
486            case TacticalLines.GAP:
487            case TacticalLines.IL:
488            case TacticalLines.DIRATKAIR:
489            case TacticalLines.PDF:
490            case TacticalLines.AC:
491            case TacticalLines.SAAFR:
492            case TacticalLines.LLTR:
493            case TacticalLines.SC:
494            case TacticalLines.MRR:
495            case TacticalLines.SL:
496            case TacticalLines.TC:
497            case TacticalLines.BOUNDARY:
498            case TacticalLines.WDRAWUP:
499            case TacticalLines.WITHDRAW:
500            case TacticalLines.DISENGAGE:
501            case TacticalLines.RETIRE:
502            case TacticalLines.FPOL:
503            case TacticalLines.RPOL:
504            case TacticalLines.RIP:
505            case TacticalLines.MOBILE_DEFENSE:
506            case TacticalLines.DEMONSTRATE:
507            case TacticalLines.DELAY:
508            case TacticalLines.CATK:
509            case TacticalLines.CATKBYFIRE:
510            case TacticalLines.SCREEN:
511            case TacticalLines.COVER:
512            case TacticalLines.GUARD:
513            case TacticalLines.FLOT:
514            case TacticalLines.LC:
515            case TacticalLines.PL:
516            case TacticalLines.FEBA:
517            case TacticalLines.LL:
518            case TacticalLines.EWL:
519            case TacticalLines.FCL:
520            case TacticalLines.HOLD:
521            case TacticalLines.BRDGHD:
522            case TacticalLines.HOLD_GE:
523            case TacticalLines.BRDGHD_GE:
524            case TacticalLines.LOA:
525            case TacticalLines.LOD:
526            case TacticalLines.LDLC:
527            case TacticalLines.PLD:
528            case TacticalLines.RELEASE:
529            case TacticalLines.HOL:
530            case TacticalLines.BHL:
531                result = true;
532                break;
533            default:
534                break;
535        }
536        if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(linetype)==true)
537            result=true;
538        return result;
539    }
540
541    /**
542     * @deprecated
543     */
544    protected static void FilterPoints(TGLight tg)
545    {
546        try
547        {
548            int lineType = tg.get_LineType();
549            double minSpikeDistance = 0;
550            switch (lineType)
551            {
552                //case TacticalLines.LC:
553                case TacticalLines.ATDITCH:
554                case TacticalLines.ATDITCHC:
555                case TacticalLines.ATDITCHM:
556                case TacticalLines.FLOT:
557                case TacticalLines.FORT_REVD:
558                case TacticalLines.FORT:
559                case TacticalLines.FORTL:
560                case TacticalLines.STRONG:
561                    minSpikeDistance=25;
562                    break;
563                case TacticalLines.LC:
564                case TacticalLines.OBSAREA:
565                case TacticalLines.OBSFAREA:
566                case TacticalLines.ENCIRCLE:
567                case TacticalLines.ZONE:
568                case TacticalLines.LINE:
569                case TacticalLines.ATWALL:
570                case TacticalLines.UNSP:
571                case TacticalLines.SFENCE:
572                case TacticalLines.DFENCE:
573                case TacticalLines.DOUBLEA:
574                case TacticalLines.LWFENCE:
575                case TacticalLines.HWFENCE:
576                case TacticalLines.SINGLEC:
577                case TacticalLines.DOUBLEC:
578                case TacticalLines.TRIPLE:
579                    minSpikeDistance=35;
580                    break;
581                case TacticalLines.UCF:
582                case TacticalLines.CF:
583                case TacticalLines.CFG:
584                case TacticalLines.CFY:
585                    minSpikeDistance=60;
586                    break;
587                case TacticalLines.SF:
588                case TacticalLines.USF:
589                case TacticalLines.OCCLUDED:
590                case TacticalLines.UOF:
591                    minSpikeDistance=60;//was 120
592                    break;
593                case TacticalLines.SFG:
594                case TacticalLines.SFY:
595                    minSpikeDistance=60;//was 180
596                    break;
597                case TacticalLines.WFY:
598                case TacticalLines.WFG:
599                case TacticalLines.OFY:
600                    minSpikeDistance=60;//was 120
601                    break;
602                case TacticalLines.WF:
603                case TacticalLines.UWF:
604                    minSpikeDistance=40;
605                    break;
606
607                case TacticalLines.RIDGE:
608                case TacticalLines.ICE_EDGE_RADAR:  //METOCs
609                case TacticalLines.ICE_OPENINGS_FROZEN:
610                case TacticalLines.CRACKS_SPECIFIC_LOCATION:
611                    minSpikeDistance=35;
612                    break;
613                default:
614                    return;
615            }
616            int j=0;
617            double dist=0;
618            ArrayList<POINT2>pts=new ArrayList();
619            ArrayList<POINT2>ptsGeo=new ArrayList();
620            pts.add(tg.Pixels.get(0));
621            ptsGeo.add(tg.LatLongs.get(0));
622            POINT2 lastGoodPt=tg.Pixels.get(0);
623            POINT2 currentPt=null;
624            POINT2 currentPtGeo=null;
625            boolean foundGoodPt=false;
626            int n=tg.Pixels.size();
627            //for(j=1;j<tg.Pixels.size();j++)
628            for(j=1;j<n;j++)
629            {
630                //we can not filter out the original end points
631                currentPt=tg.Pixels.get(j);
632                currentPtGeo=tg.LatLongs.get(j);
633                if(currentPt.style==-1)
634                {
635                    lastGoodPt=currentPt;
636                    pts.add(currentPt);
637                    ptsGeo.add(currentPtGeo);
638                    foundGoodPt=true;
639                    currentPt.style=0;
640                    continue;
641                }
642                dist=lineutility.CalcDistanceDouble(lastGoodPt, currentPt);
643                switch(lineType)
644                {
645                    case TacticalLines.LC:
646                        if(dist>minSpikeDistance)
647                        {
648                            lastGoodPt=currentPt;
649                            pts.add(currentPt);
650                            ptsGeo.add(currentPtGeo);
651                            foundGoodPt=true;
652                        }
653                        else
654                        {   //the last point is no good
655                            //replace the last good point with the last point
656                            if(j==tg.Pixels.size()-1)
657                            {
658                                pts.set(pts.size()-1, currentPt);
659                                ptsGeo.set(ptsGeo.size()-1, currentPtGeo);
660                            }
661                        }
662                        break;
663                    default:
664                        if(dist>minSpikeDistance || j==tg.Pixels.size()-1)
665                        {
666                            lastGoodPt=currentPt;
667                            pts.add(currentPt);
668                            ptsGeo.add(currentPtGeo);
669                            foundGoodPt=true;
670                        }
671                        break;
672                }
673            }
674            if(foundGoodPt==true)
675            {
676                tg.Pixels=pts;
677                tg.LatLongs=ptsGeo;
678            }
679        }
680        catch(Exception exc)
681        {
682            ErrorLogger.LogException("clsUtility", "FilterPoints",
683                    new RendererException("Failed inside FilterPoints", exc));
684
685        }
686    }
687
688    public static ArrayList<POINT2> PixelsToLatLong(ArrayList<POINT2> pts, IPointConversion converter)
689    {
690        int j=0;
691        POINT2 pt=null;
692        POINT2 ptGeo=null;
693        ArrayList<POINT2> ptsGeo=new ArrayList();
694        int n=pts.size();
695        //for(j=0;j<pts.size();j++)
696        for(j=0;j<n;j++)
697        {
698            pt=pts.get(j);
699            ptGeo=PointPixelsToLatLong(pt,converter);
700            ptsGeo.add(ptGeo);
701        }
702        return ptsGeo;
703    }
704
705    protected static ArrayList<POINT2> LatLongToPixels(ArrayList<POINT2> pts, IPointConversion converter)
706    {
707        int j=0;
708        POINT2 pt=null;
709        POINT2 ptPixels=null;
710        ArrayList<POINT2> ptsPixels=new ArrayList();
711        int n=pts.size();
712        //for(j=0;j<pts.size();j++)
713        for(j=0;j<n;j++)
714        {
715            pt=pts.get(j);
716            ptPixels=PointLatLongToPixels(pt,converter);
717            ptsPixels.add(ptPixels);
718        }
719        return ptsPixels;
720    }
721
722    private static POINT2 PointLatLongToPixels(POINT2 ptLatLong,IPointConversion converter)
723    {
724        POINT2 pt2 = new POINT2();
725        try
726        {
727            Point2D pt2d=POINT2ToPoint2D(ptLatLong);            
728            pt2d=converter.GeoToPixels(pt2d);
729            pt2=Point2DToPOINT2(pt2d);
730            pt2.style=ptLatLong.style;
731        } catch (Exception e) {
732            armyc2.c5isr.JavaTacticalRenderer.clsUtility.WriteFile("Error in clsUtility.PointLatLongToPixels");
733        }
734        return pt2;
735    }
736
737    protected static void FilterAXADPoints(TGLight tg, IPointConversion converter) {
738        try {
739            int lineType = tg.get_LineType();
740            switch (lineType) {
741                case TacticalLines.CATK:
742                case TacticalLines.CATKBYFIRE:
743                case TacticalLines.AIRAOA:
744                case TacticalLines.AAAAA:
745                case TacticalLines.SPT:
746                case TacticalLines.FRONTAL_ATTACK:
747                case TacticalLines.TURNING_MOVEMENT:
748                case TacticalLines.MOVEMENT_TO_CONTACT:
749                case TacticalLines.MAIN:
750                    break;
751                default:
752                    return;
753            }
754            int j=0;
755            ArrayList<POINT2> pts = new ArrayList();
756            ArrayList<POINT2> ptsGeo = new ArrayList();
757            POINT2 pt0 = tg.Pixels.get(0);
758            POINT2 pt1 = tg.Pixels.get(1);
759
760            Point2D pt=new Point2D.Double(pt1.x,pt1.y);
761            Point2D pt1Geo2d=converter.PixelsToGeo(pt);
762
763            POINT2 pt1geo=new POINT2(pt1Geo2d.getX(),pt1Geo2d.getY());
764            POINT2 ptj=null,ptjGeo=null;
765            POINT2 controlPt=tg.Pixels.get(tg.Pixels.size()-1); //the control point
766            POINT2 pt0Relative=lineutility.PointRelativeToLine(pt0, pt1, pt0, controlPt);
767            double relativeDist=lineutility.CalcDistanceDouble(pt0Relative, controlPt);
768            relativeDist += 5;
769            double pt0pt1dist=lineutility.CalcDistanceDouble(pt0, pt1);
770            boolean foundGoodPoint=false;
771            if(relativeDist>pt0pt1dist)
772            {
773                //first point is too close, begin rebuilding the arrays
774                pts.add(pt0);
775                pt=new Point2D.Double(pt0.x,pt0.y);
776                pt1Geo2d=converter.PixelsToGeo(pt);
777
778                pt1geo=new POINT2(pt1Geo2d.getX(),pt1Geo2d.getY());
779                ptsGeo.add(pt1geo);
780                //create a good first point and add it to the array
781                pt1=lineutility.ExtendAlongLineDouble(pt0, pt1, relativeDist);
782                pts.add(pt1);
783
784                pt=new Point2D.Double(pt1.x,pt1.y);
785                pt1Geo2d=converter.PixelsToGeo(pt);
786                pt1geo=new POINT2(pt1Geo2d.getX(),pt1Geo2d.getY());
787                ptsGeo.add(pt1geo);
788            }
789            else
790            {
791                //the first point is good, there is no need to do anything
792                foundGoodPoint=true;
793                pts=tg.Pixels;
794                ptsGeo=tg.LatLongs;
795            }
796
797            //do not add mores points to the array until we find at least one good point
798            int n=tg.Pixels.size();
799            if(foundGoodPoint==false)
800            {
801                //for(j=2;j<tg.Pixels.size()-1;j++)
802                for(j=2;j<n-1;j++)
803                {
804                    ptj=tg.Pixels.get(j);
805                    ptjGeo=tg.LatLongs.get(j);
806                    if(foundGoodPoint)
807                    {
808                       //then stuff the remainder of the arrays with the original points
809                        pts.add(ptj);
810                        ptsGeo.add(ptjGeo);
811                    }
812                    else    //no good points yet
813                    {
814                        //calculate the distance and continue if it is no good
815                        pt0pt1dist=lineutility.CalcDistanceDouble(pt0, ptj);
816                        if(relativeDist>pt0pt1dist)
817                            continue;
818                        else
819                        {
820                           //found a good point
821                           pts.add(ptj);
822                           ptsGeo.add(ptjGeo);
823                           //set the boolean so that it will stuff the array with the rest of the points
824                           foundGoodPoint=true;
825                        }
826                    }
827                }
828                //finally add the control point to the arrays and set the arrays
829                pts.add(controlPt);
830                //pt1Geo2d=converter.convertPixelsToLonLat(controlPt.x, controlPt.y);
831                pt=new Point2D.Double(controlPt.x, controlPt.y);
832                pt1Geo2d=converter.PixelsToGeo(pt);
833
834                pt1geo=new POINT2(pt1Geo2d.getX(),pt1Geo2d.getY());
835                ptsGeo.add(pt1geo);
836            }   //end if foundGoodPoint is false
837
838            //add all the successive points which are far enough apart
839            POINT2 lastGoodPt=pts.get(1);
840            POINT2 currentPt=null;
841            POINT2 currentPtGeo=null;
842            double dist=0;
843            tg.Pixels=new ArrayList();
844            tg.LatLongs=new ArrayList();
845            for(j=0;j<2;j++)
846            {
847                tg.Pixels.add(pts.get(j));
848                tg.LatLongs.add(ptsGeo.get(j));
849            }
850            n=pts.size();
851            //for(j=2;j<pts.size()-1;j++)
852            for(j=2;j<n-1;j++)
853            {
854                currentPt=pts.get(j);
855                currentPtGeo=ptsGeo.get(j);
856                dist=lineutility.CalcDistanceDouble(currentPt, lastGoodPt);
857                if(dist>5)
858                {
859                    lastGoodPt=currentPt;
860                    tg.Pixels.add(currentPt);
861                    tg.LatLongs.add(currentPtGeo);
862                }
863            }
864            //add the control point
865            tg.Pixels.add(pts.get(pts.size()-1));
866            tg.LatLongs.add(ptsGeo.get(ptsGeo.size()-1));
867        }
868        catch (Exception exc) {
869            ErrorLogger.LogException("clsUtility", "FilterAXADPoints",
870                    new RendererException("Failed inside FilterAXADPoints", exc));
871
872        }
873    }
874    /**
875     *
876     * @param tg
877     */
878    protected static void RemoveDuplicatePoints(TGLight tg)
879    {
880        try
881        {
882            //do not remove autoshape duplicate points
883//            if(isAutoshape(tg))
884//                return;
885            switch (tg.get_LineType()) {
886                case TacticalLines.SC:
887                case TacticalLines.MRR:
888                case TacticalLines.SL:
889                case TacticalLines.TC:
890                case TacticalLines.LLTR:
891                case TacticalLines.AC:
892                case TacticalLines.SAAFR:
893                    break;
894                default:
895                    if(isAutoshape(tg))
896                        return;
897            }
898
899            //we assume tg.H to have colors if it is comma delimited.
900            //only exit if colors are not set
901            switch(tg.get_LineType())   //preserve segment data
902            {
903                case TacticalLines.CATK:
904                case TacticalLines.AIRAOA:
905                case TacticalLines.AAAAA:
906                case TacticalLines.SPT:
907                case TacticalLines.FRONTAL_ATTACK:
908                case TacticalLines.TURNING_MOVEMENT:
909                case TacticalLines.MOVEMENT_TO_CONTACT:
910                case TacticalLines.MAIN:
911                case TacticalLines.CATKBYFIRE:  //80
912                    return;
913                case TacticalLines.BOUNDARY:
914                case TacticalLines.MSR:
915                case TacticalLines.ASR:
916                case TacticalLines.ROUTE:
917                    String strH=tg.get_H();
918                    if(strH != null && !strH.isEmpty())
919                    {
920                        String[] strs=strH.split(",");
921                        if(strs.length>1)
922                            return;
923                    }
924                    break;
925                default:
926                    break;
927            }
928            int linetype=tg.get_LineType();
929            if(armyc2.c5isr.JavaTacticalRenderer.clsUtility.IsChange1Area(linetype))
930                return;
931
932            POINT2 ptCurrent=null;
933            POINT2 ptLast=null;
934            Boolean isClosedPolygon= armyc2.c5isr.JavaTacticalRenderer.clsUtility.isClosedPolygon(tg.get_LineType());
935            int minSize=2;
936            if(isClosedPolygon)
937                minSize=3;
938            for(int j=1;j<tg.Pixels.size();j++)
939            {
940                ptLast=new POINT2(tg.Pixels.get(j-1));
941                ptCurrent=new POINT2(tg.Pixels.get(j));
942                //if(ptCurrent.x==ptLast.x && ptCurrent.y==ptLast.y)
943                if (Math.abs(ptCurrent.x - ptLast.x)<0.5 && Math.abs(ptCurrent.y - ptLast.y)<0.5)
944                {
945                    if(tg.Pixels.size()>minSize)
946                    {
947                        tg.Pixels.remove(j);
948                        tg.LatLongs.remove(j);
949                        j=1;
950                    }
951                }
952            }
953        }
954        catch(Exception exc)
955        {
956            ErrorLogger.LogException("clsUtility", "RemoveDuplicatePoints",
957                    new RendererException("Failed inside RemoveDuplicatePoints", exc));
958
959        }
960    }
961    protected static POINT2 PointPixelsToLatLong(POINT2 ptPixels,IPointConversion converter)
962    {
963        POINT2 pt2 = new POINT2();
964        try
965        {
966            //Point pt=POINT2ToPoint(ptPixels);
967            Point2D pt=new Point2D.Double(ptPixels.x,ptPixels.y);
968            Point2D pt2d=converter.PixelsToGeo(pt);
969            pt2=Point2DToPOINT2(pt2d);
970            pt2.style=ptPixels.style;
971
972        }
973        catch(Exception exc)
974        {
975            ErrorLogger.LogException("clsUtility" ,"PointPixelsToLatLong",
976                    new RendererException("Could not convert point to geo", exc));
977        }
978        return pt2;
979    }
980    
981    protected static Rectangle2D getMBR(ArrayList<Point2D> clipBounds)
982    {
983        Rectangle2D rect=null;
984        try
985        {
986            int j=0;
987            Point2D pt=null;
988            double xmax=clipBounds.get(0).getX(),xmin=xmax,ymax=clipBounds.get(0).getY(),ymin=ymax;
989            int n=clipBounds.size();
990            //for(j=0;j<clipBounds.size();j++)
991            for(j=0;j<n;j++)
992            {
993                pt=clipBounds.get(j);
994                if(pt.getX()<xmin)
995                    xmin=pt.getX();
996                if(pt.getX()>xmax)
997                    xmax=pt.getX();
998                if(pt.getY()<=ymin)
999                    ymin=pt.getY();
1000                if(pt.getY()>ymax)
1001                    ymax=pt.getY();
1002            }
1003            rect=new Rectangle2D.Double(xmin, ymin, xmax-xmin, ymax-ymin);
1004        }
1005        catch (Exception exc) {
1006            ErrorLogger.LogException(_className, "AddBoundaryPointsForLines",
1007                    new RendererException("Failed inside AddBoundaryPointsForLines", exc));
1008        }
1009        return rect;
1010    }
1011
1012    static void GetMBR(ArrayList<Shape2> shapes,
1013                              POINT2 ptUl,
1014                              POINT2 ptUr,
1015                              POINT2 ptLr,
1016                              POINT2 ptLl) {
1017        try {
1018            POINT2 firstPoint = shapes.get(0).getPoints().get(0);
1019            ptUl.x = firstPoint.x;
1020            ptUl.y = firstPoint.y;
1021            ptUr.x = firstPoint.x;
1022            ptUr.y = firstPoint.y;
1023            ptLl.x = firstPoint.x;
1024            ptLl.y = firstPoint.y;
1025            ptLr.x = firstPoint.x;
1026            ptLr.y = firstPoint.y;
1027            for (Shape2 shape: shapes) {
1028                ArrayList<POINT2> points = shape.getPoints();
1029                for (int j = 0; j < points.size(); j++) {
1030                    double x = points.get(j).x;
1031                    double y = points.get(j).y;
1032                    if (x < ptLl.x) {
1033                        ptLl.x = x;
1034                        ptUl.x = x;
1035                    }
1036                    if (x > ptLr.x) {
1037                        ptLr.x = x;
1038                        ptUr.x = x;
1039                    }
1040                    if (y > ptLl.y) {
1041                        ptLl.y = y;
1042                        ptLr.y = y;
1043                    }
1044                    if (y < ptUl.y) {
1045                        ptUl.y = y;
1046                        ptUr.y = y;
1047                    }
1048                }
1049            }
1050
1051        } catch (Exception exc) {
1052            ErrorLogger.LogException(_className, "GetMBR",
1053                    new RendererException("Failed inside GetMBR", exc));
1054        }
1055    }
1056}