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}