001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visual.router;
042:
043: import org.netbeans.api.visual.anchor.Anchor;
044:
045: import java.awt.*;
046: import java.util.ArrayList;
047: import java.util.List;
048:
049: /**
050: * @author David Kaspar
051: */
052: final class OrthogonalSearchRouterRegion extends Rectangle {
053:
054: public static final int MIN_INT_REGION = -20000;
055: public static final int MAX_INT_REGION = 20000;
056:
057: // private OrthogonalLinkRouterRegion parent;
058: private Anchor.Direction direction;
059: private boolean horizontal;
060: private int depth;
061:
062: public OrthogonalSearchRouterRegion(
063: /*OrthogonalLinkRouterRegion parentRegion, */int x, int y,
064: int width, int height, Anchor.Direction direction, int depth) {
065: super (x, y, width, height);
066: // this.parent = parentRegion;
067: this .direction = direction;
068: switch (direction) {
069: case LEFT:
070: case RIGHT:
071: horizontal = true;
072: break;
073: case TOP:
074: case BOTTOM:
075: horizontal = false;
076: break;
077: default:
078: throw new IllegalArgumentException();
079: }
080: this .depth = depth;
081: }
082:
083: public Anchor.Direction getDirection() {
084: return direction;
085: }
086:
087: public boolean isHorizontal() {
088: return horizontal;
089: }
090:
091: public int getDepth() {
092: return depth;
093: }
094:
095: public void extendToInfinity() {
096: switch (direction) {
097: case LEFT:
098: width = x - MIN_INT_REGION;
099: x = MIN_INT_REGION;
100: break;
101: case RIGHT:
102: width = MAX_INT_REGION - x;
103: break;
104: case TOP:
105: height = y - MIN_INT_REGION;
106: y = MIN_INT_REGION;
107: break;
108: case BOTTOM:
109: height = MAX_INT_REGION - y;
110: break;
111: default:
112: throw new IllegalArgumentException();
113: }
114: }
115:
116: public int compareImportant(Rectangle collisionToCheck,
117: Rectangle currentMostImportant) {
118: // return: <0 if important, 0 if the same, >0 if not important
119: if (!intersectsZero(collisionToCheck))
120: return Integer.MAX_VALUE;
121: if (currentMostImportant == null)
122: return Integer.MIN_VALUE;
123: switch (direction) {
124: case LEFT:
125: return (currentMostImportant.x + currentMostImportant.width)
126: - (collisionToCheck.x + collisionToCheck.width);
127: case RIGHT:
128: return collisionToCheck.x - currentMostImportant.x;
129: case TOP:
130: return (currentMostImportant.y + currentMostImportant.height)
131: - (collisionToCheck.y + collisionToCheck.height);
132: case BOTTOM:
133: return collisionToCheck.y - currentMostImportant.y;
134: default:
135: throw new IllegalArgumentException();
136: }
137: }
138:
139: private boolean intersectsZero(Rectangle r) {
140: int tx = this .x;
141: int ty = this .y;
142: int rx = r.x;
143: int ry = r.y;
144: int tw = this .width + tx;
145: int th = this .height + ty;
146: int rw = r.width + rx;
147: int rh = r.height + ry;
148: return rw > tx && rh > ty && tw > rx && th > ry;
149: }
150:
151: // TODO - optimize
152: private void parseIntervalsBy(
153: ArrayList<OrthogonalSearchRouterRegion> intervals,
154: Rectangle collision) {
155: int colStart;
156: int colEnd;
157:
158: if (horizontal) {
159: colStart = collision.y;
160: colEnd = collision.y + collision.height;
161: } else {
162: colStart = collision.x;
163: colEnd = collision.x + collision.width;
164: }
165:
166: for (int i = 0; i < intervals.size();) {
167: OrthogonalSearchRouterRegion region = intervals.get(i);
168: int regStart;
169: int regEnd;
170: if (horizontal) {
171: regStart = region.y;
172: regEnd = region.y + region.height;
173: } else {
174: regStart = region.x;
175: regEnd = region.x + region.width;
176: }
177:
178: if (colEnd <= regStart || colStart >= regEnd) {
179: // outside
180: i++;
181: continue;
182: }
183: if (colStart <= regStart && colEnd >= regEnd) {
184: // fully contained
185: intervals.remove(i);
186: continue;
187: }
188: if (colStart > regStart && colEnd < regEnd) {
189: // split to two
190: OrthogonalSearchRouterRegion clonedRegion = region
191: .cloneExactly();
192: int len1 = colStart - regStart;
193: int len2 = regEnd - colEnd;
194: if (horizontal) {
195: region.height = len1;
196: clonedRegion.y = regEnd - len2;
197: clonedRegion.height = len2;
198: intervals.add(i + 1, clonedRegion);
199: } else {
200: region.width = len1;
201: clonedRegion.x = regEnd - len2;
202: clonedRegion.width = len2;
203: intervals.add(i + 1, clonedRegion);
204: }
205: return;
206: }
207: if (colStart <= regStart && colEnd > regStart
208: && colEnd < regEnd) {
209: // cut region start
210: int difference = colEnd - regStart;
211: if (horizontal) {
212: region.y += difference;
213: region.height -= difference;
214: } else {
215: region.x += difference;
216: region.width -= difference;
217: }
218: i++;
219: continue;
220: }
221: if (colEnd >= regEnd && colStart > regStart
222: && colStart < regEnd) {
223: // cut region end
224: int difference = regEnd - colStart;
225: if (horizontal) {
226: region.height -= difference;
227: } else {
228: region.width -= difference;
229: }
230: i++;
231: continue;
232: }
233: throw new IllegalStateException();
234: }
235: }
236:
237: public OrthogonalSearchRouterRegion cloneExactly() {
238: return new OrthogonalSearchRouterRegion(/*parent, */x, y,
239: width, height, direction, depth);
240: }
241:
242: public ArrayList<OrthogonalSearchRouterRegion> parseSubRegions(
243: List<Rectangle> collisions) {
244: ArrayList<Rectangle> importantCollisions = new ArrayList<Rectangle>();
245:
246: Rectangle importantCollision = null;
247: for (Rectangle collision : collisions) {
248: int howMuch = compareImportant(collision,
249: importantCollision);
250: if (howMuch <= 0) {
251: if (howMuch < 0) {
252: importantCollisions.clear();
253: importantCollision = collision;
254: }
255: importantCollisions.add(collision);
256: }
257: }
258:
259: ArrayList<OrthogonalSearchRouterRegion> subRegions = new ArrayList<OrthogonalSearchRouterRegion>();
260: if (importantCollisions.size() > 0) {
261: cutLengthBy(importantCollision);
262: subRegions.add(cloneWithForwardEdge());
263: for (Rectangle collision : importantCollisions)
264: parseIntervalsBy(subRegions, collision);
265: }
266: return subRegions;
267: }
268:
269: public OrthogonalSearchRouterRegion cloneWithForwardEdge() {
270: return cloneWithEdge(/*parent, */direction, depth);
271: }
272:
273: public OrthogonalSearchRouterRegion cloneWithCounterClockwiseEdge() {
274: return cloneWithEdge(
275: /*this, */getCounterClockWiseDirection(direction),
276: depth + 1);
277: }
278:
279: public OrthogonalSearchRouterRegion cloneWithClockwiseEdge() {
280: return cloneWithEdge(
281: /*this, */getClockWiseDirection(direction), depth + 1);
282: }
283:
284: private OrthogonalSearchRouterRegion cloneWithEdge(
285: /*OrthogonalLinkRouterRegion parent, */Anchor.Direction dir,
286: int depth) {
287: switch (dir) {
288: case LEFT:
289: return new OrthogonalSearchRouterRegion(/*parent, */x, y,
290: 0, height, dir, depth);
291: case RIGHT:
292: return new OrthogonalSearchRouterRegion(/*parent, */x
293: + width, y, 0, height, dir, depth);
294: case TOP:
295: return new OrthogonalSearchRouterRegion(/*parent, */x, y,
296: width, 0, dir, depth);
297: case BOTTOM:
298: return new OrthogonalSearchRouterRegion(/*parent, */x, y
299: + height, width, 0, dir, depth);
300: default:
301: throw new IllegalArgumentException();
302: }
303: }
304:
305: private void cutLengthBy(Rectangle collision) {
306: switch (direction) {
307: case LEFT: {
308: int toBeMin = collision.x + collision.width;
309: int currently = x;
310: if (toBeMin > x + width) {
311: x += width;
312: width = 0;
313: } else if (toBeMin > currently) {
314: width = x + width - toBeMin;
315: x = toBeMin;
316: }
317: }
318: break;
319: case RIGHT: {
320: int toBeMax = collision.x;
321: int currently = x + width;
322: if (toBeMax < x) {
323: width = 0;
324: } else if (toBeMax < currently) {
325: width = toBeMax - x;
326: }
327: }
328: break;
329: case TOP: {
330: int toBeMin = collision.y + collision.height;
331: int currently = y;
332: if (toBeMin > y + height) {
333: y += height;
334: height = 0;
335: } else if (toBeMin > currently) {
336: height = y + height - toBeMin;
337: y = toBeMin;
338: }
339: }
340: break;
341: case BOTTOM: {
342: int toBeMax = collision.y;
343: int currently = y + height;
344: if (toBeMax < y) {
345: height = 0;
346: } else if (toBeMax < currently) {
347: height = toBeMax - y;
348: }
349: }
350: break;
351: default:
352: throw new IllegalArgumentException();
353: }
354: }
355:
356: public int getLength() {
357: return horizontal ? width : height;
358: }
359:
360: public int getDistance(Point point) {
361: return horizontal ? Math.abs(point.y - y) : Math.abs(point.x
362: - x);
363: }
364:
365: public boolean containsInsideEdges(Point point) {
366: return point.x >= x && point.x <= x + width && point.y >= y
367: && point.y <= y + height;
368: }
369:
370: public String toString() {
371: return "pos: " + x + "," + y + " size: " + width + "," + height
372: + " dir: " + direction + " depth: " + depth;
373: }
374:
375: public static Anchor.Direction getCounterClockWiseDirection(
376: Anchor.Direction direction) {
377: switch (direction) {
378: case LEFT:
379: return Anchor.Direction.BOTTOM;
380: case RIGHT:
381: return Anchor.Direction.TOP;
382: case TOP:
383: return Anchor.Direction.LEFT;
384: case BOTTOM:
385: return Anchor.Direction.RIGHT;
386: default:
387: throw new IllegalArgumentException();
388: }
389: }
390:
391: public static Anchor.Direction getClockWiseDirection(
392: Anchor.Direction direction) {
393: switch (direction) {
394: case LEFT:
395: return Anchor.Direction.TOP;
396: case RIGHT:
397: return Anchor.Direction.BOTTOM;
398: case TOP:
399: return Anchor.Direction.RIGHT;
400: case BOTTOM:
401: return Anchor.Direction.LEFT;
402: default:
403: throw new IllegalArgumentException();
404: }
405: }
406:
407: }
|