/* * @(#)RegionImpl.java 1.13 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ package sun.porting.utils; import sun.porting.graphicssystem.Region; import java.util.Enumeration; /** * Region manipulation code. This code attempts to avoid using full-fledged * Y-X bands if one or both of the regions being manipulated are single * rectangles. * * @version 1.9, 08/19/02 * @author Richard Berlin */ public class RegionImpl extends YXBandList implements Region { // static { // Coverage.cover(10, "(case deleted)"); // } /* * To avoid Y-X bands when possible, and to help speed up overlap * testing, we maintain the bounding box of the region. */ protected Rectangle boundingBox; public RegionImpl() { // // Coverage.cover(1, "Default Constructor Region()"); boundingBox = new Rectangle(0, 0, 0, 0); } public RegionImpl(int x, int y, int w, int h) { // // Coverage.cover(2, "Constructor Region(x,y,w,h)"); boundingBox = new Rectangle(x, y, w, h); } // deep copy of a Region public Region copy() { // // Coverage.cover(3, "Region copy()"); RegionImpl ret = new RegionImpl(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); if (bandList != null) { // // Coverage.cover(4, "bandList != null"); ret.copyBands(this); } return ret; } public java.awt.Rectangle getBounds() { if (bandList == null) { return new Rectangle(boundingBox); } else { return super.getBounds(); } } public boolean equals(Region reg) { RegionImpl r = (RegionImpl) reg; if (!boundingBox.equals(r.boundingBox)) { return false; } if ((bandList == null) && (r.bandList == null)) { return true; } if (bandList == null) { YXBand first = r.bandList.next; YXBand last = r.bandList.prev; // Implies also that first == last return first.children.next == last.children.prev; } if (r.bandList == null) { YXBand first = bandList.next; YXBand last = bandList.prev; // Implies also that first == last return first.children.next == last.children.prev; } return super.equals(r); } // simple overlap tests on bounding boxes, hence only tells us // whether regions *may* intersect public boolean mayIntersect(Region r) { // // Coverage.cover(5, "mayIntersect(Region)"); return (r != null) && boundingBox.intersects(((RegionImpl) r).boundingBox); } // simple overlap tests on bounding boxes, hence only tells us // whether regions *may* intersect public boolean mayIntersect(java.awt.Rectangle r) { // // Coverage.cover(6, "mayIntersect(Rectangle)"); return (r != null) && boundingBox.intersects(r); } // simple overlap tests on bounding boxes, hence only tells us // whether regions *may* intersect public boolean mayIntersect(int x, int y, int w, int h) { // // Coverage.cover(7, "mayIntersect(x,y,w,h)"); return boundingBox.intersects(x, y, w, h); } public boolean isRectangle() { if (bandList == null) { return true; } return super.isRectangle(); } public void defragment(boolean isClip) { if (bandList == null) { if (isClip) { // force a band list to be created. init(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); // now make sure it's legal if (bandList.next == bandList) { bandList = null; } } } else { super.deFragment(); } } // destructively union two regions public void union(Region reg) { RegionImpl r = (RegionImpl) reg; if (r.isEmpty()) { // Coverage.cover(1, "union with empty region"); return; } else if (r.bandList == null) { // Coverage.cover(2, "union with region that has null bandlist"); union(r.boundingBox); return; } if (bandList == null) { if (boundingBox.contains(r.boundingBox)) { // Coverage.cover(9, "region is rectangle which subsumes r"); return; } // Coverage.cover(3, "initialize bandList"); super.init(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); } boundingBox.add(r.boundingBox); super.union(r.bandList); } public void union(int x, int y, int w, int h) { if ((w <= 0) || (h <= 0)) { // Coverage.cover(4, "union with empty area"); return; } union(new Rectangle(x, y, w, h)); } // destructively union a rectangle with a region public void union(java.awt.Rectangle r) { if (r.isEmpty()) { // Coverage.cover(5, "union with empty rectangle"); return; } else if (boundingBox.isEmpty()) { boundingBox = new Rectangle(r); return; } if (r.contains(boundingBox.x, boundingBox.y) && r.contains(boundingBox.x + boundingBox.width, boundingBox.y + boundingBox.height)) { // Coverage.cover(6, "union with rectangle that subsumes all"); bandList = null; if (r instanceof Rectangle) { boundingBox = (Rectangle) r; } else { boundingBox = new Rectangle(r); } return; } if (bandList == null) { if (boundingBox.contains(r)) { // r inside boundingBox // Coverage.cover(7, "region is rectangle which subsumes r"); return; } // Coverage.cover(8, "initialize bandList"); super.init(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); } boundingBox.add(r); super.union(r.x, r.y, r.width, r.height); } // destructively subtract two regions public void subtract(Region reg) { RegionImpl r = (RegionImpl) reg; // // Coverage.cover(8, "subtract(Region)"); if (boundingBox.isEmpty() || (r == null) || r.boundingBox.isEmpty() || !boundingBox.intersects(r.boundingBox)) { // // Coverage.cover(9, "empty or nonintersecting bounding box"); return; } if (bandList == null) { // // Coverage.cover(10, "bandList == null"); super.init(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); } if (r.bandList == null) { // // Coverage.cover(11, "r.bandList == null"); super.subtract(r.boundingBox.x, r.boundingBox.y, r.boundingBox.width, r.boundingBox.height); } else { // // Coverage.cover(12, "subtract band lists"); super.subtract(r.bandList); } boundingBox = (Rectangle) getBounds(); if ((boundingBox.width | boundingBox.height) == 0) { // // Coverage.cover(13, "result has empty bounding box"); bandList = null; } } public void subtract(java.awt.Rectangle r) { subtract(r.x, r.y, r.width, r.height); } // destructively subtract a rectangle from a region public void subtract(int x, int y, int w, int h) { // // Coverage.cover(14, "subtract(x,y,w,h)"); if (((w <= 0) || (h <= 0)) || !boundingBox.intersects(x, y, w, h)) { // // Coverage.cover(15, "Null size or no intersection"); return; } boundingBox.subtract(x, y, w, h); if ((boundingBox.width | boundingBox.height) == 0) { // // Coverage.cover(16, "Bounding box subtraction yields empty rectangle"); bandList = null; return; } if (bandList == null) { // // Coverage.cover(17, "bandList == null"); super.init(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); } super.subtract(x, y, w, h); boundingBox = (Rectangle) getBounds(); if ((boundingBox.width | boundingBox.height) == 0) { // // Coverage.cover(18, "boundingBox is empty"); bandList = null; } } // destructively intersect two regions public void intersect(Region reg) { RegionImpl r = (RegionImpl) reg; // // Coverage.cover(19, "intersect(Region)"); if (boundingBox.isEmpty() || (r == null) || r.boundingBox.isEmpty() || !boundingBox.intersects(r.boundingBox)) { // // Coverage.cover(20, "empty or nonintersecting bounding box"); setEmpty(); return; } if (bandList == null) { if (r.bandList == null) { // // Coverage.cover(21, "Both band lists empty"); boundingBox.intersect(r.boundingBox); } else { // // Coverage.cover(22, "bandList empty"); super.init(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); int x1 = Math.max(boundingBox.x, r.boundingBox.x); int x2 = Math.min(boundingBox.x + boundingBox.width, r.boundingBox.x + r.boundingBox.width); super.intersect(r.bandList, x1, x2); boundingBox = (Rectangle) getBounds(); } } else { if (r.bandList == null) { // // Coverage.cover(23, "r.bandList empty"); super.intersect(r.boundingBox.x, r.boundingBox.y, r.boundingBox.width, r.boundingBox.height); } else { // // Coverage.cover(24, "intersecting 2 band lists"); int x1 = Math.max(boundingBox.x, r.boundingBox.x); int x2 = Math.min(boundingBox.x + boundingBox.width, r.boundingBox.x + r.boundingBox.width); super.intersect(r.bandList, x1, x2); } boundingBox = (Rectangle) getBounds(); } if ((boundingBox.width | boundingBox.height) == 0) { // // Coverage.cover(25, "bounding box empty"); bandList = null; } } public void intersect(java.awt.Rectangle r) { intersect(r.x, r.y, r.width, r.height); } // destructively intersect a rectangle with a region public void intersect(int x, int y, int w, int h) { // // Coverage.cover(26, "intersect(x,y,w,h)"); if (((w <= 0) || (h <= 0)) || !boundingBox.intersects(x, y, w, h)) { // // Coverage.cover(27, "Null size or no intersection"); setEmpty(); return; } if (bandList != null) { // // Coverage.cover(28, "intersect with a band list"); super.intersect(x, y, w, h); boundingBox = (Rectangle) getBounds(); } else { // // Coverage.cover(29, "intersect bounding boxes"); boundingBox.intersect(x, y, w, h); } if ((boundingBox.width | boundingBox.height) == 0) { // // Coverage.cover(30, "bounding box empty"); bandList = null; } } // return true if the point is in the region public boolean contains(int x, int y) { // // Coverage.cover(31, "contains(x,y)"); if (boundingBox.contains(x, y, 1, 1)) { // // Coverage.cover(32, "bounding box check"); if (bandList == null) { // // Coverage.cover(33, "null bandList"); return true; // region is rectangular } else { // // Coverage.cover(34, "checking band list"); return super.contains(x, y, 1, 1); } } return false; } // return true if the rectangle is in the region public boolean contains(int x, int y, int w, int h) { // // Coverage.cover(35, "contains(x,y,w,h)"); if (boundingBox.contains(x, y, w, h)) { // // Coverage.cover(36, "bounding box check"); if (bandList == null) { // // Coverage.cover(37, "null bandList"); return true; } else { // // Coverage.cover(38, "checking band list"); return super.contains(x, y, w, h); } } return false; } // translate the region by dx,dy public void translate(int dx, int dy) { // // Coverage.cover(39, "translate(dx,dy)"); boundingBox.translate(dx, dy); if ((bandList != null) && ((dx | dy) != 0)) { // // Coverage.cover(40, "translating bands"); super.translate(dx, dy); } } public void setEmpty() { // // Coverage.cover(41, "setEmpty()"); boundingBox.width = 0; boundingBox.height = 0; bandList = null; } public boolean isEmpty() { // // Coverage.cover(42, "isEmpty()"); return ((boundingBox.width | boundingBox.height) == 0); } // We don't want test coverage public String toString() { if (bandList == null) { if (boundingBox.isEmpty()) { return "[Region: (empty)]"; } else { return boundingBox.toString(); } } else { return ("[Region: " + super.toString() + "]"); } } public Enumeration getRectangles() { return new RectangleEnumerator(this); } } class RectangleEnumerator implements Enumeration { YXBand yPtr, yHead; XSpan xPtr, xHead; java.awt.Rectangle bbox; RectangleEnumerator(Region r) { yHead = ((RegionImpl) r).bandList; if (yHead == null) { bbox = r.getBounds(); } else { yPtr = yHead.next; xHead = yPtr.children; xPtr = xHead; } } public boolean hasMoreElements() { if (yHead == null) { return (bbox != null); } else { return (yPtr.next != yHead) || (xPtr.next != xHead); } } public Object nextElement() { if (yHead == null) { java.awt.Rectangle r = bbox; bbox = null; return r; } xPtr = xPtr.next; if (xPtr == xHead) { yPtr = yPtr.next; if (yPtr == yHead) { return null; } xHead = yPtr.children; xPtr = xHead.next; } return new Rectangle(xPtr.x, yPtr.y, xPtr.w, yPtr.h); } }