1 18 package org.apache.batik.ext.awt.geom; 19 20 import java.awt.Rectangle ; 21 import java.io.Serializable ; 22 import java.util.Arrays ; 23 import java.util.Collection ; 24 import java.util.List ; 25 import java.util.Comparator ; 26 import java.util.Iterator ; 27 import java.util.ListIterator ; 28 import java.util.NoSuchElementException ; 29 30 40 41 public class RectListManager implements Collection { 42 Rectangle [] rects = null; 43 int size = 0; 44 45 Rectangle bounds = null; 46 47 51 public static Comparator comparator = new RectXComparator(); 52 53 57 public RectListManager(Collection rects) { 58 this.rects = new Rectangle [rects.size()]; 59 Iterator i = rects.iterator(); 60 int j=0; 61 while (i.hasNext()) 62 this.rects[j++] = (Rectangle )i.next(); 63 this.size = this.rects.length; 64 65 Arrays.sort(this.rects, comparator); 66 } 67 68 74 public RectListManager(Rectangle [] rects) { 75 this(rects, 0, rects.length); 76 } 77 78 86 public RectListManager(Rectangle [] rects, int off, int sz) { 87 this.size = sz; 88 this.rects = new Rectangle [sz]; 89 System.arraycopy(rects, off, this.rects, 0, sz); 90 Arrays.sort(this.rects, comparator); 91 } 92 93 98 public RectListManager(RectListManager rlm) { 99 this(rlm.rects); 100 } 101 102 106 public RectListManager(Rectangle rect) { 107 this(); 108 add(rect); 109 } 110 111 112 115 public RectListManager() { 116 this.rects = new Rectangle [10]; 117 size = 0; 118 } 119 120 126 public RectListManager(int capacity) { 127 this.rects = new Rectangle [capacity]; 128 } 129 130 public Rectangle getBounds() { 131 if (bounds != null ) 132 return bounds; 133 if (size == 0) return null; 134 bounds = new Rectangle (rects[0]); 135 for (int i=1; i< size; i++) { 136 Rectangle r = rects[i]; 137 if (r.x < bounds.x) { 138 bounds.width = bounds.x+bounds.width-r.x; 139 bounds.x = r.x; 140 } 141 if (r.y < bounds.y) { 142 bounds.height = bounds.y+bounds.height-r.y; 143 bounds.y = r.y; 144 } 145 if (r.x+r.width > bounds.x+bounds.width) 146 bounds.width = r.x+r.width-bounds.x; 147 if (r.y+r.height > bounds.y+bounds.height) 148 bounds.height = r.y+r.height-bounds.y; 149 } 150 return bounds; 151 } 152 153 156 public Object clone() { 157 return copy(); 158 } 159 160 163 public RectListManager copy() { 164 return new RectListManager(rects); 165 } 166 167 170 public int size() { return size; } 171 172 173 176 public boolean isEmpty() { return (size==0); } 177 178 public void clear() { 179 for (int i=0; i<size; i++) 180 rects[i] = null; 181 size=0; 182 } 183 184 187 public Iterator iterator() { 188 return new RLMIterator(); 189 } 190 191 195 public ListIterator listIterator() { 196 return new RLMIterator(); 197 } 198 199 public Object [] toArray() { 200 Object [] ret = new Rectangle [size]; 201 System.arraycopy(rects, 0, ret, 0, size); 202 return ret; 203 } 204 205 public Object [] toArray(Object []a) { 206 Class t = a.getClass().getComponentType(); 207 if ((t != Object .class) & 208 (t != Rectangle .class)) { 209 for (int i=0; i<a.length; i++) 211 a[i] = null; 212 return a; 213 } 214 215 if (a.length < size) 216 a = new Rectangle [size]; 217 System.arraycopy(rects, 0, a, 0, size); 218 for (int i=size; i<a.length; i++) 219 a[i] = null; 220 221 return a; 222 } 223 224 public boolean add(Object o) { 225 add((Rectangle )o); 226 return true; 227 } 228 229 233 public void add(Rectangle rect) { 234 add(rect, 0, size-1); 235 } 236 237 247 protected void add(Rectangle rect, int l, int r) { 248 ensureCapacity(size+1); 249 int idx=l; 250 while (l <= r) { 251 idx = (l+r)/2; 252 while ((rects[idx] == null) && (idx <r)) idx++; 253 if (rects[idx] == null) { 254 r = (l+r)/2; 256 idx = (l+r)/2; 257 if (l>r) 258 idx=l; 259 while ((rects[idx] == null) && (idx > l)) idx--; 260 if (rects[idx] == null) { 261 rects[idx] = rect; 262 return; 263 } 264 } 265 if (rect.x == rects[idx].x) break; 266 if (rect.x < rects[idx].x) { 267 if (idx == 0) break; 268 if ((rects[idx-1] != null) && 269 (rect.x >= rects[idx-1].x)) break; 270 r = idx-1; 271 } else { 272 if (idx == size-1) {idx++; break; } 273 if ((rects[idx+1] != null) && 274 (rect.x <= rects[idx+1].x)) { idx++; break;} 275 l = idx+1; 276 } 277 } 278 279 if (idx < size) { 280 System.arraycopy(rects, idx, 281 rects, idx+1, size-idx); 282 } 283 284 291 rects[idx] = rect; 292 size++; 293 } 294 295 public boolean addAll(Collection c) { 296 if (c instanceof RectListManager) { 297 add((RectListManager)c); 298 } else { 299 add(new RectListManager(c)); 300 } 301 302 return (c.size() != 0); 303 } 304 305 public boolean contains(Object o) { 306 Rectangle rect = (Rectangle )o; 307 int l=0, r=size-1, idx=0; 308 while (l <= r) { 309 idx = (l+r)/2; 310 if (rect.x == rects[idx].x) break; 311 if (rect.x < rects[idx].x) { 312 if (idx == 0) break; 313 if (rect.x >= rects[idx-1].x) break; 314 r = idx-1; 315 } else { 316 if (idx == size-1) {idx++; break; } 317 if (rect.x <= rects[idx+1].x) { idx++; break;} 318 l = idx+1; 319 } 320 } 321 if (rects[idx].x != rect.x) return false; 323 324 for (int i=idx; i>=0; i--){ 326 if (rects[idx].equals(rect)) return true; 327 if (rects[idx].x != rect.x) break; 328 } 329 330 for (int i=idx+1; i<size; i++) { 332 if (rects[idx].equals(rect)) return true; 333 if (rects[idx].x != rect.x) break; 334 } 335 336 return false; 338 } 339 340 344 public boolean containsAll(Collection c) { 345 if (c instanceof RectListManager) 346 return containsAll((RectListManager)c); 347 return containsAll(new RectListManager(c)); 348 } 349 350 public boolean containsAll(RectListManager rlm) { 351 int x, xChange = 0; 352 for (int j=0, i=0; j<rlm.size; j++) { 353 i=xChange; 354 while(rects[i].x < rlm.rects[j].x) { 355 i++; 356 if (i == size) return false; 357 } 358 xChange = i; 359 x = rects[i].x; 360 while (!rlm.rects[j].equals(rects[i])) { 361 i++; 362 if (i == size) return false; if (x != rects[i].x) 364 return false; } 366 } 367 return true; 368 } 369 370 375 public boolean remove(Object o) { 376 return remove((Rectangle )o); 377 } 378 379 384 public boolean remove(Rectangle rect) { 385 int l=0, r=size-1, idx=0; 386 while (l <= r) { 387 idx = (l+r)/2; 388 if (rect.x == rects[idx].x) break; 389 if (rect.x < rects[idx].x) { 390 if (idx == 0) break; 391 if (rect.x >= rects[idx-1].x) break; 392 r = idx-1; 393 } else { 394 if (idx == size-1) {idx++; break; } 395 if (rect.x <= rects[idx+1].x) { idx++; break;} 396 l = idx+1; 397 } 398 } 399 if (rects[idx].x != rect.x) return false; 401 402 for (int i=idx; i>=0; i--){ 404 if (rects[idx].equals(rect)) { 405 System.arraycopy(rects, idx+1, rects, idx, size-idx); 406 size--; 407 return true; 408 } 409 if (rects[idx].x != rect.x) break; 410 } 411 412 for (int i=idx+1; i<size; i++) { 414 if (rects[idx].equals(rect)) { 415 System.arraycopy(rects, idx+1, rects, idx, size-idx); 416 size--; 417 return true; 418 } 419 if (rects[idx].x != rect.x) break; 420 } 421 422 return false; 424 } 425 426 public boolean removeAll(Collection c) { 427 if (c instanceof RectListManager) 428 return removeAll((RectListManager)c); 429 return removeAll(new RectListManager(c)); 430 } 431 432 public boolean removeAll(RectListManager rlm) { 433 int x, xChange = 0; 434 boolean ret = false; 435 for (int j=0, i=0; j<rlm.size; j++) { 436 i=xChange; 437 while ((rects[i] == null) || 438 (rects[i].x < rlm.rects[j].x)) { 439 i++; 440 if (i == size) break; 441 } 442 443 if (i == size) break; 444 445 xChange = i; 446 x = rects[i].x; 447 while (true) { 448 if (rects[i] == null) { 449 i++; 450 if (i == size) break; continue; 452 } 453 if (rlm.rects[j].equals(rects[i])) { 454 rects[i] = null; 455 ret = true; 456 } 457 i++; 458 if (i == size) break; if (x != rects[i].x) break; } 461 } 462 463 if (ret) { 465 int j=0, i=0; 466 while (i<size) { 467 if (rects[i] != null) 468 rects[j++] = rects[i]; 469 i++; 470 } 471 size = j; 472 } 473 return ret; 474 } 475 476 public boolean retainAll(Collection c) { 477 if (c instanceof RectListManager) 478 return retainAll((RectListManager)c); 479 return retainAll(new RectListManager(c)); 480 } 481 public boolean retainAll(RectListManager rlm) { 482 int x, xChange = 0; 483 boolean ret = false; 484 485 for (int j=0, i=0; j<size; j++) { 486 i=xChange; 487 while (rlm.rects[i].x < rects[j].x) { 488 i++; 489 if (i == rlm.size) break; 490 } 491 if (i == rlm.size) { 492 ret = true; 493 for (int k=j; k<size; k++) 496 rects[k] = null; 497 size = j; 498 break; 499 } 500 501 xChange = i; 502 x = rlm.rects[i].x; 503 while (true) { 504 if (rects[j].equals(rlm.rects[i])) break; 505 i++; 506 if ((i == rlm.size) || 507 (x != rlm.rects[i].x)) { 508 rects[j] = null; 510 ret = true; 511 break; 512 } 513 } 514 } 515 516 if (ret) { 518 int j=0, i=0; 519 while (i<size) { 520 if (rects[i] != null) 521 rects[j++] = rects[i]; 522 i++; 523 } 524 size = j; 525 } 526 return ret; 527 } 528 529 536 public void add(RectListManager rlm) { 537 if (rlm.size == 0) 538 return; 539 540 Rectangle [] dst = rects; 541 if (rects.length < (size+rlm.size)) { 542 dst = new Rectangle [size+rlm.size]; 543 } 544 545 if (size == 0) { 546 System.arraycopy(rlm.rects, 0, dst, size, rlm.size); 547 size = rlm.size; 548 return; 549 } 550 551 Rectangle [] src1 = rlm.rects; 552 int src1Sz = rlm.size; 553 int src1I = src1Sz-1; 554 555 Rectangle [] src2 = rects; 556 int src2Sz = size; 557 int src2I = src2Sz-1; 558 559 int dstI = size+rlm.size-1; 560 int x1 = src1[src1I].x; 561 int x2 = src2[src2I].x; 562 563 while (dstI >= 0) { 564 if (x1 <= x2) { 565 dst[dstI] = src2[src2I]; 566 if (src2I == 0) { 567 System.arraycopy(src1, 0, dst, 0, src1I+1); 568 break; 569 } 570 src2I--; 571 x2 = src2[src2I].x; 572 } else { 573 dst[dstI] = src1[src1I]; 574 if (src1I == 0) { 575 System.arraycopy(src2, 0, dst, 0, src2I+1); 576 break; 577 } 578 src1I--; 579 x1 = src1[src1I].x; 580 } 581 dstI--; 582 } 583 rects = dst; 584 size += rlm.size; 585 } 586 587 public void mergeRects(int overhead, int lineOverhead) { 588 if (size == 0) return; 589 Rectangle r, cr, mr; 590 int cost1, cost2, cost3; 591 mr = new Rectangle (); 592 Rectangle []splits = new Rectangle [4]; 593 for (int j, i=0; i<size; i++) { 594 r = rects[i]; 595 if (r == null) continue; 596 cost1 = (overhead + 597 (r.height*lineOverhead) + 598 (r.height*r.width)); 599 do { 600 int maxX = r.x+r.width+overhead/r.height; 601 for (j=i+1; j<size; j++) { 602 cr = rects[j]; 603 if ((cr == null) || (cr == r)) continue; 604 if (cr.x >= maxX) { 605 j = size; 607 break; 608 } 609 cost2 = (overhead + 610 (cr.height*lineOverhead) + 611 (cr.height*cr.width)); 612 613 mr = r.union(cr); 614 cost3 = (overhead + 615 (mr.height*lineOverhead) + 616 (mr.height*mr.width)); 617 if (cost3 <= cost1+cost2) { 618 r = rects[i] = mr; 619 rects[j] = null; 620 cost1 = cost3; 621 j=-1; 622 break; 623 } 624 625 if (!r.intersects(cr)) continue; 626 627 splitRect(cr, r, splits); 628 int splitCost=0; 629 int l=0; 630 for (int k=0; k<4; k++) { 631 if (splits[k] != null) { 632 Rectangle sr = splits[k]; 633 if (k<3) splits[l++] = sr; 636 splitCost += (overhead + 637 (sr.height*lineOverhead) + 638 (sr.height*sr.width)); 639 } 640 } 641 if (splitCost >= cost2) continue; 642 643 if (l == 0) { 645 rects[j] = null; 647 if (splits[3] != null) 648 add(splits[3], j, size-1); 649 continue; 650 } 651 652 rects[j] = splits[0]; 653 if (l > 1) 654 insertRects(splits, 1, j+1, l-1); 655 if (splits[3] != null) 656 add(splits[3], j, size-1); 657 } 658 659 } while (j != size); 663 } 664 665 int j=0, i=0; 667 float area=0; 668 while (i<size) { 669 if (rects[i] != null) { 670 r = rects[i]; 671 rects[j++] = r; 672 area += overhead + (r.height*lineOverhead) + 673 (r.height*r.width); 674 } 675 i++; 676 } 677 size = j; 678 r = getBounds(); 679 if (r == null) return; 680 if (overhead + (r.height*lineOverhead) + (r.height*r.width) < area) { 681 rects[0] = r; 682 size=1; 683 } 684 } 685 686 public void subtract(RectListManager rlm, int overhead, int lineOverhead) { 687 Rectangle r, sr; 688 int cost; 689 int jMin=0; 690 Rectangle [] splits = new Rectangle [4]; 691 692 for(int i=0; i<size; i++) { 693 r = rects[i]; cost = (overhead + 695 (r.height*lineOverhead) + 696 (r.height*r.width)); 697 for (int j=jMin; j<rlm.size; j++) { 698 sr = rlm.rects[j]; 700 if (sr.x+sr.width < r.x) { 704 if (j == jMin) jMin++; 707 continue; 708 } 709 710 if (sr.x > r.x+r.width) 714 break; 715 716 if (!r.intersects(sr)) 718 continue; 719 720 723 splitRect(r, sr, splits); 724 725 int splitCost=0; 726 Rectangle tmpR; 727 for (int k=0; k<4; k++) { 728 tmpR = splits[k]; 729 if (tmpR != null) 730 splitCost += (overhead + 731 (tmpR.height*lineOverhead) + 732 (tmpR.height*tmpR.width)); 733 } 734 735 if (splitCost >= cost) 736 continue; 743 744 int l = 0; 747 for (int k=0; k<3; k++) { 748 if (splits[k] != null) 749 splits[l++] = splits[k]; 750 } 751 752 if (l==0) { 755 rects[i].width = 0; 756 if (splits[3] != null) 759 add(splits[3], i, size-1); 760 break; 761 } 762 763 r = splits[0]; 768 rects[i] = r; 769 cost = (overhead + 770 (r.height*lineOverhead) + 771 (r.height*r.width)); 772 773 if (l > 1) 777 insertRects(splits, 1, i+1, l-1); 778 779 if (splits[3] != null) 782 add(splits[3], i+l, size-1); 783 } 784 } 785 786 int j=0, i=0; 788 while (i<size) { 789 if (rects[i].width == 0) 790 rects[i] = null; 791 else 792 rects[j++] = rects[i]; 793 i++; 794 } 795 size = j; 796 } 797 798 protected void splitRect(Rectangle r, Rectangle sr, 799 Rectangle []splits) { 800 822 int rx0 = r.x; 823 int rx1 = rx0+r.width-1; 824 int ry0 = r.y; 825 int ry1 = ry0+r.height-1; 826 827 int srx0 = sr.x; 828 int srx1 = srx0+sr.width-1; 829 int sry0 = sr.y; 830 int sry1 = sry0+sr.height-1; 831 832 if ((ry0 < sry0) && (ry1 >= sry0)) { 833 splits[0] = new Rectangle (rx0, ry0, r.width, sry0-ry0); 834 ry0 = sry0; 835 } else { 836 splits[0] = null; 837 } 838 839 if ((ry0 <= sry1) && (ry1 > sry1)) { 840 splits[1] = new Rectangle (rx0, sry1+1, r.width, ry1-sry1); 841 ry1 = sry1; 842 } else { 843 splits[1] = null; 844 } 845 846 if ((rx0 < srx0) && (rx1 >= srx0)) { 847 splits[2] = new Rectangle (rx0, ry0, srx0-rx0, ry1-ry0+1); 848 } else { 849 splits[2] = null; 850 } 851 852 if ((rx0 <= srx1) && (rx1 > srx1)) { 853 splits[3]= new Rectangle (srx1+1, ry0, rx1-srx1, ry1-ry0+1); 854 } else { 855 splits[3] = null; 856 } 857 } 858 859 protected void insertRects(Rectangle [] rects, int srcPos, 860 int dstPos, int len) { 861 if (len == 0) return; 862 863 ensureCapacity(size+len); 865 866 for (int i=size-1; i>=dstPos; i--) 868 this.rects[i+len] = this.rects[i]; 869 870 for (int i=0; i<len; i++) 872 this.rects[i+dstPos] = rects[i+srcPos]; 873 874 size += len; 875 } 876 877 public void ensureCapacity(int sz) { 878 if (sz <= rects.length) 879 return; 880 int nSz = rects.length + (rects.length>>1) + 1; 881 while (nSz < sz) 882 nSz+=(nSz>>1)+1; 883 884 Rectangle [] nRects = new Rectangle [nSz]; 885 System.arraycopy(rects, 0, nRects, 0, size); 886 887 rects = nRects; 888 } 889 890 896 private static class RectXComparator implements Comparator , Serializable { 897 898 RectXComparator() { } 899 900 public final int compare(Object o1, Object o2) { 901 return ((Rectangle )o1).x-((Rectangle )o2).x; 902 } 903 } 904 905 906 private class RLMIterator implements ListIterator { 907 int idx = 0; 908 boolean removeOk = false; 909 boolean forward = true; 910 RLMIterator() { } 911 912 public boolean hasNext() { return idx < size; } 913 public int nextIndex() { return idx; } 914 public Object next() { 915 if (idx >= size) 916 throw new NoSuchElementException ("No Next Element"); 917 forward = true; 918 removeOk = true; 919 return rects[idx++]; 920 } 921 922 public boolean hasPrevious() { return idx > 0; } 923 public int previousIndex() { return idx-1; } 924 public Object previous() { 925 if (idx <= 0) 926 throw new NoSuchElementException ("No Previous Element"); 927 forward = false; 928 removeOk = true; 929 return rects[--idx]; 930 } 931 932 public void remove() { 933 if (!removeOk) 934 throw new IllegalStateException 935 ("remove can only be called directly after next/previous"); 936 937 if (forward) idx--; 938 if (idx != size-1) 939 System.arraycopy(rects, idx+1, rects, idx, size-(idx+1)); 940 size--; 941 rects[size] = null; 942 removeOk = false; 943 } 944 945 946 public void set(Object o) { 947 Rectangle r = (Rectangle )o; 948 949 if (!removeOk) 950 throw new IllegalStateException 951 ("set can only be called directly after next/previous"); 952 953 if (forward) idx--; 954 955 if (idx+1<size) { 956 if (rects[idx+1].x < r.x) 957 throw new UnsupportedOperationException 958 ("RectListManager entries must be sorted"); 959 } 960 if (idx>=0) { 961 if (rects[idx-1].x > r.x) 962 throw new UnsupportedOperationException 963 ("RectListManager entries must be sorted"); 964 } 965 966 rects[idx] = r; 967 removeOk = false; 968 } 969 970 public void add(Object o) { 971 Rectangle r = (Rectangle )o; 972 if (idx<size) { 973 if (rects[idx].x < r.x) 974 throw new UnsupportedOperationException 975 ("RectListManager entries must be sorted"); 976 } 977 if (idx!=0) { 978 if (rects[idx-1].x > r.x) 979 throw new UnsupportedOperationException 980 ("RectListManager entries must be sorted"); 981 } 982 ensureCapacity(size+1); 983 if (idx != size) 984 System.arraycopy(rects, idx, rects, idx+1, size-idx); 985 rects[idx] = r; 986 idx++; 987 removeOk = false; 988 } 989 } 990 } 991 | Popular Tags |