001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package armyc2.c5isr.RenderMultipoints;
006
007import armyc2.c5isr.JavaTacticalRenderer.clsUtility;
008import armyc2.c5isr.JavaTacticalRenderer.TGLight;
009import java.util.ArrayList;
010import armyc2.c5isr.graphics2d.*;
011import armyc2.c5isr.renderer.utilities.ErrorLogger;
012import armyc2.c5isr.renderer.utilities.RendererException;
013import armyc2.c5isr.JavaLineArray.POINT2;
014import armyc2.c5isr.JavaLineArray.TacticalLines;
015import armyc2.c5isr.JavaLineArray.Shape2;
016import armyc2.c5isr.JavaLineArray.lineutility;
017import armyc2.c5isr.graphics2d.Line2D;
018import armyc2.c5isr.graphics2d.Point2D;
019import armyc2.c5isr.graphics2d.Polygon;
020
021import java.util.HashMap;
022import java.util.Map;
023
024/**
025 * Class to clip polygons
026*
027 */
028public final class clsClipQuad {
029    private static final String _className = "clsClipQuad";
030    /**
031     * Use the new version which takes an array for polygon clip bounds instead of rectangle
032     * @param polygon
033     * @param clipBounds
034     * @return 
035     */
036    private static int AddBoundaryPointsForLines(ArrayList<Point2D> polygon,
037            ArrayList<Point2D> clipBounds) 
038    {
039        int result=0;
040        try
041        {
042            Point2D pt02d=polygon.get(0);
043            Point2D ptLast2d=polygon.get((polygon.size()-1));
044            POINT2 pt0=new POINT2(pt02d.getX(),pt02d.getY());
045            POINT2 ptLast=new POINT2(ptLast2d.getX(),ptLast2d.getY());
046            Point2D nearestPt=new Point2D.Double();
047            Polygon clipArray=new Polygon();
048            int j=0;
049            double minDist=Double.MAX_VALUE;
050            double dist=0;
051            POINT2 sidePt=new POINT2();
052            Boolean addToFront = false, addToEnd = false;     
053            //int n=clipBounds.size();
054            //for(j=0;j<clipBounds.size();j++)
055            for(j=0;j<clipBounds.size();j++)    //was n
056            {
057                clipArray.addPoint((int)clipBounds.get(j).getX(), (int)clipBounds.get(j).getY());
058            }
059
060            double totalX=0,totalY=0;
061            int counter=0;
062            //for(j=0;j<clipBounds.size()-1;j++)
063            for(j=0;j<clipBounds.size()-1;j++)  //was n-1
064            {
065                totalX+=clipBounds.get(j).getX();
066                totalY+=clipBounds.get(j).getY();
067                counter++;
068            }
069            //if clipBounds is not closed add the jth point
070            if( clipBounds.get(0).getX()!=clipBounds.get(j).getX() || 
071                    clipBounds.get(0).getY()!=clipBounds.get(j).getY() )
072            {
073                totalX+=clipBounds.get(j).getX();
074                totalY+=clipBounds.get(j).getY();                    
075                counter++;
076            }
077            double avgX=totalX/counter;
078            double avgY=totalY/counter;
079            POINT2 ptCenter=new POINT2(avgX,avgY);
080            POINT2 ptNear=null;
081            //first point outside the clip bounds
082            if(clipArray.contains(pt02d)==false)
083            {
084                //add nearest segment midpoint to the front
085                //for(j=0;j<clipBounds.size();j++)
086                for(j=0;j<clipBounds.size();j++)    //was n
087                {
088                    sidePt.x=clipBounds.get(j).getX();
089                    sidePt.y=clipBounds.get(j).getY();
090                    dist=lineutility.CalcDistanceDouble(pt0, sidePt);
091                    if(dist<minDist)
092                    {
093                        minDist=dist;
094                        //minDistIndex=j;
095                        nearestPt.setLocation(sidePt.x,sidePt.y);
096                    }
097                }
098                //move nearestPt in a bit to not get clipped
099                ptNear=new POINT2(nearestPt.getX(),nearestPt.getY());
100                ptNear=lineutility.ExtendAlongLineDouble(ptNear, ptCenter, 2);
101                nearestPt.setLocation(ptNear.x, ptNear.y);
102                polygon.add(0, nearestPt);
103                addToFront=true;
104            }
105            //re-initialize variables
106            nearestPt=new Point2D.Double();
107            minDist=Double.MAX_VALUE;
108            //last point outside the clip bounds
109            if(clipArray.contains(ptLast2d)==false)
110            {
111                //add nearest segment midpoint to the front
112                //for(j=0;j<clipBounds.size();j++)
113                for(j=0;j<clipBounds.size();j++)    //was n
114                {
115                    sidePt.x=clipBounds.get(j).getX();
116                    sidePt.y=clipBounds.get(j).getY();
117                    dist=lineutility.CalcDistanceDouble(ptLast, sidePt);
118                    if(dist<minDist)
119                    {
120                        minDist=dist;
121                        //minDistIndex=j;
122                        nearestPt.setLocation(sidePt.x,sidePt.y);
123                    }
124                }            
125                //move nearestPt in a bit to not get clipped
126                ptNear=new POINT2(nearestPt.getX(),nearestPt.getY());
127                ptNear=lineutility.ExtendAlongLineDouble(ptNear, ptCenter, 2);
128                nearestPt.setLocation(ptNear.x, ptNear.y);
129                polygon.add(nearestPt);
130                addToEnd=true;
131            }
132            if (addToFront == false && addToEnd == false) {
133                result = 0;
134            }
135            else if (addToFront == true && addToEnd == false) {
136                result = 1;
137            }
138            else if (addToFront == false && addToEnd == true) {
139                result = 2;
140            }
141            else if (addToFront == true && addToEnd == true) {
142                result = 3;
143            }
144        }
145        catch (Exception exc) 
146        {
147            ErrorLogger.LogException(_className, "AddBoundaryPointsForLines",
148                    new RendererException("Failed inside AddBoundaryPointsForLines", exc));
149        }        
150        return result;
151    }
152    private static Point2D CalcTrueIntersectDouble(double m1,
153                                            double b1,
154                                            double m2,
155                                            double b2,
156                                            int bolVertical1,
157                                            int bolVertical2,
158                                            double X1,  //x intercept if line1 is vertical
159                                            double X2)
160    {
161        Point2D ptIntersect=new Point2D.Double(X1,X2);
162        try
163        {
164            double x=0,y=0;
165
166            if(bolVertical1==0 && bolVertical2==0)      //both lines vertical
167                return ptIntersect;
168            //the following 3 if blocks are the only ways to get an intersection
169            if(bolVertical1==0 && bolVertical2==1)      //line1 vertical, line2 not
170            {
171                ptIntersect.setLocation(X1, m2*X1+b2);
172                return ptIntersect;
173            }
174            if(bolVertical1==1 && bolVertical2==0)      //line2 vertical, line1 not
175            {
176                ptIntersect.setLocation(X2, m1*X2+b1);
177                return ptIntersect;
178            }
179            //if either of the lines is vertical function has already returned
180            //so both m1 and m2 should be valid
181            //should always be using this ocase because the lines are neither vertical
182            //or horizontal and are perpendicular
183            if(m1 != m2)
184            {
185                x=(b2-b1)/(m1-m2);      //cannot blow up
186                y=(m1*x+b1);
187                ptIntersect.setLocation(x, y);
188                return ptIntersect;
189            }
190        }
191        catch(Exception exc)
192        {
193            ErrorLogger.LogException(_className ,"CalcTrueIntersectDouble",
194                    new RendererException("Failed inside CalcTrueIntersectDouble", exc));
195        }
196        return ptIntersect;
197    }
198    /**
199     * Gets theoretical intersection of an edge with the line connecting previous and current points.
200     * @param previous
201     * @param current
202     * @param currentEdge the current edge of the clip area, assumed to not be vertical
203     * @return 
204     */
205    private static Point2D intersectPoint2(Point2D previous, 
206            Point2D current,
207            Line2D currentEdge)
208    {
209        
210        Point2D ptIntersect=null;
211        try
212        {                        
213            Point2D ll=currentEdge.getP1();
214            Point2D ul=currentEdge.getP2();
215            
216            //no vertical client segments
217            //if(current.getX()==previous.getX())            
218            if(Math.abs(current.getX()-previous.getX())<1)            
219                current.setLocation(current.getX()+1, current.getY());                
220            
221            double m1=( ul.getY()-ll.getY() )/( ul.getX()-ll.getX() );
222            double m2=( current.getY()-previous.getY() )/( current.getX()-previous.getX() );
223            double b1=ul.getY()-m1*ul.getX();
224            double b2=current.getY()-m2*current.getX(); 
225            ptIntersect=CalcTrueIntersectDouble(m1,b1,m2,b2,1,1,0,0);                    
226        }
227        catch (Exception exc) {
228            ErrorLogger.LogException(_className, "intersectPoint2",
229                    new RendererException("Failed inside intersectPoint2", exc));
230        }        
231        return ptIntersect;
232    }
233
234    /**
235     * clips array of pts against a side of the clip bounds polygon
236     * assumes clipBounds has no vertical or horizontal segments 
237     * @param pts array of points to clip against the clip bounds
238     * @param index starting index of clipBounds for the side to clip against
239     * @param clipBounds a quadrilateral or a polygon array that is the clipping area
240     * @return the clipped array of points
241     */
242    private static ArrayList<Point2D> clipSide(TGLight tg, ArrayList<Point2D> pts,
243            int index,
244            ArrayList<Point2D> clipBounds) 
245    {
246        ArrayList<Point2D> ptsResult=null;
247        try
248        {
249            Point2D pt1=new Point2D.Double(clipBounds.get(index).getX(),clipBounds.get(index).getY());//first point of clip side
250            Point2D pt2=new Point2D.Double(clipBounds.get(index+1).getX(),clipBounds.get(index+1).getY());//last point of clip side                        
251            Point2D clipBoundsPoint=null;//some point in the clipbounds not on the side
252            Point2D ptClipBoundsIntersect=null;//some point in the clipbounds not on the side
253            double m1=0,m2=0,b1=0,b2=0,b3=0,b4=0;            
254            Point2D ptPreviousIntersect=null,ptCurrentIntersect=null;            
255            int j = 0,clipBoundsQuadrant=-1,previousQuadrant=-1,currentQuadrant=-1;  //quadrants relative to side
256            Point2D current = null, previous = null;
257            Point2D intersectPt = null;
258            Line2D edge;  
259            ptsResult=new ArrayList();            
260            //set some point in the array which is not in the side
261            //this point will be used to define which side of the clipping side the rest of the clipbounds points are on
262            //then it can be used to figure out whether a given point is to be clipped
263            //for this scheme to work it needs to be a convex clipping area
264            if(index==0)
265            {
266                clipBoundsPoint=new Point2D.Double(clipBounds.get(index+2).getX(),clipBounds.get(index+2).getY());
267            }
268            else if(index>1)
269            {
270                clipBoundsPoint=new Point2D.Double(clipBounds.get(index-2).getX(),clipBounds.get(index-2).getY());
271            }
272            else if(index==1)
273            {
274                clipBoundsPoint=new Point2D.Double(clipBounds.get(0).getX(),clipBounds.get(0).getY());
275            }
276                
277            //no vertical segments
278            //if(pt2.getX()==pt1.getX())
279            if(Math.abs(pt2.getX()-pt1.getX())<1)
280                pt2.setLocation(pt2.getX()+1, pt2.getY());
281            //if(pt2.getY()==pt1.getY())
282            if(Math.abs(pt2.getY()-pt1.getY())<1)
283                pt2.setLocation(pt2.getX(), pt2.getY()+1);
284            
285            for (j = 0; j < pts.size(); j++) 
286            {                
287                current = pts.get(j);
288                if (j == 0) 
289                {
290                    previous = pts.get(pts.size() - 1);
291                } 
292                else 
293                {
294                    previous = pts.get(j - 1);
295                }
296
297                m1=(pt2.getY()-pt1.getY())/(pt2.getX()-pt1.getX());
298                m2=-1d/m1;  //the slope of the line perpendicular to m1,b1
299                b1=pt2.getY()-m1*pt2.getX();
300                b2=previous.getY()-m2*previous.getX(); 
301                b3=current.getY()-m2*current.getX(); 
302                b4=clipBoundsPoint.getY()-m2*clipBoundsPoint.getX(); 
303                ptPreviousIntersect=CalcTrueIntersectDouble(m1,b1,m2,b2,1,1,0,0);                    
304                ptCurrentIntersect=CalcTrueIntersectDouble(m1,b1,m2,b3,1,1,0,0);
305                ptClipBoundsIntersect=CalcTrueIntersectDouble(m1,b1,m2,b4,1,1,0,0);
306                clipBoundsQuadrant=lineutility.GetQuadrantDouble(clipBoundsPoint.getX(), clipBoundsPoint.getY(), ptClipBoundsIntersect.getX(), ptClipBoundsIntersect.getY());
307                previousQuadrant=lineutility.GetQuadrantDouble(previous.getX(), previous.getY(), ptPreviousIntersect.getX(), ptPreviousIntersect.getY());
308                currentQuadrant=lineutility.GetQuadrantDouble(current.getX(), current.getY(), ptCurrentIntersect.getX(), ptCurrentIntersect.getY());
309
310                //case: both inside
311                if(previousQuadrant==clipBoundsQuadrant && currentQuadrant==clipBoundsQuadrant)
312                    ptsResult.add(current);                                        
313                else if(previousQuadrant==clipBoundsQuadrant && currentQuadrant!=clipBoundsQuadrant)//previous inside, current outside
314                {
315                    edge = new Line2D.Double(pt1, pt2);
316                    intersectPt = intersectPoint2(previous, current, edge);
317                    if (intersectPt != null) 
318                    {
319                        ptsResult.add(intersectPt);
320                    }
321                    tg.set_WasClipped(true);
322                }
323                else if(previousQuadrant!=clipBoundsQuadrant && currentQuadrant==clipBoundsQuadrant)//current inside, previous outside
324                {
325                    edge = new Line2D.Double(pt1, pt2);
326                    intersectPt = intersectPoint2(previous, current, edge);
327                    if (intersectPt != null) 
328                    {
329                        ptsResult.add(intersectPt);
330                    }
331                    ptsResult.add(current);
332                    tg.set_WasClipped(true);
333                }
334                else if(previousQuadrant!=clipBoundsQuadrant && currentQuadrant!=clipBoundsQuadrant)
335                    continue;
336            }//end for j=0 to pts.size()-1
337        }//end try
338        catch (Exception exc) {
339            ErrorLogger.LogException(_className, "clipSide",
340                    new RendererException("Failed inside clipSide", exc));
341        }    
342        return ptsResult;
343    }
344    /**
345     * for pre-clipped lines which also require fill but need the processed points
346     * to create the fill. This function is called after the clip, so the fill
347     * does not get clipped.
348     * @param tg
349     * @param shapes
350     */
351    protected static void addAbatisFill(TGLight tg,
352            ArrayList<Shape2>shapes)
353    {
354        try
355        {
356            if(tg.Pixels==null ||
357                    tg.Pixels.size()<2 ||
358                    tg.get_FillColor()==null ||
359                    tg.get_FillColor().getAlpha()<2 ||
360                    shapes==null)
361                return;
362
363            int j=0,n=tg.Pixels.size();
364            Shape2 shape=null;
365            TGLight tg2=null;
366            switch(tg.get_LineType())
367            {
368                case TacticalLines.MSDZ:
369                    double dist0=0,dist1=0,dist2=0;
370                    shape=new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
371                    shape.setFillColor(tg.get_FillColor());
372                    if(tg.Pixels != null & tg.Pixels.size()>=300)
373                    {
374                        dist0=Math.abs(tg.Pixels.get(0).x-tg.Pixels.get(50).x);
375                        dist1=Math.abs(tg.Pixels.get(100).x-tg.Pixels.get(150).x);
376                        dist2=Math.abs(tg.Pixels.get(200).x-tg.Pixels.get(250).x);
377                        int start=-1,end=-1;
378                        if(dist0>=dist1 && dist0>=dist2)
379                        {
380                            start=0;
381                            end=99;
382                        }
383                        else if(dist1>=dist0 && dist1>=dist2)
384                        {
385                            start=100;
386                            end=199;
387                        }
388                        else
389                        {
390                            start=200;
391                            end=299;
392                        }
393                        shape.moveTo(tg.Pixels.get(start));
394                        for(j=start;j<=end;j++)
395                            shape.lineTo(tg.Pixels.get(j));
396
397                        //shapes.add(0,shape);
398                    }
399                    break;
400                case TacticalLines.ABATIS:
401                    shape=new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
402                    shape.setFillColor(tg.get_FillColor());
403                    tg2=new TGLight();
404                    tg2.set_LineType(TacticalLines.GENERAL);
405                    tg2.Pixels=new ArrayList();
406                    if(tg.Pixels != null && tg.Pixels.size()>2)
407                    {
408                        tg2.Pixels.add(tg.Pixels.get(n-3));
409                        tg2.Pixels.add(tg.Pixels.get(n-2));
410                        tg2.Pixels.add(tg.Pixels.get(n-1));
411                        tg2.Pixels.add(tg.Pixels.get(n-3));
412
413                        shape.moveTo(tg2.Pixels.get(0));
414                        for(j=1;j<tg2.Pixels.size();j++)
415                            shape.lineTo(tg2.Pixels.get(j));
416
417                        //shapes.add(shape);
418                    }
419                    break;
420                default:
421                    return;
422            }//end switch
423            if(shapes != null)
424                shapes.add(0,shape);
425        }
426        catch (Exception exc) {
427            ErrorLogger.LogException(_className, "addAbatisFill",
428                    new RendererException("Failed inside addAbatisFill", exc));
429        }
430    }
431    /**
432     * for lines with glyphs the fill must be handled (clipped) as a separate shape.
433     * this function needs to be called before the clipping is done to the line
434     * @param tg
435     * @param clipBounds
436     */
437    protected static ArrayList<Shape2> LinesWithFill(TGLight tg,
438            ArrayList<Point2D> clipBounds)
439    {                        
440        ArrayList<Shape2>shapes=null;
441        try
442        {
443            if(tg.get_FillColor()==null || tg.get_FillColor().getAlpha()<=1 ||
444                    tg.Pixels==null || tg.Pixels.isEmpty())
445                return shapes;
446
447            switch(tg.get_LineType())
448            {
449                case TacticalLines.ABATIS:
450                case TacticalLines.SPT:
451                case TacticalLines.FRONTAL_ATTACK:
452                case TacticalLines.TURNING_MOVEMENT:
453                case TacticalLines.MOVEMENT_TO_CONTACT:
454                case TacticalLines.MAIN:
455                case TacticalLines.AAAAA:
456                case TacticalLines.AIRAOA:
457                case TacticalLines.CATK:
458                case TacticalLines.CATKBYFIRE:
459                case TacticalLines.CORDONSEARCH:
460                case TacticalLines.CORDONKNOCK:
461                case TacticalLines.SECURE:
462                case TacticalLines.OCCUPY:
463                case TacticalLines.RETAIN:
464                case TacticalLines.ISOLATE:
465                case TacticalLines.AREA_DEFENSE:
466                case TacticalLines.MOBILE_DEFENSE:
467                case TacticalLines.CONVOY:
468                case TacticalLines.HCONVOY:
469                    return shapes;
470                case TacticalLines.PAA_RECTANGULAR:
471                case TacticalLines.RECTANGULAR_TARGET:
472                    return null;
473                case TacticalLines.OBSFAREA:
474                case TacticalLines.OBSAREA:
475                case TacticalLines.STRONG:
476                case TacticalLines.ZONE:
477                case TacticalLines.FORT_REVD:
478                case TacticalLines.FORT:
479                case TacticalLines.ENCIRCLE:
480                case TacticalLines.ATDITCHC:
481                case TacticalLines.ATDITCHM:
482                    return fillDMA(tg,clipBounds);
483                default:
484                    break;
485            }
486            if(clsUtility.LinesWithFill(tg.get_LineType())==false)
487                return shapes;
488
489            shapes=new ArrayList();
490            //undo any fillcolor that might have been set for the existing shape
491            //because we are divorcing fill from the line
492            Shape2 shape=null;
493
494            //create a generic area tg from the pixels and clip it
495            TGLight tg2=new TGLight();
496            tg2.set_LineType(TacticalLines.GENERAL);
497            tg2.Pixels=new ArrayList();
498            tg2.Pixels.addAll(tg.Pixels);
499            closeAreaTG(tg2);
500            //tg2.Pixels.add(tg.Pixels.get(0));
501            if(clipBounds != null)
502                ClipPolygon(tg2,clipBounds);
503
504
505            if(tg2.Pixels==null || tg2.Pixels.isEmpty())
506                return null;
507
508            int j=0;
509            shape=new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
510            shape.setFillColor(tg.get_FillColor());
511
512            shape.moveTo(tg2.Pixels.get(0));
513            for(j=1;j<tg2.Pixels.size();j++)
514                shape.lineTo(tg2.Pixels.get(j));
515
516            if(tg.get_FillColor() != null || tg.get_FillColor().getAlpha()>1)
517            {
518                shapes.add(shape);
519            }
520            else
521                return  null;
522        }
523        catch (Exception exc) {
524            ErrorLogger.LogException(_className, "LinesWithFill",
525                    new RendererException("Failed inside LinesWithFill", exc));
526        }
527        return shapes;
528    }
529    /**
530     * closes an area
531     * @param tg
532     */
533    private static void closeAreaTG(TGLight tg)
534    {
535        try
536        {
537            if(tg.Pixels==null || tg.Pixels.isEmpty())
538                return;
539
540            POINT2 pt0=tg.Pixels.get(0);
541            POINT2 ptn=tg.Pixels.get(tg.Pixels.size()-1);
542            if(pt0.x != ptn.x || pt0.y != ptn.y)
543                tg.Pixels.add(pt0);
544            
545        }
546            catch (Exception exc) {
547            ErrorLogger.LogException(_className, "closeAreaTG",
548                    new RendererException("Failed inside closeAreaTG", exc));
549        }
550    }
551    /**
552     * DMA, DMAF fill must be handled separately because of the feint
553     * @param tg
554     * @param clipBounds
555     * @return
556     */
557    protected static ArrayList<Shape2> fillDMA(TGLight tg,
558            ArrayList<Point2D> clipBounds)
559    {
560        ArrayList<Shape2>shapes=new ArrayList();
561        try
562        {
563            switch(tg.get_LineType())
564            {
565                case TacticalLines.OBSFAREA:
566                case TacticalLines.OBSAREA:
567                case TacticalLines.STRONG:
568                case TacticalLines.ZONE:
569                case TacticalLines.FORT_REVD:
570                case TacticalLines.FORT:
571                case TacticalLines.ENCIRCLE:
572                case TacticalLines.ATDITCHC:
573                case TacticalLines.ATDITCHM:
574                    break;
575                default:
576                    return shapes;
577            }
578            Shape2 shape=null;
579
580            //create a generic area tg from the pixels and clip it
581            int j=0;
582            TGLight tg2=new TGLight();
583            tg2.set_LineType(TacticalLines.GENERAL);
584            tg2.Pixels=new ArrayList();
585            //to get the original pixels size
586            int n=0;
587            n=tg.Pixels.size();
588            
589            for(j=0;j<n;j++)
590                tg2.Pixels.add(tg.Pixels.get(j));
591
592            closeAreaTG(tg2);
593
594            if(clipBounds != null)
595                ClipPolygon(tg2,clipBounds);
596
597            if(tg2.Pixels==null || tg2.Pixels.isEmpty())
598                return shapes;
599
600            shape=new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
601            shape.setFillColor(tg.get_FillColor());
602
603            shape.moveTo(tg2.Pixels.get(0));
604            //original pixels do not include feint
605            for(j=1;j<tg2.Pixels.size();j++)
606                shape.lineTo(tg2.Pixels.get(j));
607
608            shapes.add(shape);
609        }
610        catch (Exception exc) {
611            ErrorLogger.LogException(_className, "fillDMA",
612                    new RendererException("Failed inside fillDMA", exc));
613        }
614        return shapes;
615    }
616//    private static Boolean isClosed(ArrayList<POINT2>pts)
617//    {
618//        boolean closed=false;
619//        POINT2 pt0=pts.get(0);
620//        POINT2 ptLast=pts.get(pts.size()-1);
621//        if(pt0.x==ptLast.x && pt0.y==ptLast.y)
622//            closed=true;
623//        return closed;
624//    }
625    /**
626     * 
627     * @param tg
628     * @param clipBounds polygon representing clipping area
629     * @return 
630     */
631    protected static ArrayList<Point2D> ClipPolygon(TGLight tg,
632            ArrayList<Point2D> clipBounds) {
633        ArrayList<Point2D> poly = new ArrayList();
634        try 
635        {            
636            //diagnostic
637            Boolean isClosed = clsUtility.isClosedPolygon(tg.get_LineType());            
638            //Boolean isClosed = isClosed(tg.Pixels);
639            //M. Deutch commented one line 12-27-12
640            //clipBounds=clsUtilityGE.expandPolygon(clipBounds, 20);
641            clipBounds=clsUtilityGE.expandPolygon(clipBounds, 20);
642            //int n=clipBounds.size();
643            ArrayList polygon = clsUtilityCPOF.POINT2toPoint2D(tg.Pixels);            
644            
645            int j=0;
646            Map<String,Object>hashMap=new HashMap<String,Object>();
647            //int hashCode=0;
648            for(j=0;j<polygon.size();j++)            
649                hashMap.put(Integer.toString(j), polygon.get(j));
650            
651            //close the clipbounds if necessary
652            Point2D clipBoundsPtStart=clipBounds.get(0);
653            Point2D clipBoundsPtEnd=clipBounds.get(clipBounds.size()-1);
654            if(clipBoundsPtStart.getX() != clipBoundsPtEnd.getX() ||
655                    clipBoundsPtStart.getY() != clipBoundsPtEnd.getY())
656                clipBounds.add(clipBoundsPtStart);
657                        
658            int addedLinePoints = 0;
659            if (isClosed)             
660                polygon.remove(polygon.size() - 1);             
661            else 
662            {                     
663                addedLinePoints = AddBoundaryPointsForLines(polygon, clipBounds);
664            }
665
666            //for(j=0;j<clipBounds.size()-1;j++)
667            for(j=0;j<clipBounds.size()-1;j++)
668            {
669                if(j==0)
670                    poly=clipSide(tg,polygon,j,clipBounds);
671                else
672                    poly=clipSide(tg,poly,j,clipBounds);
673            }
674            
675            
676            if (isClosed)
677            {
678                if (poly.size() > 0)
679                {
680                    poly.add(poly.get(0));
681                }
682            }
683            else
684            {
685                switch (addedLinePoints)
686                {
687                    case 0: //no points were added, do nothing
688                        break;
689                    case 1: //point was added to the front to make algorithm work, remove segment
690                        if (poly.size() > 0) {
691                            poly.remove(0);
692                        }
693                        if (poly.size() > 0) {
694                            poly.remove(0);
695                        }
696                        break;
697                    case 2: //point was added to the end to make algorithm work, remove segment
698                        if (poly.size() > 0) {
699                            poly.remove(poly.size() - 1);
700                        }
701                        if (poly.size() > 0) {
702                           poly.remove(poly.size() - 1);
703                        }
704                        break;
705                    case 3: //point was added to the front and end to make algorithm work, remove segments
706                        if (poly.size() > 0) {
707                            poly.remove(0);
708                        }
709                        if (poly.size() > 0) {
710                            poly.remove(0);
711                        }
712                        if (poly.size() > 0) {
713                            poly.remove(poly.size() - 1);
714                        }
715                        if (poly.size() > 0) {
716                            poly.remove(poly.size() - 1);
717                        }
718                        break;
719                }
720            }
721            
722            if (isClosed == true)
723            {
724                if (poly.size() > 2)
725                {
726                    tg.Pixels = clsUtilityCPOF.Point2DtoPOINT2Mapped(poly,hashMap);
727                } 
728                else
729                {
730                    tg.Pixels=new ArrayList();
731                }
732
733            } 
734            else
735            {
736                if (poly.size() > 1)
737                {
738                    tg.Pixels = clsUtilityCPOF.Point2DtoPOINT2Mapped(poly,hashMap);
739                } 
740                else
741                {
742                    tg.Pixels=new ArrayList();
743                }
744            }            
745
746        } catch (Exception exc) {
747            ErrorLogger.LogException(_className, "ClipPolygon",
748                    new RendererException("Failed inside ClipPolygon", exc));
749        }
750        return poly;
751    }
752}