001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Denis M. Kishenko
019: * @version $Revision$
020: */package java.awt.geom;
021:
022: import java.util.NoSuchElementException;
023:
024: import org.apache.harmony.awt.internal.nls.Messages;
025: import org.apache.harmony.misc.HashCode;
026:
027: public abstract class Rectangle2D extends RectangularShape {
028:
029: public static final int OUT_LEFT = 1;
030: public static final int OUT_TOP = 2;
031: public static final int OUT_RIGHT = 4;
032: public static final int OUT_BOTTOM = 8;
033:
034: public static class Float extends Rectangle2D {
035:
036: public float x;
037: public float y;
038: public float width;
039: public float height;
040:
041: public Float() {
042: }
043:
044: public Float(float x, float y, float width, float height) {
045: setRect(x, y, width, height);
046: }
047:
048: @Override
049: public double getX() {
050: return x;
051: }
052:
053: @Override
054: public double getY() {
055: return y;
056: }
057:
058: @Override
059: public double getWidth() {
060: return width;
061: }
062:
063: @Override
064: public double getHeight() {
065: return height;
066: }
067:
068: @Override
069: public boolean isEmpty() {
070: return width <= 0.0f || height <= 0.0f;
071: }
072:
073: public void setRect(float x, float y, float width, float height) {
074: this .x = x;
075: this .y = y;
076: this .width = width;
077: this .height = height;
078: }
079:
080: @Override
081: public void setRect(double x, double y, double width,
082: double height) {
083: this .x = (float) x;
084: this .y = (float) y;
085: this .width = (float) width;
086: this .height = (float) height;
087: }
088:
089: @Override
090: public void setRect(Rectangle2D r) {
091: this .x = (float) r.getX();
092: this .y = (float) r.getY();
093: this .width = (float) r.getWidth();
094: this .height = (float) r.getHeight();
095: }
096:
097: @Override
098: public int outcode(double px, double py) {
099: int code = 0;
100:
101: if (width <= 0.0f) {
102: code |= OUT_LEFT | OUT_RIGHT;
103: } else if (px < x) {
104: code |= OUT_LEFT;
105: } else if (px > x + width) {
106: code |= OUT_RIGHT;
107: }
108:
109: if (height <= 0.0f) {
110: code |= OUT_TOP | OUT_BOTTOM;
111: } else if (py < y) {
112: code |= OUT_TOP;
113: } else if (py > y + height) {
114: code |= OUT_BOTTOM;
115: }
116:
117: return code;
118: }
119:
120: @Override
121: public Rectangle2D getBounds2D() {
122: return new Float(x, y, width, height);
123: }
124:
125: @Override
126: public Rectangle2D createIntersection(Rectangle2D r) {
127: Rectangle2D dst;
128: if (r instanceof Double) {
129: dst = new Rectangle2D.Double();
130: } else {
131: dst = new Rectangle2D.Float();
132: }
133: Rectangle2D.intersect(this , r, dst);
134: return dst;
135: }
136:
137: @Override
138: public Rectangle2D createUnion(Rectangle2D r) {
139: Rectangle2D dst;
140: if (r instanceof Double) {
141: dst = new Rectangle2D.Double();
142: } else {
143: dst = new Rectangle2D.Float();
144: }
145: Rectangle2D.union(this , r, dst);
146: return dst;
147: }
148:
149: @Override
150: public String toString() {
151: // The output format based on 1.5 release behaviour. It could be obtained in the following way
152: // System.out.println(new Rectangle2D.Float().toString())
153: return getClass().getName()
154: + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
155: }
156: }
157:
158: public static class Double extends Rectangle2D {
159:
160: public double x;
161: public double y;
162: public double width;
163: public double height;
164:
165: public Double() {
166: }
167:
168: public Double(double x, double y, double width, double height) {
169: setRect(x, y, width, height);
170: }
171:
172: @Override
173: public double getX() {
174: return x;
175: }
176:
177: @Override
178: public double getY() {
179: return y;
180: }
181:
182: @Override
183: public double getWidth() {
184: return width;
185: }
186:
187: @Override
188: public double getHeight() {
189: return height;
190: }
191:
192: @Override
193: public boolean isEmpty() {
194: return width <= 0.0 || height <= 0.0;
195: }
196:
197: @Override
198: public void setRect(double x, double y, double width,
199: double height) {
200: this .x = x;
201: this .y = y;
202: this .width = width;
203: this .height = height;
204: }
205:
206: @Override
207: public void setRect(Rectangle2D r) {
208: this .x = r.getX();
209: this .y = r.getY();
210: this .width = r.getWidth();
211: this .height = r.getHeight();
212: }
213:
214: @Override
215: public int outcode(double px, double py) {
216: int code = 0;
217:
218: if (width <= 0.0) {
219: code |= OUT_LEFT | OUT_RIGHT;
220: } else if (px < x) {
221: code |= OUT_LEFT;
222: } else if (px > x + width) {
223: code |= OUT_RIGHT;
224: }
225:
226: if (height <= 0.0) {
227: code |= OUT_TOP | OUT_BOTTOM;
228: } else if (py < y) {
229: code |= OUT_TOP;
230: } else if (py > y + height) {
231: code |= OUT_BOTTOM;
232: }
233:
234: return code;
235: }
236:
237: @Override
238: public Rectangle2D getBounds2D() {
239: return new Double(x, y, width, height);
240: }
241:
242: @Override
243: public Rectangle2D createIntersection(Rectangle2D r) {
244: Rectangle2D dst = new Rectangle2D.Double();
245: Rectangle2D.intersect(this , r, dst);
246: return dst;
247: }
248:
249: @Override
250: public Rectangle2D createUnion(Rectangle2D r) {
251: Rectangle2D dest = new Rectangle2D.Double();
252: Rectangle2D.union(this , r, dest);
253: return dest;
254: }
255:
256: @Override
257: public String toString() {
258: // The output format based on 1.5 release behaviour. It could be obtained in the following way
259: // System.out.println(new Rectangle2D.Double().toString())
260: return getClass().getName()
261: + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
262: }
263: }
264:
265: /*
266: * Rectangle2D path iterator
267: */
268: class Iterator implements PathIterator {
269:
270: /**
271: * The x coordinate of left-upper rectangle corner
272: */
273: double x;
274:
275: /**
276: * The y coordinate of left-upper rectangle corner
277: */
278: double y;
279:
280: /**
281: * The width of rectangle
282: */
283: double width;
284:
285: /**
286: * The height of rectangle
287: */
288: double height;
289:
290: /**
291: * The path iterator transformation
292: */
293: AffineTransform t;
294:
295: /**
296: * The current segmenet index
297: */
298: int index;
299:
300: /**
301: * Constructs a new Rectangle2D.Iterator for given rectangle and transformation
302: * @param r - the source Rectangle2D object
303: * @param at - the AffineTransform object to apply rectangle path
304: */
305: Iterator(Rectangle2D r, AffineTransform at) {
306: this .x = r.getX();
307: this .y = r.getY();
308: this .width = r.getWidth();
309: this .height = r.getHeight();
310: this .t = at;
311: if (width < 0.0 || height < 0.0) {
312: index = 6;
313: }
314: }
315:
316: public int getWindingRule() {
317: return WIND_NON_ZERO;
318: }
319:
320: public boolean isDone() {
321: return index > 5;
322: }
323:
324: public void next() {
325: index++;
326: }
327:
328: public int currentSegment(double[] coords) {
329: if (isDone()) {
330: throw new NoSuchElementException(Messages
331: .getString("awt.4B")); //$NON-NLS-1$
332: }
333: if (index == 5) {
334: return SEG_CLOSE;
335: }
336: int type;
337: if (index == 0) {
338: type = SEG_MOVETO;
339: coords[0] = x;
340: coords[1] = y;
341: } else {
342: type = SEG_LINETO;
343: switch (index) {
344: case 1:
345: coords[0] = x + width;
346: coords[1] = y;
347: break;
348: case 2:
349: coords[0] = x + width;
350: coords[1] = y + height;
351: break;
352: case 3:
353: coords[0] = x;
354: coords[1] = y + height;
355: break;
356: case 4:
357: coords[0] = x;
358: coords[1] = y;
359: break;
360: }
361: }
362: if (t != null) {
363: t.transform(coords, 0, coords, 0, 1);
364: }
365: return type;
366: }
367:
368: public int currentSegment(float[] coords) {
369: if (isDone()) {
370: throw new NoSuchElementException(Messages
371: .getString("awt.4B")); //$NON-NLS-1$
372: }
373: if (index == 5) {
374: return SEG_CLOSE;
375: }
376: int type;
377: if (index == 0) {
378: coords[0] = (float) x;
379: coords[1] = (float) y;
380: type = SEG_MOVETO;
381: } else {
382: type = SEG_LINETO;
383: switch (index) {
384: case 1:
385: coords[0] = (float) (x + width);
386: coords[1] = (float) y;
387: break;
388: case 2:
389: coords[0] = (float) (x + width);
390: coords[1] = (float) (y + height);
391: break;
392: case 3:
393: coords[0] = (float) x;
394: coords[1] = (float) (y + height);
395: break;
396: case 4:
397: coords[0] = (float) x;
398: coords[1] = (float) y;
399: break;
400: }
401: }
402: if (t != null) {
403: t.transform(coords, 0, coords, 0, 1);
404: }
405: return type;
406: }
407:
408: }
409:
410: protected Rectangle2D() {
411: }
412:
413: public abstract void setRect(double x, double y, double width,
414: double height);
415:
416: public abstract int outcode(double x, double y);
417:
418: public abstract Rectangle2D createIntersection(Rectangle2D r);
419:
420: public abstract Rectangle2D createUnion(Rectangle2D r);
421:
422: public void setRect(Rectangle2D r) {
423: setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
424: }
425:
426: @Override
427: public void setFrame(double x, double y, double width, double height) {
428: setRect(x, y, width, height);
429: }
430:
431: public Rectangle2D getBounds2D() {
432: return (Rectangle2D) clone();
433: }
434:
435: public boolean intersectsLine(double x1, double y1, double x2,
436: double y2) {
437: double rx1 = getX();
438: double ry1 = getY();
439: double rx2 = rx1 + getWidth();
440: double ry2 = ry1 + getHeight();
441: return (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2)
442: || (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2)
443: || Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1,
444: x2, y2)
445: || Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1,
446: x2, y2);
447: }
448:
449: public boolean intersectsLine(Line2D l) {
450: return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l
451: .getY2());
452: }
453:
454: public int outcode(Point2D p) {
455: return outcode(p.getX(), p.getY());
456: }
457:
458: public boolean contains(double x, double y) {
459: if (isEmpty()) {
460: return false;
461: }
462:
463: double x1 = getX();
464: double y1 = getY();
465: double x2 = x1 + getWidth();
466: double y2 = y1 + getHeight();
467:
468: return x1 <= x && x < x2 && y1 <= y && y < y2;
469: }
470:
471: public boolean intersects(double x, double y, double width,
472: double height) {
473: if (isEmpty() || width <= 0.0 || height <= 0.0) {
474: return false;
475: }
476:
477: double x1 = getX();
478: double y1 = getY();
479: double x2 = x1 + getWidth();
480: double y2 = y1 + getHeight();
481:
482: return x + width > x1 && x < x2 && y + height > y1 && y < y2;
483: }
484:
485: public boolean contains(double x, double y, double width,
486: double height) {
487: if (isEmpty() || width <= 0.0 || height <= 0.0) {
488: return false;
489: }
490:
491: double x1 = getX();
492: double y1 = getY();
493: double x2 = x1 + getWidth();
494: double y2 = y1 + getHeight();
495:
496: return x1 <= x && x + width <= x2 && y1 <= y
497: && y + height <= y2;
498: }
499:
500: public static void intersect(Rectangle2D src1, Rectangle2D src2,
501: Rectangle2D dst) {
502: double x1 = Math.max(src1.getMinX(), src2.getMinX());
503: double y1 = Math.max(src1.getMinY(), src2.getMinY());
504: double x2 = Math.min(src1.getMaxX(), src2.getMaxX());
505: double y2 = Math.min(src1.getMaxY(), src2.getMaxY());
506: dst.setFrame(x1, y1, x2 - x1, y2 - y1);
507: }
508:
509: public static void union(Rectangle2D src1, Rectangle2D src2,
510: Rectangle2D dst) {
511: double x1 = Math.min(src1.getMinX(), src2.getMinX());
512: double y1 = Math.min(src1.getMinY(), src2.getMinY());
513: double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
514: double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
515: dst.setFrame(x1, y1, x2 - x1, y2 - y1);
516: }
517:
518: public void add(double x, double y) {
519: double x1 = Math.min(getMinX(), x);
520: double y1 = Math.min(getMinY(), y);
521: double x2 = Math.max(getMaxX(), x);
522: double y2 = Math.max(getMaxY(), y);
523: setRect(x1, y1, x2 - x1, y2 - y1);
524: }
525:
526: public void add(Point2D p) {
527: add(p.getX(), p.getY());
528: }
529:
530: public void add(Rectangle2D r) {
531: union(this , r, this );
532: }
533:
534: public PathIterator getPathIterator(AffineTransform t) {
535: return new Iterator(this , t);
536: }
537:
538: @Override
539: public PathIterator getPathIterator(AffineTransform t,
540: double flatness) {
541: return new Iterator(this , t);
542: }
543:
544: @Override
545: public int hashCode() {
546: HashCode hash = new HashCode();
547: hash.append(getX());
548: hash.append(getY());
549: hash.append(getWidth());
550: hash.append(getHeight());
551: return hash.hashCode();
552: }
553:
554: @Override
555: public boolean equals(Object obj) {
556: if (obj == this ) {
557: return true;
558: }
559: if (obj instanceof Rectangle2D) {
560: Rectangle2D r = (Rectangle2D) obj;
561: return getX() == r.getX() && getY() == r.getY()
562: && getWidth() == r.getWidth()
563: && getHeight() == r.getHeight();
564: }
565: return false;
566: }
567:
568: }
|