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.awt.Rectangle;
023: import java.awt.Shape;
024: import java.util.NoSuchElementException;
025:
026: import org.apache.harmony.awt.internal.nls.Messages;
027:
028: public abstract class Line2D implements Shape, Cloneable {
029:
030: public static class Float extends Line2D {
031:
032: public float x1;
033: public float y1;
034: public float x2;
035: public float y2;
036:
037: public Float() {
038: }
039:
040: public Float(float x1, float y1, float x2, float y2) {
041: setLine(x1, y1, x2, y2);
042: }
043:
044: public Float(Point2D p1, Point2D p2) {
045: setLine(p1, p2);
046: }
047:
048: @Override
049: public double getX1() {
050: return x1;
051: }
052:
053: @Override
054: public double getY1() {
055: return y1;
056: }
057:
058: @Override
059: public double getX2() {
060: return x2;
061: }
062:
063: @Override
064: public double getY2() {
065: return y2;
066: }
067:
068: @Override
069: public Point2D getP1() {
070: return new Point2D.Float(x1, y1);
071: }
072:
073: @Override
074: public Point2D getP2() {
075: return new Point2D.Float(x2, y2);
076: }
077:
078: @Override
079: public void setLine(double x1, double y1, double x2, double y2) {
080: this .x1 = (float) x1;
081: this .y1 = (float) y1;
082: this .x2 = (float) x2;
083: this .y2 = (float) y2;
084: }
085:
086: public void setLine(float x1, float y1, float x2, float y2) {
087: this .x1 = x1;
088: this .y1 = y1;
089: this .x2 = x2;
090: this .y2 = y2;
091: }
092:
093: public Rectangle2D getBounds2D() {
094: float rx, ry, rw, rh;
095: if (x1 < x2) {
096: rx = x1;
097: rw = x2 - x1;
098: } else {
099: rx = x2;
100: rw = x1 - x2;
101: }
102: if (y1 < y2) {
103: ry = y1;
104: rh = y2 - y1;
105: } else {
106: ry = y2;
107: rh = y1 - y2;
108: }
109: return new Rectangle2D.Float(rx, ry, rw, rh);
110: }
111: }
112:
113: public static class Double extends Line2D {
114:
115: public double x1;
116: public double y1;
117: public double x2;
118: public double y2;
119:
120: public Double() {
121: }
122:
123: public Double(double x1, double y1, double x2, double y2) {
124: setLine(x1, y1, x2, y2);
125: }
126:
127: public Double(Point2D p1, Point2D p2) {
128: setLine(p1, p2);
129: }
130:
131: @Override
132: public double getX1() {
133: return x1;
134: }
135:
136: @Override
137: public double getY1() {
138: return y1;
139: }
140:
141: @Override
142: public double getX2() {
143: return x2;
144: }
145:
146: @Override
147: public double getY2() {
148: return y2;
149: }
150:
151: @Override
152: public Point2D getP1() {
153: return new Point2D.Double(x1, y1);
154: }
155:
156: @Override
157: public Point2D getP2() {
158: return new Point2D.Double(x2, y2);
159: }
160:
161: @Override
162: public void setLine(double x1, double y1, double x2, double y2) {
163: this .x1 = x1;
164: this .y1 = y1;
165: this .x2 = x2;
166: this .y2 = y2;
167: }
168:
169: public Rectangle2D getBounds2D() {
170: double rx, ry, rw, rh;
171: if (x1 < x2) {
172: rx = x1;
173: rw = x2 - x1;
174: } else {
175: rx = x2;
176: rw = x1 - x2;
177: }
178: if (y1 < y2) {
179: ry = y1;
180: rh = y2 - y1;
181: } else {
182: ry = y2;
183: rh = y1 - y2;
184: }
185: return new Rectangle2D.Double(rx, ry, rw, rh);
186: }
187: }
188:
189: /*
190: * Line2D path iterator
191: */
192: class Iterator implements PathIterator {
193:
194: /**
195: * The x coordinate of the start line point
196: */
197: double x1;
198:
199: /**
200: * The y coordinate of the start line point
201: */
202: double y1;
203:
204: /**
205: * The x coordinate of the end line point
206: */
207: double x2;
208:
209: /**
210: * The y coordinate of the end line point
211: */
212: double y2;
213:
214: /**
215: * The path iterator transformation
216: */
217: AffineTransform t;
218:
219: /**
220: * The current segmenet index
221: */
222: int index;
223:
224: /**
225: * Constructs a new Line2D.Iterator for given line and transformation
226: * @param l - the source Line2D object
227: * @param at - the AffineTransform object to apply rectangle path
228: */
229: Iterator(Line2D l, AffineTransform at) {
230: this .x1 = l.getX1();
231: this .y1 = l.getY1();
232: this .x2 = l.getX2();
233: this .y2 = l.getY2();
234: this .t = at;
235: }
236:
237: public int getWindingRule() {
238: return WIND_NON_ZERO;
239: }
240:
241: public boolean isDone() {
242: return index > 1;
243: }
244:
245: public void next() {
246: index++;
247: }
248:
249: public int currentSegment(double[] coords) {
250: if (isDone()) {
251: // awt.4B=Iterator out of bounds
252: throw new NoSuchElementException(Messages
253: .getString("awt.4B")); //$NON-NLS-1$
254: }
255: int type;
256: if (index == 0) {
257: type = SEG_MOVETO;
258: coords[0] = x1;
259: coords[1] = y1;
260: } else {
261: type = SEG_LINETO;
262: coords[0] = x2;
263: coords[1] = y2;
264: }
265: if (t != null) {
266: t.transform(coords, 0, coords, 0, 1);
267: }
268: return type;
269: }
270:
271: public int currentSegment(float[] coords) {
272: if (isDone()) {
273: // awt.4B=Iterator out of bounds
274: throw new NoSuchElementException(Messages
275: .getString("awt.4B")); //$NON-NLS-1$
276: }
277: int type;
278: if (index == 0) {
279: type = SEG_MOVETO;
280: coords[0] = (float) x1;
281: coords[1] = (float) y1;
282: } else {
283: type = SEG_LINETO;
284: coords[0] = (float) x2;
285: coords[1] = (float) y2;
286: }
287: if (t != null) {
288: t.transform(coords, 0, coords, 0, 1);
289: }
290: return type;
291: }
292:
293: }
294:
295: protected Line2D() {
296: }
297:
298: public abstract double getX1();
299:
300: public abstract double getY1();
301:
302: public abstract double getX2();
303:
304: public abstract double getY2();
305:
306: public abstract Point2D getP1();
307:
308: public abstract Point2D getP2();
309:
310: public abstract void setLine(double x1, double y1, double x2,
311: double y2);
312:
313: public void setLine(Point2D p1, Point2D p2) {
314: setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
315: }
316:
317: public void setLine(Line2D line) {
318: setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2());
319: }
320:
321: public Rectangle getBounds() {
322: return getBounds2D().getBounds();
323: }
324:
325: public static int relativeCCW(double x1, double y1, double x2,
326: double y2, double px, double py) {
327: /*
328: * A = (x2-x1, y2-y1) P = (px-x1, py-y1)
329: */
330: x2 -= x1;
331: y2 -= y1;
332: px -= x1;
333: py -= y1;
334: double t = px * y2 - py * x2; // PxA
335: if (t == 0.0) {
336: t = px * x2 + py * y2; // P*A
337: if (t > 0.0) {
338: px -= x2; // B-A
339: py -= y2;
340: t = px * x2 + py * y2; // (P-A)*A
341: if (t < 0.0) {
342: t = 0.0;
343: }
344: }
345: }
346:
347: return t < 0.0 ? -1 : (t > 0.0 ? 1 : 0);
348: }
349:
350: public int relativeCCW(double px, double py) {
351: return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py);
352: }
353:
354: public int relativeCCW(Point2D p) {
355: return relativeCCW(getX1(), getY1(), getX2(), getY2(),
356: p.getX(), p.getY());
357: }
358:
359: public static boolean linesIntersect(double x1, double y1,
360: double x2, double y2, double x3, double y3, double x4,
361: double y4) {
362: /*
363: * A = (x2-x1, y2-y1) B = (x3-x1, y3-y1) C = (x4-x1, y4-y1) D = (x4-x3,
364: * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B
365: *
366: * Result is ((AxB) * (AxC) <=0) and ((DxE) * (DxF) <= 0)
367: *
368: * DxE = (C-B)x(-B) = BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB =
369: * AxB+BxC-AxC
370: */
371:
372: x2 -= x1; // A
373: y2 -= y1;
374: x3 -= x1; // B
375: y3 -= y1;
376: x4 -= x1; // C
377: y4 -= y1;
378:
379: double AvB = x2 * y3 - x3 * y2;
380: double AvC = x2 * y4 - x4 * y2;
381:
382: // Online
383: if (AvB == 0.0 && AvC == 0.0) {
384: if (x2 != 0.0) {
385: return (x4 * x3 <= 0.0)
386: || ((x3 * x2 >= 0.0) && (x2 > 0.0 ? x3 <= x2
387: || x4 <= x2 : x3 >= x2 || x4 >= x2));
388: }
389: if (y2 != 0.0) {
390: return (y4 * y3 <= 0.0)
391: || ((y3 * y2 >= 0.0) && (y2 > 0.0 ? y3 <= y2
392: || y4 <= y2 : y3 >= y2 || y4 >= y2));
393: }
394: return false;
395: }
396:
397: double BvC = x3 * y4 - x4 * y3;
398:
399: return (AvB * AvC <= 0.0) && (BvC * (AvB + BvC - AvC) <= 0.0);
400: }
401:
402: public boolean intersectsLine(double x1, double y1, double x2,
403: double y2) {
404: return linesIntersect(x1, y1, x2, y2, getX1(), getY1(),
405: getX2(), getY2());
406: }
407:
408: public boolean intersectsLine(Line2D l) {
409: return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l
410: .getY2(), getX1(), getY1(), getX2(), getY2());
411: }
412:
413: public static double ptSegDistSq(double x1, double y1, double x2,
414: double y2, double px, double py) {
415: /*
416: * A = (x2 - x1, y2 - y1) P = (px - x1, py - y1)
417: */
418: x2 -= x1; // A = (x2, y2)
419: y2 -= y1;
420: px -= x1; // P = (px, py)
421: py -= y1;
422: double dist;
423: if (px * x2 + py * y2 <= 0.0) { // P*A
424: dist = px * px + py * py;
425: } else {
426: px = x2 - px; // P = A - P = (x2 - px, y2 - py)
427: py = y2 - py;
428: if (px * x2 + py * y2 <= 0.0) { // P*A
429: dist = px * px + py * py;
430: } else {
431: dist = px * y2 - py * x2;
432: dist = dist * dist / (x2 * x2 + y2 * y2); // pxA/|A|
433: }
434: }
435: if (dist < 0) {
436: dist = 0;
437: }
438: return dist;
439: }
440:
441: public static double ptSegDist(double x1, double y1, double x2,
442: double y2, double px, double py) {
443: return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py));
444: }
445:
446: public double ptSegDistSq(double px, double py) {
447: return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
448: }
449:
450: public double ptSegDistSq(Point2D p) {
451: return ptSegDistSq(getX1(), getY1(), getX2(), getY2(),
452: p.getX(), p.getY());
453: }
454:
455: public double ptSegDist(double px, double py) {
456: return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py);
457: }
458:
459: public double ptSegDist(Point2D p) {
460: return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(),
461: p.getY());
462: }
463:
464: public static double ptLineDistSq(double x1, double y1, double x2,
465: double y2, double px, double py) {
466: x2 -= x1;
467: y2 -= y1;
468: px -= x1;
469: py -= y1;
470: double s = px * y2 - py * x2;
471: return s * s / (x2 * x2 + y2 * y2);
472: }
473:
474: public static double ptLineDist(double x1, double y1, double x2,
475: double y2, double px, double py) {
476: return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py));
477: }
478:
479: public double ptLineDistSq(double px, double py) {
480: return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
481: }
482:
483: public double ptLineDistSq(Point2D p) {
484: return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), p
485: .getX(), p.getY());
486: }
487:
488: public double ptLineDist(double px, double py) {
489: return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py);
490: }
491:
492: public double ptLineDist(Point2D p) {
493: return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(),
494: p.getY());
495: }
496:
497: public boolean contains(double px, double py) {
498: return false;
499: }
500:
501: public boolean contains(Point2D p) {
502: return false;
503: }
504:
505: public boolean contains(Rectangle2D r) {
506: return false;
507: }
508:
509: public boolean contains(double rx, double ry, double rw, double rh) {
510: return false;
511: }
512:
513: public boolean intersects(double rx, double ry, double rw, double rh) {
514: return intersects(new Rectangle2D.Double(rx, ry, rw, rh));
515: }
516:
517: public boolean intersects(Rectangle2D r) {
518: return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
519: }
520:
521: public PathIterator getPathIterator(AffineTransform at) {
522: return new Iterator(this , at);
523: }
524:
525: public PathIterator getPathIterator(AffineTransform at,
526: double flatness) {
527: return new Iterator(this , at);
528: }
529:
530: @Override
531: public Object clone() {
532: try {
533: return super .clone();
534: } catch (CloneNotSupportedException e) {
535: throw new InternalError();
536: }
537: }
538:
539: }
|