001/* 002 * To change this template, choose Tools | Templates 003 * and open the template in the editor. 004 */ 005package sec.sun.awt.geom; 006 007/** 008 * 009 * @author Michael Deutch 010 */ 011public class AreaOp2 { 012 public static final int EOWINDOP = 0; 013 public static final int NZWINDOP = 1; 014 /* Constants to tag the left and right curves in the edge list */ 015 public static final int CTAG_LEFT = 0; 016 public static final int CTAG_RIGHT = 1; 017 018 /* Constants to classify edges */ 019 public static final int ETAG_IGNORE = 0; 020 public static final int ETAG_ENTER = 1; 021 public static final int ETAG_EXIT = -1; 022 023 /* Constants used to classify result state */ 024 public static final int RSTAG_INSIDE = 1; 025 public static final int RSTAG_OUTSIDE = -1; 026 027 private EOWindOp eo=null; 028 private NZWindOp nz=null; 029 public AreaOp2(int type) { 030 //_type=type; 031 switch(type) 032 { 033 case EOWINDOP: 034 eo=new EOWindOp(); 035 break; 036 case NZWINDOP: 037 nz=new NZWindOp(); 038 break; 039 default: 040 break; 041 } 042 } 043 044 public Vector calculate(Vector left, Vector right) { 045 Vector edges = new Vector(); 046 addEdges(edges, left, CTAG_LEFT); 047 addEdges(edges, right, CTAG_RIGHT); 048 edges = pruneEdges(edges); 049 if (false) { 050 System.out.println("result: "); 051 int numcurves = edges.size(); 052 //Curve[] curvelist = (Curve[]) edges.toArray(new Curve[numcurves]); 053 Curve[] curvelist = (Curve[]) edges.toArray2(); 054 for (int i = 0; i < numcurves; i++) { 055 System.out.println("curvelist["+i+"] = "+curvelist[i]); 056 } 057 } 058 return edges; 059 } 060 061 private static void addEdges(Vector edges, Vector curves, int curvetag) { 062 Enumeration enum_ = curves.elements(); 063 CurveObject c=null; 064 Object obj=null; 065 while (enum_.hasMoreElements()) { 066 obj=enum_.nextElement(); 067 if(obj instanceof CurveObject) 068 c=(CurveObject)obj; 069 else 070 c=new CurveObject(obj); 071 if (c.getOrder() > 0) { 072 edges.add(new Edge(c, curvetag)); 073 } 074 } 075 } 076 077 private Vector pruneEdges(Vector edges) { 078 EOWindOp eo=new EOWindOp(); 079 NZWindOp nz=new NZWindOp(); 080 int numedges = edges.size(); 081 if (numedges < 2) { 082 return edges; 083 } 084 Edge[] edgelist = new Edge[numedges]; 085 Enumeration _enum=edges.elements(); 086 int k=0; 087 while(_enum.hasMoreElements()) 088 { 089 edgelist[k++]=(Edge)_enum.nextElement(); 090 } 091 Arrays.sort(edgelist); 092 if (false) { 093 System.out.println("pruning: "); 094 for (int i = 0; i < numedges; i++) { 095 System.out.println("edgelist["+i+"] = "+edgelist[i]); 096 } 097 } 098 Edge e; 099 int left = 0; 100 int right = 0; 101 int cur = 0; 102 int next = 0; 103 double yrange[] = new double[2]; 104 Vector subcurves = new Vector(); 105 Vector chains = new Vector(); 106 Vector links = new Vector(); 107 // Active edges are between left (inclusive) and right (exclusive) 108 while (left < numedges) { 109 double y = yrange[0]; 110 // Prune active edges that fall off the top of the active y range 111 for (cur = next = right - 1; cur >= left; cur--) { 112 e = edgelist[cur]; 113 if (e.getCurve().getYBot() > y) { 114 if (next > cur) { 115 edgelist[next] = e; 116 } 117 next--; 118 } 119 } 120 left = next + 1; 121 // Grab a new "top of Y range" if the active edges are empty 122 if (left >= right) { 123 if (right >= numedges) { 124 break; 125 } 126 y = edgelist[right].getCurve().getYTop(); 127 if (y > yrange[0]) { 128 finalizeSubCurves(subcurves, chains); 129 } 130 yrange[0] = y; 131 } 132 // Incorporate new active edges that enter the active y range 133 while (right < numedges) { 134 e = edgelist[right]; 135 if (e.getCurve().getYTop() > y) { 136 break; 137 } 138 right++; 139 } 140 // Sort the current active edges by their X values and 141 // determine the maximum valid Y range where the X ordering 142 // is correct 143 yrange[1] = edgelist[left].getCurve().getYBot(); 144 if (right < numedges) { 145 y = edgelist[right].getCurve().getYTop(); 146 if (yrange[1] > y) { 147 yrange[1] = y; 148 } 149 } 150 if (false) { 151 System.out.println("current line: y = ["+ 152 yrange[0]+", "+yrange[1]+"]"); 153 for (cur = left; cur < right; cur++) { 154 System.out.println(" "+edgelist[cur]); 155 } 156 } 157 // Note: We could start at left+1, but we need to make 158 // sure that edgelist[left] has its equivalence set to 0. 159 int nexteq = 1; 160 for (cur = left; cur < right; cur++) { 161 e = edgelist[cur]; 162 e.setEquivalence(0); 163 for (next = cur; next > left; next--) { 164 Edge prevedge = edgelist[next-1]; 165 int ordering = e.compareTo(prevedge, yrange); 166 if (yrange[1] <= yrange[0]) { 167 throw new InternalError("backstepping to "+yrange[1]+ 168 " from "+yrange[0]); 169 } 170 if (ordering >= 0) { 171 if (ordering == 0) { 172 // If the curves are equal, mark them to be 173 // deleted later if they cancel each other 174 // out so that we avoid having extraneous 175 // curve segments. 176 int eq = prevedge.getEquivalence(); 177 if (eq == 0) { 178 eq = nexteq++; 179 prevedge.setEquivalence(eq); 180 } 181 e.setEquivalence(eq); 182 } 183 break; 184 } 185 edgelist[next] = prevedge; 186 } 187 edgelist[next] = e; 188 } 189 if (false) { 190 System.out.println("current sorted line: y = ["+ 191 yrange[0]+", "+yrange[1]+"]"); 192 for (cur = left; cur < right; cur++) { 193 System.out.println(" "+edgelist[cur]); 194 } 195 } 196 // Now prune the active edge list. 197 // For each edge in the list, determine its classification 198 // (entering shape, exiting shape, ignore - no change) and 199 // record the current Y range and its classification in the 200 // Edge object for use later in constructing the new outline. 201 newRow(); 202 double ystart = yrange[0]; 203 double yend = yrange[1]; 204 for (cur = left; cur < right; cur++) { 205 e = edgelist[cur]; 206 int etag; 207 int eq = e.getEquivalence(); 208 if (eq != 0) { 209 // Find one of the segments in the "equal" range 210 // with the right transition state and prefer an 211 // edge that was either active up until ystart 212 // or the edge that extends the furthest downward 213 // (i.e. has the most potential for continuation) 214 int origstate = getState(); 215 etag = (origstate == RSTAG_INSIDE 216 ? ETAG_EXIT 217 : ETAG_ENTER); 218 Edge activematch = null; 219 Edge longestmatch = e; 220 double furthesty = yend; 221 do { 222 // Note: classify() must be called 223 // on every edge we consume here. 224 classify(e); 225 if (activematch == null && 226 e.isActiveFor(ystart, etag)) 227 { 228 activematch = e; 229 } 230 y = e.getCurve().getYBot(); 231 if (y > furthesty) { 232 longestmatch = e; 233 furthesty = y; 234 } 235 } while (++cur < right && 236 (e = edgelist[cur]).getEquivalence() == eq); 237 --cur; 238 if (getState() == origstate) 239 { 240 etag = ETAG_IGNORE; 241 } 242 else 243 { 244 e = (activematch != null ? activematch : longestmatch); 245 } 246 } else 247 { 248 etag = classify(e); 249 } 250 if (etag != ETAG_IGNORE) { 251 e.record(yend, etag); 252 links.add(new CurveLink(e.getCurve(), ystart, yend, etag)); 253 } 254 } 255 // assert(getState() == AreaOp.RSTAG_OUTSIDE); 256 if (getState() != RSTAG_OUTSIDE) { 257 System.out.println("Still inside at end of active edge list!"); 258 System.out.println("num curves = "+(right-left)); 259 System.out.println("num links = "+links.size()); 260 System.out.println("y top = "+yrange[0]); 261 if (right < numedges) { 262 System.out.println("y top of next curve = "+ 263 edgelist[right].getCurve().getYTop()); 264 } else { 265 System.out.println("no more curves"); 266 } 267 for (cur = left; cur < right; cur++) { 268 e = edgelist[cur]; 269 System.out.println(e); 270 int eq = e.getEquivalence(); 271 if (eq != 0) { 272 System.out.println(" was equal to "+eq+"..."); 273 } 274 } 275 } 276 if (false) { 277 System.out.println("new links:"); 278 for (int i = 0; i < links.size(); i++) { 279 CurveLink link = (CurveLink) links.elementAt(i); 280 System.out.println(" "+link.getSubCurve()); 281 } 282 } 283 resolveLinks(subcurves, chains, links); 284 links.clear(); 285 // Finally capture the bottom of the valid Y range as the top 286 // of the next Y range. 287 yrange[0] = yend; 288 } 289 finalizeSubCurves(subcurves, chains); 290 Vector ret = new Vector(); 291 Enumeration enum_ = subcurves.elements(); 292 CurveObject c=null; 293 Object obj=null; 294 while (enum_.hasMoreElements()) { 295 CurveLink link = (CurveLink) enum_.nextElement(); 296 ret.add(link.getMoveto()); 297 CurveLink nextlink = link; 298 while ((nextlink = nextlink.getNext()) != null) { 299 if (!link.absorb(nextlink)) 300 { 301 //ret.add(link.getSubCurve()); 302 obj=link.getSubCurve(); 303 if(obj instanceof Order0) 304 c=((Order0)obj).getParent(); 305 else if(obj instanceof Order1) 306 c=((Order1)obj).getParent(); 307 else if(obj instanceof Order2) 308 c=((Order2)obj).getParent(); 309 else if(obj instanceof Order3) 310 c=((Order3)obj).getParent(); 311 else if(obj instanceof CurveObject) 312 c=(CurveObject)obj; 313 if(c==null) 314 c=new CurveObject(obj); 315 316 317 ret.add(c); 318 link = nextlink; 319 } 320 } 321 obj=link.getSubCurve(); 322 //ret.add(link.getSubCurve()); 323 if(obj instanceof Order0) 324 c=((Order0)obj).getParent(); 325 else if(obj instanceof Order1) 326 c=((Order1)obj).getParent(); 327 else if(obj instanceof Order2) 328 c=((Order2)obj).getParent(); 329 else if(obj instanceof Order3) 330 c=((Order3)obj).getParent(); 331 else if(obj instanceof CurveObject) 332 c=(CurveObject)obj; 333 if(c==null) 334 c=new CurveObject(obj); 335 336 ret.add(c); 337 } 338 return ret; 339 } 340 341 public static void finalizeSubCurves(Vector subcurves, Vector chains) { 342 int numchains = chains.size(); 343 if (numchains == 0) { 344 return; 345 } 346 if ((numchains & 1) != 0) { 347 throw new InternalError("Odd number of chains!"); 348 } 349 ChainEnd[] endlist = new ChainEnd[numchains]; 350 chains.toArray(endlist); 351 for (int i = 1; i < numchains; i += 2) { 352 ChainEnd open = endlist[i - 1]; 353 ChainEnd close = endlist[i]; 354 CurveLink subcurve = open.linkTo(close); 355 if (subcurve != null) { 356 subcurves.add(subcurve); 357 } 358 } 359 chains.clear(); 360 } 361 362 private static CurveLink[] EmptyLinkList = new CurveLink[2]; 363 private static ChainEnd[] EmptyChainList = new ChainEnd[2]; 364 365 public static void resolveLinks(Vector subcurves, 366 Vector chains, 367 Vector links) 368 { 369 int numlinks = links.size(); 370 CurveLink[] linklist; 371 if (numlinks == 0) { 372 linklist = EmptyLinkList; 373 } else { 374 if ((numlinks & 1) != 0) { 375 throw new InternalError("Odd number of new curves!"); 376 } 377 linklist = new CurveLink[numlinks+2]; 378 links.toArray(linklist); 379 } 380 int numchains = chains.size(); 381 ChainEnd[] endlist; 382 if (numchains == 0) { 383 endlist = EmptyChainList; 384 } else { 385 if ((numchains & 1) != 0) { 386 throw new InternalError("Odd number of chains!"); 387 } 388 endlist = new ChainEnd[numchains+2]; 389 chains.toArray(endlist); 390 } 391 int curchain = 0; 392 int curlink = 0; 393 chains.clear(); 394 ChainEnd chain = endlist[0]; 395 ChainEnd nextchain = endlist[1]; 396 CurveLink link = linklist[0]; 397 CurveLink nextlink = linklist[1]; 398 while (chain != null || link != null) { 399 /* 400 * Strategy 1: 401 * Connect chains or links if they are the only things left... 402 */ 403 boolean connectchains = (link == null); 404 boolean connectlinks = (chain == null); 405 406 if (!connectchains && !connectlinks) { 407 // assert(link != null && chain != null); 408 /* 409 * Strategy 2: 410 * Connect chains or links if they close off an open area... 411 */ 412 connectchains = ((curchain & 1) == 0 && 413 chain.getX() == nextchain.getX()); 414 connectlinks = ((curlink & 1) == 0 && 415 link.getX() == nextlink.getX()); 416 417 if (!connectchains && !connectlinks) { 418 /* 419 * Strategy 3: 420 * Connect chains or links if their successor is 421 * between them and their potential connectee... 422 */ 423 double cx = chain.getX(); 424 double lx = link.getX(); 425 connectchains = 426 (nextchain != null && cx < lx && 427 obstructs(nextchain.getX(), lx, curchain)); 428 connectlinks = 429 (nextlink != null && lx < cx && 430 obstructs(nextlink.getX(), cx, curlink)); 431 } 432 } 433 if (connectchains) { 434 CurveLink subcurve = chain.linkTo(nextchain); 435 if (subcurve != null) { 436 subcurves.add(subcurve); 437 } 438 curchain += 2; 439 chain = endlist[curchain]; 440 nextchain = endlist[curchain+1]; 441 } 442 if (connectlinks) { 443 ChainEnd openend = new ChainEnd(link, null); 444 ChainEnd closeend = new ChainEnd(nextlink, openend); 445 openend.setOtherEnd(closeend); 446 chains.add(openend); 447 chains.add(closeend); 448 curlink += 2; 449 link = linklist[curlink]; 450 nextlink = linklist[curlink+1]; 451 } 452 if (!connectchains && !connectlinks) { 453 // assert(link != null); 454 // assert(chain != null); 455 // assert(chain.getEtag() == link.getEtag()); 456 chain.addLink(link); 457 chains.add(chain); 458 curchain++; 459 chain = nextchain; 460 nextchain = endlist[curchain+1]; 461 curlink++; 462 link = nextlink; 463 nextlink = linklist[curlink+1]; 464 } 465 } 466 if ((chains.size() & 1) != 0) { 467 System.out.println("Odd number of chains!"); 468 } 469 } 470 471 /* 472 * Does the position of the next edge at v1 "obstruct" the 473 * connectivity between current edge and the potential 474 * partner edge which is positioned at v2? 475 * 476 * Phase tells us whether we are testing for a transition 477 * into or out of the interior part of the resulting area. 478 * 479 * Require 4-connected continuity if this edge and the partner 480 * edge are both "entering into" type edges 481 * Allow 8-connected continuity for "exiting from" type edges 482 */ 483 public static boolean obstructs(double v1, double v2, int phase) { 484 return (((phase & 1) == 0) ? (v1 <= v2) : (v1 < v2)); 485 } 486 private void newRow() 487 { 488 if(eo!=null) 489 eo.newRow(); 490 else if(nz!=null) 491 nz.newRow(); 492 } 493 private int getState() 494 { 495 if(eo!=null) 496 return eo.getState(); 497 else if(nz!=null) 498 return nz.getState(); 499 else return -1; 500 } 501 private int classify(Edge e) 502 { 503 if(eo!=null) 504 return eo.classify(e); 505 else if(nz!=null) 506 return nz.classify(e); 507 else return -1; 508 } 509}