PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/batik/src/main/java/org/apache/batik/ext/awt/geom/RectListManager.java

https://github.com/rmuller/xmlgraphics-mavenized
Java | 1017 lines | 673 code | 117 blank | 227 comment | 236 complexity | 0c25ea0295f16a5c7d137a7214e17d60 MD5 | raw file
  1. /*
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. */
  15. package org.apache.batik.ext.awt.geom;
  16. import java.awt.Rectangle;
  17. import java.io.Serializable;
  18. import java.util.Arrays;
  19. import java.util.Collection;
  20. import java.util.Comparator;
  21. import java.util.Iterator;
  22. import java.util.ListIterator;
  23. import java.util.NoSuchElementException;
  24. /**
  25. * RectListManager is a class to manage a list of rectangular regions.
  26. * This class contains methods to add new rectangles to the List, to
  27. * merge rectangles in the list (based on a cost function), and
  28. * functions to subract one RectListManager from another. The main
  29. * purpose of this class is to manage dirty regions on a display (for
  30. * this reason it uses Rectangle not Rectangle2D).
  31. *
  32. * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
  33. * @version $Id: RectListManager.java 1372129 2012-08-12 15:31:50Z helder $
  34. */
  35. public class RectListManager implements Collection {
  36. Rectangle [] rects = null;
  37. int size = 0;
  38. Rectangle bounds = null;
  39. public void dump() {
  40. System.err.println("RLM: " + this + " Sz: " + size);
  41. System.err.println("Bounds: " + getBounds());
  42. for (int i=0; i<size; i++) {
  43. Rectangle r = rects[i];
  44. System.err.println(" [" + r.x + ", " + r.y + ", " +
  45. r.width + ", " + r.height + ']' );
  46. }
  47. }
  48. /**
  49. * The comparator used to sort the elements of this List.
  50. * Sorts on x value of Rectangle.
  51. */
  52. public static Comparator comparator = new RectXComparator();
  53. /**
  54. * Construct a <code>RectListManager</code> from a Collection of Rectangles
  55. * @param rects Collection that must only contain rectangles.
  56. */
  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()) // todo can be replaced by rects.toArray()
  62. this.rects[j++] = (Rectangle)i.next();
  63. this.size = this.rects.length;
  64. Arrays.sort(this.rects, comparator);
  65. }
  66. /**
  67. * Construct a <code>RectListManager</code> from an Array of
  68. * <code>Rectangles</code>
  69. * @param rects Array of <code>Rectangles</code>, must not contain
  70. * any null entries.
  71. */
  72. public RectListManager(Rectangle [] rects) {
  73. this(rects, 0, rects.length);
  74. }
  75. /**
  76. * Construct a <code>RectListManager</code> from an Array of
  77. * <code>Rectangles</code>
  78. * @param rects Array of <code>Rectangles</code>, must not contain
  79. * any null entries in the range [off, off+sz-1].
  80. * @param off The offset to start copying from in rects.
  81. * @param sz The number of entries to copy from rects.
  82. */
  83. public RectListManager(Rectangle [] rects, int off, int sz) {
  84. this.size = sz;
  85. this.rects = new Rectangle[sz];
  86. System.arraycopy(rects, off, this.rects, 0, sz);
  87. Arrays.sort(this.rects, comparator);
  88. }
  89. /**
  90. * Construct a <code>RectListManager</code> from another
  91. * <code>RectListManager</code> (data is copied).
  92. * @param rlm RectListManager to copy.
  93. */
  94. public RectListManager(RectListManager rlm) {
  95. this(rlm.rects);
  96. }
  97. /**
  98. * Construct a <code>RectListManager</code> with one rectangle
  99. * @param rect The rectangle to put in this rlm.
  100. */
  101. public RectListManager(Rectangle rect) {
  102. this();
  103. add(rect);
  104. }
  105. /**
  106. * Construct an initially empty <code>RectListManager</code>.
  107. */
  108. public RectListManager() {
  109. this.rects = new Rectangle[10];
  110. size = 0;
  111. }
  112. /**
  113. * Construct an initially empty <code>RectListManager</code>,
  114. * with initial <code>capacity</code>.
  115. * @param capacity The inital capacity for the list. Setting
  116. * this appropriately can save reallocations.
  117. */
  118. public RectListManager(int capacity) {
  119. this.rects = new Rectangle[capacity];
  120. }
  121. public Rectangle getBounds() {
  122. if (bounds != null )
  123. return bounds;
  124. if (size == 0) return null;
  125. bounds = new Rectangle(rects[0]);
  126. for (int i=1; i< size; i++) {
  127. Rectangle r = rects[i];
  128. if (r.x < bounds.x) {
  129. bounds.width = bounds.x+bounds.width-r.x;
  130. bounds.x = r.x;
  131. }
  132. if (r.y < bounds.y) {
  133. bounds.height = bounds.y+bounds.height-r.y;
  134. bounds.y = r.y;
  135. }
  136. if (r.x+r.width > bounds.x+bounds.width)
  137. bounds.width = r.x+r.width-bounds.x;
  138. if (r.y+r.height > bounds.y+bounds.height)
  139. bounds.height = r.y+r.height-bounds.y;
  140. }
  141. return bounds;
  142. }
  143. /**
  144. * Standard <code>Object</code> clone method.
  145. */
  146. public Object clone() throws CloneNotSupportedException {
  147. return copy();
  148. }
  149. /**
  150. * Similar to clone only strongly typed
  151. * TODO Java 5: The use of covariant return types on clone() can eliminate
  152. * this method.
  153. */
  154. public RectListManager copy() {
  155. return new RectListManager(rects);
  156. }
  157. /**
  158. * Returns the number of elements currently stored in this collection.
  159. */
  160. public int size() { return size; }
  161. /**
  162. * Returns true if this collection contains no elements.
  163. */
  164. public boolean isEmpty() { return (size==0); }
  165. public void clear() {
  166. Arrays.fill( rects, null );
  167. size=0;
  168. bounds = null;
  169. }
  170. /**
  171. * Returns an iterator over the elements in this collection
  172. */
  173. public Iterator iterator() {
  174. return new RLMIterator();
  175. }
  176. /**
  177. * Returns a list iterator of the elements in this list
  178. * (in proper sequence).
  179. */
  180. public ListIterator listIterator() {
  181. return new RLMIterator();
  182. }
  183. public Object [] toArray() {
  184. Object [] ret = new Rectangle[size];
  185. System.arraycopy(rects, 0, ret, 0, size);
  186. return ret;
  187. }
  188. /**
  189. * fill the given array a with values from my internal <code>rects</code>.
  190. * when a is not large enough, a new array is allocated, filled and returned.
  191. * the method works only, when a is a Object[] or a Rectange[].
  192. * When this is not the case, the a[] is just cleared.
  193. *
  194. * @param a array to fill (must not be null!)
  195. * @return the content of rects, either in a[] or a fresh array.
  196. */
  197. public Object [] toArray(Object[] a) {
  198. Class t = a.getClass().getComponentType();
  199. if ((t != Object.class) &&
  200. (t != Rectangle.class)) {
  201. // Nothing here for it...
  202. Arrays.fill( a, null );
  203. return a;
  204. }
  205. if (a.length < size)
  206. a = new Rectangle[size];
  207. System.arraycopy(rects, 0, a, 0, size);
  208. Arrays.fill( a, size, a.length, null );
  209. return a;
  210. }
  211. public boolean add(Object o) {
  212. add((Rectangle)o);
  213. return true;
  214. }
  215. /**
  216. * Ensures that this collection contains the specified element
  217. * @param rect The rectangle to add
  218. */
  219. public void add(Rectangle rect) {
  220. add(rect, 0, size-1);
  221. }
  222. /**
  223. * Ensures that this collection contains the specified element
  224. * l is the lower bound index for insertion r is upper
  225. * bound index for insertion.
  226. * @param rect The rectangle to add
  227. * @param l the lowest possible index for a rect with
  228. * greater 'x' coord.
  229. * @param r the highest possible index for a rect with
  230. * greater 'x' coord.
  231. */
  232. protected void add(Rectangle rect, int l, int r) {
  233. ensureCapacity(size+1);
  234. int idx=l;
  235. while (l <= r) {
  236. idx = (l+r)/2;
  237. while ((rects[idx] == null) && (idx <r)) idx++;
  238. if (rects[idx] == null) {
  239. // All 'null' from center to r so skip them
  240. r = (l+r)/2;
  241. idx = (l+r)/2;
  242. if (l>r)
  243. idx=l;
  244. while ((rects[idx] == null) && (idx > l)) idx--;
  245. if (rects[idx] == null) {
  246. rects[idx] = rect;
  247. return;
  248. }
  249. }
  250. if (rect.x == rects[idx].x) break;
  251. if (rect.x < rects[idx].x) {
  252. if (idx == 0) break;
  253. if ((rects[idx-1] != null) &&
  254. (rect.x >= rects[idx-1].x)) break;
  255. r = idx-1;
  256. } else {
  257. if (idx == size-1) {idx++; break; }
  258. if ((rects[idx+1] != null) &&
  259. (rect.x <= rects[idx+1].x)) { idx++; break;}
  260. l = idx+1;
  261. }
  262. }
  263. if (idx < size) {
  264. System.arraycopy(rects, idx,
  265. rects, idx+1, size-idx);
  266. }
  267. // if (idx!=0) System.out.print(rects[idx-1].x);
  268. // else System.out.print("[First]");
  269. // System.out.print(" " + rect.x + " ");
  270. // if (idx<size) System.out.print(rects[idx+1].x);
  271. // else System.out.print("[last]");
  272. // System.out.println("");
  273. rects[idx] = rect;
  274. size++;
  275. bounds=null;
  276. }
  277. public boolean addAll(Collection c) {
  278. if (c instanceof RectListManager) {
  279. add((RectListManager)c);
  280. } else {
  281. add(new RectListManager(c));
  282. }
  283. return (c.size() != 0);
  284. }
  285. public boolean contains(Object o) {
  286. Rectangle rect = (Rectangle)o;
  287. int l=0, r=size-1, idx=0;
  288. while (l <= r) {
  289. idx = (l+r) >>> 1;
  290. if (rect.x == rects[idx].x) break;
  291. if (rect.x < rects[idx].x) {
  292. if (idx == 0) break;
  293. if (rect.x >= rects[idx-1].x) break;
  294. r = idx-1;
  295. } else {
  296. if (idx == size-1) {idx++; break; }
  297. if (rect.x <= rects[idx+1].x) { idx++; break;}
  298. l = idx+1;
  299. }
  300. }
  301. // Didn't find any rect with the same x value.
  302. if (rects[idx].x != rect.x) return false;
  303. // Search towards 0 from idx for rect that matches
  304. for (int i=idx; i>=0; i--){
  305. if (rects[idx].equals(rect)) return true;
  306. if (rects[idx].x != rect.x) break;
  307. }
  308. // Search towards size from idx for rect that matches
  309. for (int i=idx+1; i<size; i++) {
  310. if (rects[idx].equals(rect)) return true;
  311. if (rects[idx].x != rect.x) break;
  312. }
  313. // No match...
  314. return false;
  315. }
  316. /**
  317. * Returns true if this collection contains all of the elements in
  318. * the specified collection.
  319. */
  320. public boolean containsAll(Collection c) {
  321. if (c instanceof RectListManager)
  322. return containsAll((RectListManager)c);
  323. return containsAll(new RectListManager(c));
  324. }
  325. public boolean containsAll(RectListManager rlm) {
  326. int x, xChange = 0;
  327. for (int j=0, i=0; j<rlm.size; j++) {
  328. i=xChange;
  329. while(rects[i].x < rlm.rects[j].x) {
  330. i++;
  331. if (i == size) return false;
  332. }
  333. xChange = i;
  334. x = rects[i].x;
  335. while (!rlm.rects[j].equals(rects[i])) {
  336. i++;
  337. if (i == size) return false; // out of rects
  338. if (x != rects[i].x)
  339. return false; // out of the zone.
  340. }
  341. }
  342. return true;
  343. }
  344. /**
  345. * Removes a single instance of the specified element from this
  346. * collection, if it is present.
  347. * @param o Object to remove an matching instance of.
  348. */
  349. public boolean remove(Object o) {
  350. return remove((Rectangle)o);
  351. }
  352. /**
  353. * Removes a single instance of the specified Rectangle from this
  354. * collection, if it is present.
  355. * @param rect Rectangle to remove an matching instance of.
  356. */
  357. public boolean remove(Rectangle rect) {
  358. int l=0, r=size-1, idx=0;
  359. while (l <= r) {
  360. idx = (l+r) >>> 1;
  361. if (rect.x == rects[idx].x) break;
  362. if (rect.x < rects[idx].x) {
  363. if (idx == 0) break;
  364. if (rect.x >= rects[idx-1].x) break;
  365. r = idx-1;
  366. } else {
  367. if (idx == size-1) {idx++; break; }
  368. if (rect.x <= rects[idx+1].x) { idx++; break;}
  369. l = idx+1;
  370. }
  371. }
  372. // Didn't find any rect with the same x value.
  373. if (rects[idx].x != rect.x) return false;
  374. // Search towards 0 from idx for rect that matches
  375. for (int i=idx; i>=0; i--){
  376. if (rects[idx].equals(rect)) {
  377. System.arraycopy(rects, idx+1, rects, idx, size-idx);
  378. size--;
  379. bounds = null;
  380. return true;
  381. }
  382. if (rects[idx].x != rect.x) break;
  383. }
  384. // Search towards size from idx for rect that matches
  385. for (int i=idx+1; i<size; i++) {
  386. if (rects[idx].equals(rect)) {
  387. System.arraycopy(rects, idx+1, rects, idx, size-idx);
  388. size--;
  389. bounds = null;
  390. return true;
  391. }
  392. if (rects[idx].x != rect.x) break;
  393. }
  394. // No match...
  395. return false;
  396. }
  397. public boolean removeAll(Collection c) {
  398. if (c instanceof RectListManager)
  399. return removeAll((RectListManager)c);
  400. return removeAll(new RectListManager(c));
  401. }
  402. public boolean removeAll(RectListManager rlm) {
  403. int x, xChange = 0;
  404. boolean ret = false;
  405. for (int j=0, i=0; j<rlm.size; j++) {
  406. i=xChange;
  407. while ((rects[i] == null) ||
  408. (rects[i].x < rlm.rects[j].x)) {
  409. i++;
  410. if (i == size) break;
  411. }
  412. if (i == size) break;
  413. xChange = i;
  414. x = rects[i].x;
  415. while (true) {
  416. if (rects[i] == null) {
  417. i++;
  418. if (i == size) break; // out of rects
  419. continue;
  420. }
  421. if (rlm.rects[j].equals(rects[i])) {
  422. rects[i] = null;
  423. ret = true;
  424. }
  425. i++;
  426. if (i == size) break; // out of rects
  427. if (x != rects[i].x) break; // out of the zone.
  428. }
  429. }
  430. // Now we will go through collapsing the nulled entries.
  431. if (ret) {
  432. int j=0, i=0;
  433. while (i<size) {
  434. if (rects[i] != null)
  435. rects[j++] = rects[i];
  436. i++;
  437. }
  438. size = j;
  439. bounds = null;
  440. }
  441. return ret;
  442. }
  443. public boolean retainAll(Collection c) {
  444. if (c instanceof RectListManager)
  445. return retainAll((RectListManager)c);
  446. return retainAll(new RectListManager(c));
  447. }
  448. public boolean retainAll(RectListManager rlm) {
  449. int x, xChange = 0;
  450. boolean ret = false;
  451. for (int j=0, i=0; j<size; j++) {
  452. i=xChange;
  453. while (rlm.rects[i].x < rects[j].x) {
  454. i++;
  455. if (i == rlm.size) break;
  456. }
  457. if (i == rlm.size) {
  458. ret = true;
  459. // No more rects will match anything from rlm
  460. // so remove them from this RLM.
  461. for (int k=j; k<size; k++)
  462. rects[k] = null;
  463. size = j;
  464. break;
  465. }
  466. xChange = i;
  467. x = rlm.rects[i].x;
  468. while (true) {
  469. if (rects[j].equals(rlm.rects[i])) break;
  470. i++;
  471. if ((i == rlm.size) ||
  472. (x != rlm.rects[i].x)) {
  473. // Out of zone or rects
  474. rects[j] = null;
  475. ret = true;
  476. break;
  477. }
  478. }
  479. }
  480. // Now we will go through collapsing the nulled entries.
  481. if (ret) {
  482. int j=0, i=0;
  483. while (i<size) {
  484. if (rects[i] != null)
  485. rects[j++] = rects[i];
  486. i++;
  487. }
  488. size = j;
  489. bounds = null;
  490. }
  491. return ret;
  492. }
  493. /**
  494. * Adds the contents of <code>rlm</code> to this RectListManager. No
  495. * collapsing of rectangles is done here the contents are simply
  496. * added (you should generally call 'mergeRects' some time after
  497. * this operation before using the contents of this
  498. * RectListManager.
  499. * @param rlm The RectListManager to add the contents of. */
  500. public void add(RectListManager rlm) {
  501. if (rlm.size == 0)
  502. return;
  503. Rectangle [] dst = rects;
  504. if (rects.length < (size+rlm.size)) {
  505. dst = new Rectangle[size+rlm.size];
  506. }
  507. if (size == 0) {
  508. System.arraycopy(rlm.rects, 0, dst, size, rlm.size);
  509. size = rlm.size;
  510. bounds = null;
  511. return;
  512. }
  513. Rectangle [] src1 = rlm.rects;
  514. int src1Sz = rlm.size;
  515. int src1I = src1Sz-1;
  516. Rectangle [] src2 = rects;
  517. int src2Sz = size;
  518. int src2I = src2Sz-1;
  519. int dstI = size+rlm.size-1;
  520. int x1 = src1[src1I].x;
  521. int x2 = src2[src2I].x;
  522. while (dstI >= 0) {
  523. if (x1 <= x2) {
  524. dst[dstI] = src2[src2I];
  525. if (src2I == 0) {
  526. System.arraycopy(src1, 0, dst, 0, src1I+1);
  527. break;
  528. }
  529. src2I--;
  530. x2 = src2[src2I].x;
  531. } else {
  532. dst[dstI] = src1[src1I];
  533. if (src1I == 0) {
  534. System.arraycopy(src2, 0, dst, 0, src2I+1);
  535. break;
  536. }
  537. src1I--;
  538. x1 = src1[src1I].x;
  539. }
  540. dstI--;
  541. }
  542. rects = dst;
  543. size += rlm.size;
  544. bounds = null;
  545. }
  546. public void mergeRects(int overhead, int lineOverhead) {
  547. if (size == 0) return;
  548. Rectangle r, cr;
  549. int cost1, cost2, cost3;
  550. Rectangle []splits = new Rectangle[4];
  551. for (int j, i=0; i<size; i++) {
  552. r = rects[i];
  553. if (r == null) continue;
  554. cost1 = (overhead +
  555. (r.height*lineOverhead) +
  556. (r.height*r.width));
  557. do {
  558. int maxX = r.x+r.width+overhead/r.height;
  559. for (j=i+1; j<size; j++) {
  560. cr = rects[j];
  561. if ((cr == null) || (cr == r)) continue;
  562. if (cr.x >= maxX) {
  563. // No more merges can happen.
  564. j = size;
  565. break;
  566. }
  567. cost2 = (overhead +
  568. (cr.height*lineOverhead) +
  569. (cr.height*cr.width));
  570. Rectangle mr = r.union(cr);
  571. cost3 = (overhead +
  572. (mr.height*lineOverhead) +
  573. (mr.height*mr.width));
  574. if (cost3 <= cost1+cost2) {
  575. r = rects[i] = mr;
  576. rects[j] = null;
  577. cost1 = cost3;
  578. j=-1;
  579. break;
  580. }
  581. if (!r.intersects(cr)) continue;
  582. splitRect(cr, r, splits);
  583. int splitCost=0;
  584. int l=0;
  585. for (int k=0; k<4; k++) {
  586. if (splits[k] != null) {
  587. Rectangle sr = splits[k];
  588. // Collapse null entries in first three
  589. // (That share common 'x').
  590. if (k<3) splits[l++] = sr;
  591. splitCost += (overhead +
  592. (sr.height*lineOverhead) +
  593. (sr.height*sr.width));
  594. }
  595. }
  596. if (splitCost >= cost2) continue;
  597. // Insert the splits.
  598. if (l == 0) {
  599. // only third split may be left (no common 'x').
  600. rects[j] = null;
  601. if (splits[3] != null)
  602. add(splits[3], j, size-1);
  603. continue;
  604. }
  605. rects[j] = splits[0];
  606. if (l > 1)
  607. insertRects(splits, 1, j+1, l-1);
  608. if (splits[3] != null)
  609. add(splits[3], j, size-1);
  610. }
  611. // if we merged it with another rect then
  612. // we need to check all the rects up to i again,
  613. // against the merged rect.
  614. } while (j != size);
  615. }
  616. // Now we will go through collapsing the nulled entries.
  617. int j=0, i=0;
  618. float area=0;
  619. while (i<size) {
  620. if (rects[i] != null) {
  621. r = rects[i];
  622. rects[j++] = r;
  623. area += overhead + (r.height*lineOverhead) +
  624. (r.height*r.width);
  625. }
  626. i++;
  627. }
  628. size = j;
  629. bounds=null;
  630. r = getBounds();
  631. if (r == null) return;
  632. if (overhead + (r.height*lineOverhead) + (r.height*r.width) < area) {
  633. rects[0] = r;
  634. size=1;
  635. }
  636. }
  637. public void subtract(RectListManager rlm, int overhead, int lineOverhead) {
  638. Rectangle r, sr;
  639. int cost;
  640. int jMin=0;
  641. Rectangle [] splits = new Rectangle[4];
  642. for(int i=0; i<size; i++) {
  643. r = rects[i]; // Canidate rect...
  644. cost = (overhead +
  645. (r.height*lineOverhead) +
  646. (r.height*r.width));
  647. for (int j=jMin; j<rlm.size; j++) {
  648. sr = rlm.rects[j]; // subtraction rect.
  649. // Check if the canidate rect starts after
  650. // the end of this rect in 'x' if so
  651. // go to the next one.
  652. if (sr.x+sr.width < r.x) {
  653. // If this was jMin then increment jMin (no
  654. // future canidate rect will intersect this rect).
  655. if (j == jMin) jMin++;
  656. continue;
  657. }
  658. // Check if the rest of the rects from rlm are past
  659. // the end of the canidate rect. If so we are
  660. // done with this canidate rect.
  661. if (sr.x > r.x+r.width)
  662. break;
  663. // If they don't insersect then go to next sub rect.
  664. if (!r.intersects(sr))
  665. continue;
  666. // Now we know they intersect one another lets
  667. // figure out how...
  668. splitRect(r, sr, splits);
  669. int splitCost=0;
  670. Rectangle tmpR;
  671. for (int k=0; k<4; k++) {
  672. tmpR = splits[k];
  673. if (tmpR != null)
  674. splitCost += (overhead +
  675. (tmpR.height*lineOverhead) +
  676. (tmpR.height*tmpR.width));
  677. }
  678. if (splitCost >= cost)
  679. // This isn't ideal as depending on the order
  680. // Stuff is done in we might later kill some of
  681. // these rectangles (hence lowering the cost).
  682. // For this reason it is probably best of the
  683. // subtract list has been merged as this will help
  684. // reduce the instances where this will happen.
  685. continue;
  686. // Collapse null entries in first three elements
  687. // split 0, 1, 2 (entries that share a common 'x').
  688. int l = 0;
  689. for (int k=0; k<3; k++) {
  690. if (splits[k] != null)
  691. splits[l++] = splits[k];
  692. }
  693. // Fully covered (or only split 3 survived which we
  694. // will visit later) this canidate rect goes away.
  695. if (l==0) {
  696. rects[i].width = 0;
  697. // Insert the third split (if any) at the
  698. // proper place in rects list.
  699. if (splits[3] != null)
  700. add(splits[3], i, size-1);
  701. break;
  702. }
  703. // Otherwise replace the canidate with the top of
  704. // the split, since it only shrunk it didn't grow,
  705. // we know that the previous subtract rects don't
  706. // intersect it.
  707. r = splits[0];
  708. rects[i] = r;
  709. cost = (overhead +
  710. (r.height*lineOverhead) +
  711. (r.height*r.width));
  712. // Add the remainder of the rects that
  713. // share 'r.x' (if any). Possible
  714. // are split 1, and split 2.
  715. if (l > 1)
  716. insertRects(splits, 1, i+1, l-1);
  717. // Insert the third split (if any) at the
  718. // proper place in rects list.
  719. if (splits[3] != null)
  720. add(splits[3], i+l, size-1);
  721. }
  722. }
  723. // Now we will go through collapsing the nulled entries.
  724. int j=0, i=0;
  725. while (i<size) {
  726. if (rects[i].width == 0)
  727. rects[i] = null;
  728. else
  729. rects[j++] = rects[i];
  730. i++;
  731. }
  732. size = j;
  733. bounds = null;
  734. }
  735. protected void splitRect(Rectangle r, Rectangle sr,
  736. Rectangle []splits) {
  737. // We split the canidate rectrect into four parts. In
  738. // many cases one or more of these will be empty.
  739. //
  740. // +-------------------------------------+ ry0
  741. // | |
  742. // | |
  743. // | Split 0 |
  744. // | |
  745. // | |
  746. // ------------+-----------------+--------------- sry0
  747. // | | | |
  748. // | Split2 | subtracted | Split 3 |
  749. // | | rect | |
  750. // | | | |
  751. // ------------+-----------------+--------------- sry1
  752. // | srx0 srx1 |
  753. // | |
  754. // | Split 1 |
  755. // | |
  756. // +-------------------------------------+ ry1
  757. // rx0 rx1
  758. int rx0 = r.x;
  759. int rx1 = rx0+r.width-1;
  760. int ry0 = r.y;
  761. int ry1 = ry0+r.height-1;
  762. int srx0 = sr.x;
  763. int srx1 = srx0+sr.width-1;
  764. int sry0 = sr.y;
  765. int sry1 = sry0+sr.height-1;
  766. if ((ry0 < sry0) && (ry1 >= sry0)) {
  767. splits[0] = new Rectangle(rx0, ry0, r.width, sry0-ry0);
  768. ry0 = sry0;
  769. } else {
  770. splits[0] = null;
  771. }
  772. if ((ry0 <= sry1) && (ry1 > sry1)) {
  773. splits[1] = new Rectangle(rx0, sry1+1, r.width, ry1-sry1);
  774. ry1 = sry1;
  775. } else {
  776. splits[1] = null;
  777. }
  778. if ((rx0 < srx0) && (rx1 >= srx0)) {
  779. splits[2] = new Rectangle(rx0, ry0, srx0-rx0, ry1-ry0+1);
  780. } else {
  781. splits[2] = null;
  782. }
  783. if ((rx0 <= srx1) && (rx1 > srx1)) {
  784. splits[3]= new Rectangle(srx1+1, ry0, rx1-srx1, ry1-ry0+1);
  785. } else {
  786. splits[3] = null;
  787. }
  788. }
  789. protected void insertRects(Rectangle[] rects, int srcPos,
  790. int dstPos, int len) {
  791. if (len == 0) return;
  792. // Make sure we have room.
  793. ensureCapacity(size+len);
  794. // Move everything after pos up...
  795. for (int i=size-1; i>=dstPos; i--)
  796. this.rects[i+len] = this.rects[i];
  797. // Put the new rects in.
  798. System.arraycopy( rects, srcPos, this.rects, dstPos, len );
  799. size += len;
  800. }
  801. public void ensureCapacity(int sz) {
  802. if (sz <= rects.length)
  803. return;
  804. int nSz = rects.length + (rects.length>>1) + 1;
  805. while (nSz < sz)
  806. nSz+=(nSz>>1)+1;
  807. Rectangle [] nRects = new Rectangle[nSz];
  808. System.arraycopy(rects, 0, nRects, 0, size);
  809. rects = nRects;
  810. }
  811. /**
  812. * Comparator for ordering rects in X.
  813. *
  814. * Note: this comparator imposes orderings that are inconsistent
  815. * with equals.
  816. */
  817. private static class RectXComparator implements Comparator, Serializable {
  818. RectXComparator() { }
  819. public final int compare(Object o1, Object o2) {
  820. return ((Rectangle)o1).x-((Rectangle)o2).x;
  821. }
  822. }
  823. private class RLMIterator implements ListIterator {
  824. int idx = 0;
  825. boolean removeOk = false;
  826. boolean forward = true;
  827. RLMIterator() { }
  828. public boolean hasNext() { return idx < size; }
  829. public int nextIndex() { return idx; }
  830. public Object next() {
  831. if (idx >= size)
  832. throw new NoSuchElementException("No Next Element");
  833. forward = true;
  834. removeOk = true;
  835. return rects[idx++];
  836. }
  837. public boolean hasPrevious() { return idx > 0; }
  838. public int previousIndex() { return idx-1; }
  839. public Object previous() {
  840. if (idx <= 0)
  841. throw new NoSuchElementException("No Previous Element");
  842. forward = false;
  843. removeOk = true;
  844. return rects[--idx];
  845. }
  846. public void remove() {
  847. if (!removeOk)
  848. throw new IllegalStateException
  849. ("remove can only be called directly after next/previous");
  850. if (forward) idx--;
  851. if (idx != size-1)
  852. System.arraycopy(rects, idx+1, rects, idx, size-(idx+1));
  853. size--;
  854. rects[size] = null;
  855. removeOk = false;
  856. }
  857. public void set(Object o) {
  858. Rectangle r = (Rectangle)o;
  859. if (!removeOk)
  860. throw new IllegalStateException
  861. ("set can only be called directly after next/previous");
  862. if (forward) idx--;
  863. if (idx+1<size) {
  864. if (rects[idx+1].x < r.x)
  865. throw new UnsupportedOperationException
  866. ("RectListManager entries must be sorted");
  867. }
  868. if (idx>=0) {
  869. if (rects[idx-1].x > r.x)
  870. throw new UnsupportedOperationException
  871. ("RectListManager entries must be sorted");
  872. }
  873. rects[idx] = r;
  874. removeOk = false;
  875. }
  876. public void add(Object o) {
  877. Rectangle r = (Rectangle)o;
  878. if (idx<size) {
  879. if (rects[idx].x < r.x)
  880. throw new UnsupportedOperationException
  881. ("RectListManager entries must be sorted");
  882. }
  883. if (idx!=0) {
  884. if (rects[idx-1].x > r.x)
  885. throw new UnsupportedOperationException
  886. ("RectListManager entries must be sorted");
  887. }
  888. ensureCapacity(size+1);
  889. if (idx != size)
  890. System.arraycopy(rects, idx, rects, idx+1, size-idx);
  891. rects[idx] = r;
  892. idx++;
  893. removeOk = false;
  894. }
  895. }
  896. }