001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package armyc2.c2sd.graphics2d;
006import armyc2.c2sd.renderer.utilities.ErrorLogger;
007import armyc2.c2sd.renderer.utilities.RendererException;
008import java.util.ArrayList;
009import armyc2.c2sd.JavaLineArray.POINT2;
010import armyc2.c2sd.JavaLineArray.lineutility;
011import java.util.HashMap;
012import java.util.Map;
013/**
014 *
015 * @author Michael Deutch
016 */
017public class Area extends GeneralPath{
018    private static final String _className="Area";
019    //private ArrayList<POINT2>_pts=null;
020    public Area(Polygon poly)
021    {
022        int j=0;
023        int n=poly.npoints;
024        //for(j=0;j<poly.npoints;j++)
025        for(j=0;j<n;j++)
026        {
027            if(j==0)
028                moveTo(poly.xpoints[j],poly.ypoints[j]);
029            else
030                lineTo(poly.xpoints[j],poly.ypoints[j]);
031        }
032    }
033    public Area(Shape shape)
034    {
035        int j=0;
036        PathIterator p=shape.getPathIterator(null);
037        ArrayList<POINT2>pts=p.getPoints();
038        POINT2 pt=null;
039        int n=pts.size();
040        //for(j=0;j<pts.size();j++)
041        for(j=0;j<n;j++)
042        {
043            pt=pts.get(j);
044            switch(pt.style)
045            {
046                case IPathIterator.SEG_MOVETO:
047                    moveTo(pt.x,pt.y);
048                    break;
049                case IPathIterator.SEG_LINETO:
050                    lineTo(pt.x,pt.y);
051                    break;
052                default:
053                    break;
054            }
055        }    
056    }
057    /**
058     * organizes intersect points by increasing distance from the hatch line origin
059     * @param hatchLine
060     * @param pts 
061     */
062    private void reorderPointsByDistance(Line2D hatchLine, ArrayList<Point2D>pts)
063    {
064        try
065        {
066            double minDistance=0,dist=0;
067            int j=0,minIndex=-1;
068            Map<Integer,Double>distances=new HashMap();
069            ArrayList<Point2D>ptsOrdered=new ArrayList();
070            Point2D origin=hatchLine.getP1();
071            POINT2 pt0=new POINT2(origin.getX(),origin.getY());
072            POINT2 pt1=null;
073            //build the distances array
074            int n=pts.size();
075            //for(j=0;j<pts.size();j++)
076            for(j=0;j<n;j++)
077            {
078                pt1=new POINT2(pts.get(j).getX(), pts.get(j).getY());
079                dist=lineutility.CalcDistanceDouble(pt0, pt1);
080                distances.put(j, dist);
081            }
082            while (distances.size()>0)
083            {
084                //initialize minDistance after an array element was removed
085                //for(j=0;j<pts.size();j++)
086                for(j=0;j<n;j++)
087                {
088                    if(distances.containsKey(j))
089                    {
090                        minIndex=j;
091                        minDistance=distances.get(j);
092                        break;
093                    }
094                }
095                //loop through the remaining elements to find the next minimum distance
096                //for(j=0;j<pts.size();j++)
097                for(j=0;j<n;j++)
098                {
099                    if(distances.containsKey(j))
100                    {
101                        dist=distances.get(j);
102                        if(dist<minDistance)
103                        {
104                            minDistance=dist;
105                            minIndex=j;
106                        }
107                    }
108                }                                    
109                //add the next point to the array
110                ptsOrdered.add(pts.get(minIndex));
111                distances.remove(minIndex);
112            }
113            pts.clear();
114            n=ptsOrdered.size();
115            //for(j=0;j<ptsOrdered.size();j++)
116            for(j=0;j<n;j++)
117                pts.add(ptsOrdered.get(j));
118        }
119        catch(Exception exc)
120        {
121            ErrorLogger.LogException(_className, "reorderPointsByDistance",
122                    new RendererException("Failed inside reorderPointsByDistance", exc));
123        }
124    }
125    Rectangle2D getMBR(ArrayList<POINT2>polygon)
126    {
127        int j=0;
128        double left=polygon.get(0).x;
129        double top=polygon.get(0).y;
130        double right=polygon.get(0).x;
131        double bottom=polygon.get(0).y;
132        int n=polygon.size();
133        //for (j=1;j<polygon.size();j++)
134        for (j=1;j<n;j++)
135        {
136            if(polygon.get(j).x<left)
137                left=polygon.get(j).x;
138            if(polygon.get(j).x>right)
139                right=polygon.get(j).x;
140            
141            if(polygon.get(j).y<top)
142                top=polygon.get(j).y;
143            if(polygon.get(j).y>bottom)
144                bottom=polygon.get(j).y;
145        }
146        return new Rectangle2D.Double(left,top,right-left,bottom-top);
147    }
148    boolean isVertical(Line2D edge)
149    {
150        if(edge.getX1()==edge.getX2())
151            return true;
152        else return false;
153    }
154    private void adjustVerticalLine(Line2D line)
155    {
156        Point2D linePt0=line.getP1();
157        Point2D linePt1=line.getP1();
158        if(isVertical(line))
159        {
160            double x=line.getX2()+1;
161            double y=line.getY2();
162            linePt1.setLocation(x, y);
163            line.setLine(linePt0, linePt1);
164        }             
165    }
166    /**
167     * 
168     * @param hatchLine the hatch line to intersect against the area points.
169     * the thatch line is assumed to start outside the area (polygon) MBR
170     * @return the GeneralPath which represents the intersection
171     */
172    private ArrayList<POINT2> getLineIntersectPoints(ArrayList<POINT2> polygon, Line2D hatchLine)
173    {
174        ArrayList<POINT2>pts=null;
175        try
176        {
177            int j=0,k=0;
178            Line2D segment=null;
179            Point2D pt0=null,pt1=null;
180            //no (exactly) vertical hatch lines
181            adjustVerticalLine(hatchLine);
182            ArrayList<Point2D>ptsPath=new ArrayList();
183            double x=0,y=0;
184            double m1=0,    //hatch line
185                    m2=0,   //segment slope
186                    b1=0,   //hatch line y intercept
187                    b2=0;   //segment y intercept
188            int n=polygon.size();
189            //for(j=0;j<polygon.size()-1;j++)
190            for(j=0;j<n-1;j++)
191            {
192                pt0=new Point2D.Double(polygon.get(j));
193                pt1=new Point2D.Double(polygon.get(j+1));
194                segment=new Line2D.Double(pt0,pt1);
195                //no vertical segments
196                adjustVerticalLine(segment);
197                pt0=segment.getP1();
198                pt1=segment.getP2();
199                m1=(hatchLine.getY1()-hatchLine.getY2())/(hatchLine.getX1()-hatchLine.getX2());
200                m2=(pt0.getY()-pt1.getY())/(pt0.getX()-pt1.getX());
201                if( hatchLine.intersectsLine(segment) )
202                {
203                    //m1=(hatchLine.getY1()-hatchLine.getY2())/(hatchLine.getX1()-hatchLine.getX2());
204                    //m2=(pt0.getY()-pt1.getY())/(pt0.getX()-pt1.getX());
205                    if(m1==m2)
206                    {
207                        ptsPath.add(pt0);
208                        ptsPath.add(pt1);
209                    }
210                    else    //slopes not equal
211                    {
212                        //add one intersection point
213                        b1=hatchLine.getY1()-m1*hatchLine.getX1();
214                        b2=segment.getY1()-m2*segment.getX1();
215                        x=(b2-b1)/(m1-m2);  //cannot blow up
216                        y=(m1*x+b1);
217                        ptsPath.add(new Point2D.Double(x,y));
218                    }
219                }
220            }
221            //reorder ptsPath by distance from the hatch line origin
222            reorderPointsByDistance(hatchLine,ptsPath);
223            Point2D pt=null;
224            pts=new ArrayList();
225            n=ptsPath.size();
226            //for(k=0;k<ptsPath.size();k++)
227            for(k=0;k<n;k++)
228            {
229                pt=ptsPath.get(k);
230                if(k%2==0)                
231                {
232                   pts.add(new POINT2(pt.getX(),pt.getY(),IPathIterator.SEG_MOVETO));
233                }
234                else
235                {
236                   pts.add(new POINT2(pt.getX(),pt.getY(),IPathIterator.SEG_LINETO));
237                }
238
239            }
240            ptsPath.clear();
241        }
242        catch(Exception exc)
243        {
244            ErrorLogger.LogException(_className, "getLineIntersectPoints",
245                    new RendererException("Failed inside getLineIntersectPoints", exc));
246        }
247        return pts;
248    }
249    /**
250     * this is functionality for clsUtilityGE.buildHatchFillwhich calls hatchLineArea.intersect(shapeArea).
251     * so it assumes that this._pts is the hatch lines so it is hatchLines.intersect(shape) where
252     * shape is the polygon to be filled with hatch lines
253     * @param area 
254     */
255    public void intersect(Area area)
256    {
257        try
258        {
259            //assume area is the polygon and "this" is the hatch line shape
260            int j=0;
261            ArrayList<POINT2>polygon=area.getPathIterator(null).getPoints();
262            ArrayList<POINT2>hatchLines=this.getPathIterator(null).getPoints();
263            //close the polygon
264            if(polygon.get(0).x != polygon.get(polygon.size()-1).x || polygon.get(0).y != polygon.get(polygon.size()-1).y)
265            {
266                polygon.add(new POINT2(polygon.get(polygon.size()-1)));            
267            }
268            //GeneralPath gp=null;
269            //GeneralPath masterGP=null;
270            Line2D hatchLine=null;
271            Rectangle2D rectHatch=null;
272            Rectangle2D rectPoly=getMBR(polygon);
273            ArrayList<POINT2> pts=new ArrayList();
274            ArrayList<POINT2> ptsTemp=null;
275            int n=hatchLines.size();
276            //for(j=0;j<hatchLines.size()-1;j++)
277            for(j=0;j<n-1;j++)
278            {
279                hatchLine=new Line2D.Double(hatchLines.get(j).x,hatchLines.get(j).y,hatchLines.get(j+1).x,hatchLines.get(j+1).y);
280                rectHatch=hatchLine.getBounds2D();
281                if(rectHatch.intersects(rectPoly)==false)
282                    continue;
283
284                ptsTemp=getLineIntersectPoints(polygon,hatchLine);
285                if(ptsTemp != null)
286                    pts.addAll(ptsTemp);
287            }   
288            POINT2 pt=null;
289            //area.getPathIterator(null).reset();
290            //area.getPathIterator(null).getPoints().clear();
291            //this._pts.clear();            
292            this.getPathIterator(null).getPoints().clear();
293            //area._pts.clear();
294            n=pts.size();
295            //for(j=0;j<pts.size();j++)
296            for(j=0;j<n;j++)
297            {
298                pt=pts.get(j);
299                switch(pt.style)
300                {
301                    case IPathIterator.SEG_MOVETO:
302                        moveTo(pt.x,pt.y);
303                        break;
304                    case IPathIterator.SEG_LINETO:
305                        lineTo(pt.x,pt.y);
306                        break;
307                    default:
308                        break;
309                }
310            }      
311            this.getPathIterator(null).reset();
312        }
313        catch(Exception exc)
314        {
315            ErrorLogger.LogException(_className, "intersect",
316                    new RendererException("Failed inside intersect", exc));
317        }
318    }
319}