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