/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package armyc2.c2sd.graphics2d;
import armyc2.c2sd.renderer.utilities.ErrorLogger;
import armyc2.c2sd.renderer.utilities.RendererException;
import java.util.ArrayList;
import armyc2.c2sd.JavaLineArray.POINT2;
import armyc2.c2sd.JavaLineArray.lineutility;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Michael Deutch
*/
public class Area extends GeneralPath{
private static final String _className="Area";
//private ArrayList<POINT2>_pts=null;
public Area(Polygon poly)
{
int j=0;
int n=poly.npoints;
//for(j=0;j<poly.npoints;j++)
for(j=0;j<n;j++)
{
if(j==0)
moveTo(poly.xpoints[j],poly.ypoints[j]);
else
lineTo(poly.xpoints[j],poly.ypoints[j]);
}
}
public Area(Shape shape)
{
int j=0;
PathIterator p=shape.getPathIterator(null);
ArrayList<POINT2>pts=p.getPoints();
POINT2 pt=null;
int n=pts.size();
//for(j=0;j<pts.size();j++)
for(j=0;j<n;j++)
{
pt=pts.get(j);
switch(pt.style)
{
case IPathIterator.SEG_MOVETO:
moveTo(pt.x,pt.y);
break;
case IPathIterator.SEG_LINETO:
lineTo(pt.x,pt.y);
break;
default:
break;
}
}
}
/**
* organizes intersect points by increasing distance from the hatch line origin
* @param hatchLine
* @param pts
*/
private void reorderPointsByDistance(Line2D hatchLine, ArrayList<Point2D>pts)
{
try
{
double minDistance=0,dist=0;
int j=0,minIndex=-1;
Map<Integer,Double>distances=new HashMap();
ArrayList<Point2D>ptsOrdered=new ArrayList();
Point2D origin=hatchLine.getP1();
POINT2 pt0=new POINT2(origin.getX(),origin.getY());
POINT2 pt1=null;
//build the distances array
int n=pts.size();
//for(j=0;j<pts.size();j++)
for(j=0;j<n;j++)
{
pt1=new POINT2(pts.get(j).getX(), pts.get(j).getY());
dist=lineutility.CalcDistanceDouble(pt0, pt1);
distances.put(j, dist);
}
while (distances.size()>0)
{
//initialize minDistance after an array element was removed
//for(j=0;j<pts.size();j++)
for(j=0;j<n;j++)
{
if(distances.containsKey(j))
{
minIndex=j;
minDistance=distances.get(j);
break;
}
}
//loop through the remaining elements to find the next minimum distance
//for(j=0;j<pts.size();j++)
for(j=0;j<n;j++)
{
if(distances.containsKey(j))
{
dist=distances.get(j);
if(dist<minDistance)
{
minDistance=dist;
minIndex=j;
}
}
}
//add the next point to the array
ptsOrdered.add(pts.get(minIndex));
distances.remove(minIndex);
}
pts.clear();
n=ptsOrdered.size();
//for(j=0;j<ptsOrdered.size();j++)
for(j=0;j<n;j++)
pts.add(ptsOrdered.get(j));
}
catch(Exception exc)
{
ErrorLogger.LogException(_className, "reorderPointsByDistance",
new RendererException("Failed inside reorderPointsByDistance", exc));
}
}
Rectangle2D getMBR(ArrayList<POINT2>polygon)
{
int j=0;
double left=polygon.get(0).x;
double top=polygon.get(0).y;
double right=polygon.get(0).x;
double bottom=polygon.get(0).y;
int n=polygon.size();
//for (j=1;j<polygon.size();j++)
for (j=1;j<n;j++)
{
if(polygon.get(j).x<left)
left=polygon.get(j).x;
if(polygon.get(j).x>right)
right=polygon.get(j).x;
if(polygon.get(j).y<top)
top=polygon.get(j).y;
if(polygon.get(j).y>bottom)
bottom=polygon.get(j).y;
}
return new Rectangle2D.Double(left,top,right-left,bottom-top);
}
boolean isVertical(Line2D edge)
{
if(edge.getX1()==edge.getX2())
return true;
else return false;
}
private void adjustVerticalLine(Line2D line)
{
Point2D linePt0=line.getP1();
Point2D linePt1=line.getP1();
if(isVertical(line))
{
double x=line.getX2()+1;
double y=line.getY2();
linePt1.setLocation(x, y);
line.setLine(linePt0, linePt1);
}
}
/**
*
* @param hatchLine the hatch line to intersect against the area points.
* the thatch line is assumed to start outside the area (polygon) MBR
* @return the GeneralPath which represents the intersection
*/
private ArrayList<POINT2> getLineIntersectPoints(ArrayList<POINT2> polygon, Line2D hatchLine)
{
ArrayList<POINT2>pts=null;
try
{
int j=0,k=0;
Line2D segment=null;
Point2D pt0=null,pt1=null;
//no (exactly) vertical hatch lines
adjustVerticalLine(hatchLine);
ArrayList<Point2D>ptsPath=new ArrayList();
double x=0,y=0;
double m1=0, //hatch line
m2=0, //segment slope
b1=0, //hatch line y intercept
b2=0; //segment y intercept
int n=polygon.size();
//for(j=0;j<polygon.size()-1;j++)
for(j=0;j<n-1;j++)
{
pt0=new Point2D.Double(polygon.get(j));
pt1=new Point2D.Double(polygon.get(j+1));
segment=new Line2D.Double(pt0,pt1);
//no vertical segments
adjustVerticalLine(segment);
pt0=segment.getP1();
pt1=segment.getP2();
m1=(hatchLine.getY1()-hatchLine.getY2())/(hatchLine.getX1()-hatchLine.getX2());
m2=(pt0.getY()-pt1.getY())/(pt0.getX()-pt1.getX());
if( hatchLine.intersectsLine(segment) )
{
//m1=(hatchLine.getY1()-hatchLine.getY2())/(hatchLine.getX1()-hatchLine.getX2());
//m2=(pt0.getY()-pt1.getY())/(pt0.getX()-pt1.getX());
if(m1==m2)
{
ptsPath.add(pt0);
ptsPath.add(pt1);
}
else //slopes not equal
{
//add one intersection point
b1=hatchLine.getY1()-m1*hatchLine.getX1();
b2=segment.getY1()-m2*segment.getX1();
x=(b2-b1)/(m1-m2); //cannot blow up
y=(m1*x+b1);
ptsPath.add(new Point2D.Double(x,y));
}
}
}
//reorder ptsPath by distance from the hatch line origin
reorderPointsByDistance(hatchLine,ptsPath);
Point2D pt=null;
pts=new ArrayList();
n=ptsPath.size();
//for(k=0;k<ptsPath.size();k++)
for(k=0;k<n;k++)
{
pt=ptsPath.get(k);
if(k%2==0)
{
pts.add(new POINT2(pt.getX(),pt.getY(),IPathIterator.SEG_MOVETO));
}
else
{
pts.add(new POINT2(pt.getX(),pt.getY(),IPathIterator.SEG_LINETO));
}
}
ptsPath.clear();
}
catch(Exception exc)
{
ErrorLogger.LogException(_className, "getLineIntersectPoints",
new RendererException("Failed inside getLineIntersectPoints", exc));
}
return pts;
}
/**
* this is functionality for clsUtilityGE.buildHatchFillwhich calls hatchLineArea.intersect(shapeArea).
* so it assumes that this._pts is the hatch lines so it is hatchLines.intersect(shape) where
* shape is the polygon to be filled with hatch lines
* @param area
*/
public void intersect(Area area)
{
try
{
//assume area is the polygon and "this" is the hatch line shape
int j=0;
ArrayList<POINT2>polygon=area.getPathIterator(null).getPoints();
ArrayList<POINT2>hatchLines=this.getPathIterator(null).getPoints();
//close the polygon
if(polygon.get(0).x != polygon.get(polygon.size()-1).x || polygon.get(0).y != polygon.get(polygon.size()-1).y)
{
polygon.add(new POINT2(polygon.get(polygon.size()-1)));
}
//GeneralPath gp=null;
//GeneralPath masterGP=null;
Line2D hatchLine=null;
Rectangle2D rectHatch=null;
Rectangle2D rectPoly=getMBR(polygon);
ArrayList<POINT2> pts=new ArrayList();
ArrayList<POINT2> ptsTemp=null;
int n=hatchLines.size();
//for(j=0;j<hatchLines.size()-1;j++)
for(j=0;j<n-1;j++)
{
hatchLine=new Line2D.Double(hatchLines.get(j).x,hatchLines.get(j).y,hatchLines.get(j+1).x,hatchLines.get(j+1).y);
rectHatch=hatchLine.getBounds2D();
if(rectHatch.intersects(rectPoly)==false)
continue;
ptsTemp=getLineIntersectPoints(polygon,hatchLine);
if(ptsTemp != null)
pts.addAll(ptsTemp);
}
POINT2 pt=null;
//area.getPathIterator(null).reset();
//area.getPathIterator(null).getPoints().clear();
//this._pts.clear();
this.getPathIterator(null).getPoints().clear();
//area._pts.clear();
n=pts.size();
//for(j=0;j<pts.size();j++)
for(j=0;j<n;j++)
{
pt=pts.get(j);
switch(pt.style)
{
case IPathIterator.SEG_MOVETO:
moveTo(pt.x,pt.y);
break;
case IPathIterator.SEG_LINETO:
lineTo(pt.x,pt.y);
break;
default:
break;
}
}
this.getPathIterator(null).reset();
}
catch(Exception exc)
{
ErrorLogger.LogException(_className, "intersect",
new RendererException("Failed inside intersect", exc));
}
}
}