001: /*
002: * @(#)RegionImpl.java 1.13 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: package sun.porting.utils;
028:
029: import sun.porting.graphicssystem.Region;
030: import java.util.Enumeration;
031:
032: /**
033: * Region manipulation code. This code attempts to avoid using full-fledged
034: * Y-X bands if one or both of the regions being manipulated are single
035: * rectangles.
036: *
037: * @version 1.9, 08/19/02
038: * @author Richard Berlin
039: */
040: public class RegionImpl extends YXBandList implements Region {
041: // static {
042: // Coverage.cover(10, "(case deleted)");
043: // }
044:
045: /*
046: * To avoid Y-X bands when possible, and to help speed up overlap
047: * testing, we maintain the bounding box of the region.
048: */
049: protected Rectangle boundingBox;
050:
051: public RegionImpl() {
052: // // Coverage.cover(1, "Default Constructor Region()");
053: boundingBox = new Rectangle(0, 0, 0, 0);
054: }
055:
056: public RegionImpl(int x, int y, int w, int h) {
057: // // Coverage.cover(2, "Constructor Region(x,y,w,h)");
058: boundingBox = new Rectangle(x, y, w, h);
059: }
060:
061: // deep copy of a Region
062: public Region copy() {
063: // // Coverage.cover(3, "Region copy()");
064: RegionImpl ret = new RegionImpl(boundingBox.x, boundingBox.y,
065: boundingBox.width, boundingBox.height);
066: if (bandList != null) {
067: // // Coverage.cover(4, "bandList != null");
068: ret.copyBands(this );
069: }
070: return ret;
071: }
072:
073: public java.awt.Rectangle getBounds() {
074: if (bandList == null) {
075: return new Rectangle(boundingBox);
076: } else {
077: return super .getBounds();
078: }
079: }
080:
081: public boolean equals(Region reg) {
082: RegionImpl r = (RegionImpl) reg;
083: if (!boundingBox.equals(r.boundingBox)) {
084: return false;
085: }
086: if ((bandList == null) && (r.bandList == null)) {
087: return true;
088: }
089: if (bandList == null) {
090: YXBand first = r.bandList.next;
091: YXBand last = r.bandList.prev;
092: // Implies also that first == last
093: return first.children.next == last.children.prev;
094: }
095: if (r.bandList == null) {
096: YXBand first = bandList.next;
097: YXBand last = bandList.prev;
098: // Implies also that first == last
099: return first.children.next == last.children.prev;
100: }
101: return super .equals(r);
102: }
103:
104: // simple overlap tests on bounding boxes, hence only tells us
105: // whether regions *may* intersect
106: public boolean mayIntersect(Region r) {
107: // // Coverage.cover(5, "mayIntersect(Region)");
108: return (r != null)
109: && boundingBox.intersects(((RegionImpl) r).boundingBox);
110: }
111:
112: // simple overlap tests on bounding boxes, hence only tells us
113: // whether regions *may* intersect
114: public boolean mayIntersect(java.awt.Rectangle r) {
115: // // Coverage.cover(6, "mayIntersect(Rectangle)");
116: return (r != null) && boundingBox.intersects(r);
117: }
118:
119: // simple overlap tests on bounding boxes, hence only tells us
120: // whether regions *may* intersect
121: public boolean mayIntersect(int x, int y, int w, int h) {
122: // // Coverage.cover(7, "mayIntersect(x,y,w,h)");
123: return boundingBox.intersects(x, y, w, h);
124: }
125:
126: public boolean isRectangle() {
127: if (bandList == null) {
128: return true;
129: }
130: return super .isRectangle();
131: }
132:
133: public void defragment(boolean isClip) {
134: if (bandList == null) {
135: if (isClip) {
136: // force a band list to be created.
137: init(boundingBox.x, boundingBox.y, boundingBox.width,
138: boundingBox.height);
139: // now make sure it's legal
140: if (bandList.next == bandList) {
141: bandList = null;
142: }
143: }
144: } else {
145: super .deFragment();
146: }
147: }
148:
149: // destructively union two regions
150: public void union(Region reg) {
151: RegionImpl r = (RegionImpl) reg;
152: if (r.isEmpty()) {
153: // Coverage.cover(1, "union with empty region");
154: return;
155: } else if (r.bandList == null) {
156: // Coverage.cover(2, "union with region that has null bandlist");
157: union(r.boundingBox);
158: return;
159: }
160: if (bandList == null) {
161: if (boundingBox.contains(r.boundingBox)) {
162: // Coverage.cover(9, "region is rectangle which subsumes r");
163: return;
164: }
165: // Coverage.cover(3, "initialize bandList");
166: super .init(boundingBox.x, boundingBox.y, boundingBox.width,
167: boundingBox.height);
168: }
169: boundingBox.add(r.boundingBox);
170: super .union(r.bandList);
171: }
172:
173: public void union(int x, int y, int w, int h) {
174: if ((w <= 0) || (h <= 0)) {
175: // Coverage.cover(4, "union with empty area");
176: return;
177: }
178: union(new Rectangle(x, y, w, h));
179: }
180:
181: // destructively union a rectangle with a region
182: public void union(java.awt.Rectangle r) {
183: if (r.isEmpty()) {
184: // Coverage.cover(5, "union with empty rectangle");
185: return;
186: } else if (boundingBox.isEmpty()) {
187: boundingBox = new Rectangle(r);
188: return;
189: }
190: if (r.contains(boundingBox.x, boundingBox.y)
191: && r.contains(boundingBox.x + boundingBox.width,
192: boundingBox.y + boundingBox.height)) {
193: // Coverage.cover(6, "union with rectangle that subsumes all");
194: bandList = null;
195: if (r instanceof Rectangle) {
196: boundingBox = (Rectangle) r;
197: } else {
198: boundingBox = new Rectangle(r);
199: }
200: return;
201: }
202: if (bandList == null) {
203: if (boundingBox.contains(r)) { // r inside boundingBox
204: // Coverage.cover(7, "region is rectangle which subsumes r");
205: return;
206: }
207: // Coverage.cover(8, "initialize bandList");
208: super .init(boundingBox.x, boundingBox.y, boundingBox.width,
209: boundingBox.height);
210: }
211: boundingBox.add(r);
212: super .union(r.x, r.y, r.width, r.height);
213: }
214:
215: // destructively subtract two regions
216: public void subtract(Region reg) {
217: RegionImpl r = (RegionImpl) reg;
218: // // Coverage.cover(8, "subtract(Region)");
219: if (boundingBox.isEmpty() || (r == null)
220: || r.boundingBox.isEmpty()
221: || !boundingBox.intersects(r.boundingBox)) {
222: // // Coverage.cover(9, "empty or nonintersecting bounding box");
223: return;
224: }
225: if (bandList == null) {
226: // // Coverage.cover(10, "bandList == null");
227: super .init(boundingBox.x, boundingBox.y, boundingBox.width,
228: boundingBox.height);
229: }
230: if (r.bandList == null) {
231: // // Coverage.cover(11, "r.bandList == null");
232: super .subtract(r.boundingBox.x, r.boundingBox.y,
233: r.boundingBox.width, r.boundingBox.height);
234: } else {
235: // // Coverage.cover(12, "subtract band lists");
236: super .subtract(r.bandList);
237: }
238: boundingBox = (Rectangle) getBounds();
239: if ((boundingBox.width | boundingBox.height) == 0) {
240: // // Coverage.cover(13, "result has empty bounding box");
241: bandList = null;
242: }
243: }
244:
245: public void subtract(java.awt.Rectangle r) {
246: subtract(r.x, r.y, r.width, r.height);
247: }
248:
249: // destructively subtract a rectangle from a region
250: public void subtract(int x, int y, int w, int h) {
251: // // Coverage.cover(14, "subtract(x,y,w,h)");
252: if (((w <= 0) || (h <= 0))
253: || !boundingBox.intersects(x, y, w, h)) {
254: // // Coverage.cover(15, "Null size or no intersection");
255: return;
256: }
257: boundingBox.subtract(x, y, w, h);
258: if ((boundingBox.width | boundingBox.height) == 0) {
259: // // Coverage.cover(16, "Bounding box subtraction yields empty rectangle");
260: bandList = null;
261: return;
262: }
263: if (bandList == null) {
264: // // Coverage.cover(17, "bandList == null");
265: super .init(boundingBox.x, boundingBox.y, boundingBox.width,
266: boundingBox.height);
267: }
268: super .subtract(x, y, w, h);
269: boundingBox = (Rectangle) getBounds();
270: if ((boundingBox.width | boundingBox.height) == 0) {
271: // // Coverage.cover(18, "boundingBox is empty");
272: bandList = null;
273: }
274: }
275:
276: // destructively intersect two regions
277: public void intersect(Region reg) {
278: RegionImpl r = (RegionImpl) reg;
279: // // Coverage.cover(19, "intersect(Region)");
280: if (boundingBox.isEmpty() || (r == null)
281: || r.boundingBox.isEmpty()
282: || !boundingBox.intersects(r.boundingBox)) {
283: // // Coverage.cover(20, "empty or nonintersecting bounding box");
284: setEmpty();
285: return;
286: }
287: if (bandList == null) {
288: if (r.bandList == null) {
289: // // Coverage.cover(21, "Both band lists empty");
290: boundingBox.intersect(r.boundingBox);
291: } else {
292: // // Coverage.cover(22, "bandList empty");
293: super .init(boundingBox.x, boundingBox.y,
294: boundingBox.width, boundingBox.height);
295: int x1 = Math.max(boundingBox.x, r.boundingBox.x);
296: int x2 = Math.min(boundingBox.x + boundingBox.width,
297: r.boundingBox.x + r.boundingBox.width);
298: super .intersect(r.bandList, x1, x2);
299: boundingBox = (Rectangle) getBounds();
300: }
301: } else {
302: if (r.bandList == null) {
303: // // Coverage.cover(23, "r.bandList empty");
304: super .intersect(r.boundingBox.x, r.boundingBox.y,
305: r.boundingBox.width, r.boundingBox.height);
306: } else {
307: // // Coverage.cover(24, "intersecting 2 band lists");
308: int x1 = Math.max(boundingBox.x, r.boundingBox.x);
309: int x2 = Math.min(boundingBox.x + boundingBox.width,
310: r.boundingBox.x + r.boundingBox.width);
311: super .intersect(r.bandList, x1, x2);
312: }
313: boundingBox = (Rectangle) getBounds();
314: }
315: if ((boundingBox.width | boundingBox.height) == 0) {
316: // // Coverage.cover(25, "bounding box empty");
317: bandList = null;
318: }
319: }
320:
321: public void intersect(java.awt.Rectangle r) {
322: intersect(r.x, r.y, r.width, r.height);
323: }
324:
325: // destructively intersect a rectangle with a region
326: public void intersect(int x, int y, int w, int h) {
327: // // Coverage.cover(26, "intersect(x,y,w,h)");
328: if (((w <= 0) || (h <= 0))
329: || !boundingBox.intersects(x, y, w, h)) {
330: // // Coverage.cover(27, "Null size or no intersection");
331: setEmpty();
332: return;
333: }
334: if (bandList != null) {
335: // // Coverage.cover(28, "intersect with a band list");
336: super .intersect(x, y, w, h);
337: boundingBox = (Rectangle) getBounds();
338: } else {
339: // // Coverage.cover(29, "intersect bounding boxes");
340: boundingBox.intersect(x, y, w, h);
341: }
342: if ((boundingBox.width | boundingBox.height) == 0) {
343: // // Coverage.cover(30, "bounding box empty");
344: bandList = null;
345: }
346: }
347:
348: // return true if the point is in the region
349: public boolean contains(int x, int y) {
350: // // Coverage.cover(31, "contains(x,y)");
351: if (boundingBox.contains(x, y, 1, 1)) {
352: // // Coverage.cover(32, "bounding box check");
353: if (bandList == null) {
354: // // Coverage.cover(33, "null bandList");
355: return true; // region is rectangular
356: } else {
357: // // Coverage.cover(34, "checking band list");
358: return super .contains(x, y, 1, 1);
359: }
360: }
361: return false;
362: }
363:
364: // return true if the rectangle is in the region
365: public boolean contains(int x, int y, int w, int h) {
366: // // Coverage.cover(35, "contains(x,y,w,h)");
367: if (boundingBox.contains(x, y, w, h)) {
368: // // Coverage.cover(36, "bounding box check");
369: if (bandList == null) {
370: // // Coverage.cover(37, "null bandList");
371: return true;
372: } else {
373: // // Coverage.cover(38, "checking band list");
374: return super .contains(x, y, w, h);
375: }
376: }
377: return false;
378: }
379:
380: // translate the region by dx,dy
381: public void translate(int dx, int dy) {
382: // // Coverage.cover(39, "translate(dx,dy)");
383: boundingBox.translate(dx, dy);
384: if ((bandList != null) && ((dx | dy) != 0)) {
385: // // Coverage.cover(40, "translating bands");
386: super .translate(dx, dy);
387: }
388: }
389:
390: public void setEmpty() {
391: // // Coverage.cover(41, "setEmpty()");
392: boundingBox.width = 0;
393: boundingBox.height = 0;
394: bandList = null;
395: }
396:
397: public boolean isEmpty() {
398: // // Coverage.cover(42, "isEmpty()");
399: return ((boundingBox.width | boundingBox.height) == 0);
400: }
401:
402: // We don't want test coverage
403: public String toString() {
404: if (bandList == null) {
405: if (boundingBox.isEmpty()) {
406: return "[Region: (empty)]";
407: } else {
408: return boundingBox.toString();
409: }
410: } else {
411: return ("[Region: " + super .toString() + "]");
412: }
413: }
414:
415: public Enumeration getRectangles() {
416: return new RectangleEnumerator(this );
417: }
418: }
419:
420: class RectangleEnumerator implements Enumeration {
421: YXBand yPtr, yHead;
422: XSpan xPtr, xHead;
423: java.awt.Rectangle bbox;
424:
425: RectangleEnumerator(Region r) {
426: yHead = ((RegionImpl) r).bandList;
427: if (yHead == null) {
428: bbox = r.getBounds();
429: } else {
430: yPtr = yHead.next;
431: xHead = yPtr.children;
432: xPtr = xHead;
433: }
434: }
435:
436: public boolean hasMoreElements() {
437: if (yHead == null) {
438: return (bbox != null);
439: } else {
440: return (yPtr.next != yHead) || (xPtr.next != xHead);
441: }
442: }
443:
444: public Object nextElement() {
445: if (yHead == null) {
446: java.awt.Rectangle r = bbox;
447: bbox = null;
448: return r;
449: }
450: xPtr = xPtr.next;
451: if (xPtr == xHead) {
452: yPtr = yPtr.next;
453: if (yPtr == yHead) {
454: return null;
455: }
456: xHead = yPtr.children;
457: xPtr = xHead.next;
458: }
459: return new Rectangle(xPtr.x, yPtr.y, xPtr.w, yPtr.h);
460: }
461: }
|