001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: package org.netbeans.modules.bpel.design.geometry;
021:
022: import java.awt.Rectangle;
023: import java.awt.Shape;
024: import java.awt.geom.AffineTransform;
025: import java.awt.geom.PathIterator;
026: import java.awt.geom.Point2D;
027: import java.awt.geom.Rectangle2D;
028: import java.util.Collection;
029:
030: /**
031: *
032: * @author anjeleevich
033: */
034: public class FPath implements Shape {
035:
036: private FPoint[] points;
037: private int[] types;
038:
039: private int pointOffset;
040: private int pointCount;
041:
042: private float minX;
043: private float minY;
044:
045: private float maxX;
046: private float maxY;
047:
048: public FPath(double x1, double y1, double x2, double y2) {
049: points = new FPoint[] { new FPoint(x1, y1), new FPoint(x2, y2) };
050: types = new int[] { PathIterator.SEG_MOVETO,
051: PathIterator.SEG_LINETO };
052: pointOffset = 0;
053: pointCount = 2;
054: ok();
055: }
056:
057: public FPath(double x1, double y1, double x2, double y2, double x3,
058: double y3) {
059: points = new FPoint[] { new FPoint(x1, y1), new FPoint(x2, y2),
060: new FPoint(x3, y3) };
061:
062: types = new int[] { PathIterator.SEG_MOVETO,
063: PathIterator.SEG_LINETO, PathIterator.SEG_LINETO };
064:
065: pointOffset = 0;
066: pointCount = 3;
067: ok();
068: }
069:
070: public FPath(double x1, double y1, double x2, double y2, double x3,
071: double y3, double x4, double y4) {
072: points = new FPoint[] { new FPoint(x1, y1), new FPoint(x2, y2),
073: new FPoint(x3, y3), new FPoint(x4, y4) };
074:
075: types = new int[] { PathIterator.SEG_MOVETO,
076: PathIterator.SEG_LINETO, PathIterator.SEG_LINETO,
077: PathIterator.SEG_LINETO };
078:
079: pointOffset = 0;
080: pointCount = 4;
081: ok();
082: }
083:
084: private FPath() {
085: points = new FPoint[INITIAL_SIZE];
086: types = new int[INITIAL_SIZE];
087: pointOffset = 0;
088: pointCount = 0;
089: };
090:
091: public FPath(Collection<FPoint> points) {
092: pointOffset = 0;
093: pointCount = points.size();
094: this .points = points.toArray(new FPoint[pointCount]);
095: this .types = new int[pointCount];
096:
097: if (pointCount > 0) {
098: types[0] = PathIterator.SEG_MOVETO;
099: for (int i = pointCount - 1; i >= 1; i--) {
100: types[i] = PathIterator.SEG_LINETO;
101: }
102: }
103: }
104:
105: public FPath(FPoint[] points) {
106: pointOffset = 0;
107: pointCount = points.length;
108:
109: this .points = new FPoint[pointCount];
110: this .types = new int[pointCount];
111:
112: if (pointCount > 0) {
113: System.arraycopy(points, 0, this .points, 0, pointCount);
114: types[0] = PathIterator.SEG_MOVETO;
115: for (int i = pointCount - 1; i >= 1; i--) {
116: types[i] = PathIterator.SEG_LINETO;
117: }
118: }
119: }
120:
121: private FPath(FPoint[] points, int[] types, int offset, int count) {
122: this .types = types;
123: this .points = points;
124: pointOffset = offset;
125: pointCount = count;
126: ok();
127: }
128:
129: public FPath translate(double tx, double ty) {
130: if (((float) tx == 0.0f) && ((float) ty == 0.0f))
131: return this ;
132:
133: FPoint[] newPoints = new FPoint[pointCount];
134: int[] newTypes = new int[pointCount];
135:
136: for (int i = 0; i < pointCount; i++) {
137: int j = pointOffset + i;
138: newPoints[i] = points[j].translate(tx, ty);
139: newTypes[i] = types[j];
140: }
141:
142: return new FPath(newPoints, newTypes, 0, pointCount);
143: }
144:
145: public FPath move(double px, double py) {
146: if (pointCount == 0) {
147: return this ;
148: }
149:
150: FPoint p = points[pointOffset];
151:
152: return translate(px - p.x, py - p.y);
153: }
154:
155: public FPath subtract(FShape shape) {
156: if (pointCount == 0) {
157: return this ;
158: }
159:
160: int i1 = pointOffset;
161: int i2 = i1 + pointCount;
162:
163: FIntersector intersector = null;
164:
165: FPoint point1 = points[i1];
166: int type1 = types[i1];
167: boolean inside1 = shape.contains(point1);
168:
169: FPath result = new FPath();
170:
171: for (int i = i1 + 1; i < i2; i++) {
172: FPoint point2 = points[i];
173: int type2 = types[i];
174: boolean inside2 = shape.contains(point2);
175:
176: if (type2 == PathIterator.SEG_MOVETO) {
177: result.addSpace(point1, point2);
178: } else if (inside1 && inside2) {
179: result.addSpace(point1, point2);
180: } else {
181: if (intersector == null) {
182: intersector = new FIntersector();
183: }
184:
185: intersector.setLine(point1, point2);
186:
187: if (shape.intersect(intersector)) {
188: FPoint ip1 = point1.point(intersector.getT1(),
189: point2);
190: FPoint ip2 = point1.point(intersector.getT2(),
191: point2);
192:
193: if (!ip1.equals(point1)) {
194: result.addLine(point1, ip1);
195: }
196:
197: result.addSpace(ip1, ip2);
198:
199: if (!ip2.equals(point2)) {
200: result.addLine(ip2, point2);
201: }
202: } else {
203: result.addLine(point1, point2);
204: }
205: }
206:
207: inside1 = inside2;
208: type1 = type2;
209: point1 = point2;
210: }
211:
212: result.ok();
213:
214: return result;
215: }
216:
217: public FPath intersect(FShape shape) {
218: if (pointCount == 0) {
219: return this ;
220: }
221:
222: int i1 = pointOffset;
223: int i2 = i1 + pointCount;
224:
225: FIntersector intersector = null;
226:
227: FPoint point1 = points[i1];
228: int type1 = types[i1];
229: boolean inside1 = shape.contains(point1);
230:
231: FPath result = new FPath();
232: ;
233:
234: for (int i = i1 + 1; i < i2; i++) {
235: FPoint point2 = points[i];
236: int type2 = types[i];
237: boolean inside2 = shape.contains(point2);
238:
239: if (type2 == PathIterator.SEG_MOVETO) {
240: result.addSpace(point1, point2);
241: } else if (inside1 && inside2) {
242: result.addLine(point1, point2);
243: } else {
244: if (intersector == null) {
245: intersector = new FIntersector();
246: }
247:
248: intersector.setLine(point1, point2);
249:
250: if (shape.intersect(intersector)) {
251: FPoint ip1 = point1.point(intersector.getT1(),
252: point2);
253: FPoint ip2 = point1.point(intersector.getT2(),
254: point2);
255:
256: if (!ip1.equals(point1)) {
257: result.addSpace(point1, ip1);
258: }
259:
260: result.addLine(ip1, ip2);
261:
262: if (!ip2.equals(point2)) {
263: result.addSpace(ip2, point2);
264: }
265: } else {
266: result.addSpace(point1, point2);
267: }
268: }
269:
270: inside1 = inside2;
271: type1 = type2;
272: point1 = point2;
273: }
274:
275: result.ok();
276:
277: return result;
278: }
279:
280: public FPath round(double radius) {
281: if (radius <= 0.0)
282: return this ;
283: if (pointCount <= 2)
284: return this ;
285:
286: FPath result = new FPath();
287:
288: int i1 = pointOffset;
289: int i2 = i1 + pointCount;
290:
291: FPoint p = points[i1];
292:
293: for (int i = i1 + 1; i < i2; i++) {
294: FPoint p2 = points[i];
295: int t2 = types[i];
296:
297: if (t2 == PathIterator.SEG_MOVETO) {
298: result.addSpace(p, p2);
299: p = p2;
300: continue;
301: }
302:
303: if (i + 1 == i2) {
304: result.addLine(p, p2);
305: p = p2;
306: continue;
307: }
308:
309: int t3 = types[i + 1];
310:
311: if (t3 == PathIterator.SEG_MOVETO) {
312: result.addLine(p, p2);
313: p = p2;
314: } else {
315: FPoint p1 = points[i - 1];
316: FPoint p3 = points[i + 1];
317:
318: double len1 = p1.distance(p2);
319: double len2 = p2.distance(p3);
320:
321: if (((float) len1 != 0.0f) && ((float) len2 != 0.0f)) {
322: double k1 = (len1 - radius) / len1;
323:
324: if (k1 < 0.5) {
325: k1 = 0.5;
326: }
327:
328: double k2 = radius / len2;
329:
330: if (k2 > 0.5) {
331: k2 = 0.5;
332: }
333:
334: FPoint kp1 = p1.point(k1, p2);
335: FPoint kp2 = p2.point(k2, p3);
336:
337: result.addLine(p, kp1);
338: result.addLine(kp1, kp2);
339:
340: p = kp2;
341: } else {
342: result.addLine(p, p2);
343: p = p2;
344: }
345: }
346: }
347:
348: result.ok();
349:
350: return result;
351: }
352:
353: private void addSpace(FPoint p1, FPoint p2) {
354: if (pointCount == 0) {
355: ensureCapacity(1);
356: points[0] = p2;
357: types[0] = PathIterator.SEG_MOVETO;
358: pointCount = 1;
359: } else if (types[pointCount - 1] == PathIterator.SEG_MOVETO) {
360: points[pointCount - 1] = p2;
361: } else {
362: ensureCapacity(pointCount + 1);
363: points[pointCount] = p2;
364: types[pointCount] = PathIterator.SEG_MOVETO;
365: pointCount++;
366: }
367: }
368:
369: private void addLine(FPoint p1, FPoint p2) {
370: if (p1.equals(p2))
371: return;
372:
373: if (pointCount == 0) {
374: ensureCapacity(2);
375:
376: points[0] = p1;
377: points[1] = p2;
378:
379: types[0] = PathIterator.SEG_MOVETO;
380: types[1] = PathIterator.SEG_LINETO;
381:
382: pointCount = 2;
383: } else {
384: ensureCapacity(pointCount + 1);
385:
386: points[pointCount] = p2;
387: types[pointCount] = PathIterator.SEG_LINETO;
388: pointCount++;
389: }
390: }
391:
392: private void ensureCapacity(int size) {
393: if (size > points.length) {
394: int newSize = points.length * 3 / 2 + 1;
395: int maxNewSize = points.length + 10;
396:
397: if (newSize > maxNewSize) {
398: newSize = maxNewSize;
399: }
400:
401: if (newSize < size) {
402: newSize = size;
403: }
404:
405: FPoint[] newPoints = new FPoint[newSize];
406: int[] newTypes = new int[newSize];
407:
408: System.arraycopy(points, 0, newPoints, 0, pointCount);
409: System.arraycopy(types, 0, newTypes, 0, pointCount);
410:
411: points = newPoints;
412: types = newTypes;
413: }
414: }
415:
416: private void ok() {
417: int i1 = pointOffset;
418: int i2 = i1 + pointCount - 1;
419:
420: for (int i = i2; i >= i1; i--) {
421: if (types[i] == PathIterator.SEG_LINETO)
422: break;
423:
424: points[i] = null;
425: pointCount--;
426: }
427:
428: float minX = Float.POSITIVE_INFINITY;
429: float minY = Float.POSITIVE_INFINITY;
430:
431: float maxX = Float.NEGATIVE_INFINITY;
432: float maxY = Float.NEGATIVE_INFINITY;
433:
434: i2 = i1 + pointCount;
435:
436: for (int i = i1; i < i2; i++) {
437: FPoint p = points[i];
438:
439: if (p.x < minX) {
440: minX = p.x;
441: }
442: if (p.x > maxX) {
443: maxX = p.x;
444: }
445:
446: if (p.y < minY) {
447: minY = p.y;
448: }
449: if (p.y > maxY) {
450: maxY = p.y;
451: }
452: }
453:
454: this .minX = minX;
455: this .minY = minY;
456:
457: this .maxX = maxX;
458: this .maxY = maxY;
459: }
460:
461: public boolean isConnected() {
462: if (pointCount == 0)
463: return true;
464:
465: for (int i = 2; i < pointCount; i++) {
466: if (types[i] == PathIterator.SEG_MOVETO)
467: return false;
468: }
469:
470: return true;
471: }
472:
473: public double length() {
474: if (pointCount == 0)
475: return 0.0;
476:
477: double length = 0.0;
478:
479: int i1 = pointOffset;
480: int i2 = i1 + pointCount;
481:
482: FPoint p1 = points[i1];
483:
484: for (int i = i1 + 1; i < i2; i++) {
485: FPoint p2 = points[i];
486:
487: if (!p1.equals(p2) && types[i] == PathIterator.SEG_LINETO) {
488: length += p1.distance(p2);
489: }
490:
491: p1 = p2;
492: }
493:
494: return length;
495: }
496:
497: public FCoords coords(double t) {
498: t = parameterToLength(t);
499:
500: int i1 = pointOffset;
501: int i2 = i1 + pointCount;
502:
503: double length = 0;
504:
505: FPoint p1 = points[i1];
506:
507: for (int i = i1 + 1; i < i2; i++) {
508: FPoint p2 = points[i];
509:
510: if (!p1.equals(p2) && (types[i] == PathIterator.SEG_LINETO)) {
511: double segLength = p1.distance(p2);
512: double nextLength = length + segLength;
513:
514: if (length <= t && t <= nextLength) {
515: t = (t - length) / segLength;
516:
517: double x0;
518: double y0;
519:
520: double dx = p2.x - p1.x;
521: double dy = p2.y - p1.y;
522:
523: if (t < 0.0) {
524: x0 = p1.x;
525: y0 = p1.y;
526: } else if (t > 1.0) {
527: x0 = p2.x;
528: y0 = p2.y;
529: } else {
530: x0 = p1.x + t * dx;
531: y0 = p1.y + t * dy;
532: }
533:
534: return new FCoords(x0, y0, dx / segLength, dy
535: / segLength);
536: }
537:
538: length = nextLength;
539: }
540:
541: p1 = p2;
542: }
543:
544: return new FCoords(p1.x, p1.y);
545: }
546:
547: public FPoint point(double t) {
548: t = parameterToLength(t);
549:
550: int i1 = pointOffset;
551: int i2 = i1 + pointCount;
552:
553: FPoint p1 = points[i1];
554:
555: for (int i = i1 + 1; i < i2; i++) {
556: FPoint p2 = points[i];
557:
558: if (!p1.equals(p2) && (types[i] == PathIterator.SEG_LINETO)) {
559: double segLength = p1.distance(p2);
560:
561: if (t <= segLength) {
562: return (t == 0) ? p1 : p1.point(t / segLength, p2);
563: }
564:
565: t -= segLength;
566: }
567:
568: p1 = p2;
569: }
570:
571: return p1;
572: }
573:
574: public FPoint tangent(double t) {
575: t = parameterToLength(t);
576:
577: int i1 = pointOffset;
578: int i2 = i1 + pointCount;
579:
580: double length = 0;
581:
582: FPoint p1 = points[i1];
583:
584: for (int i = i1 + 1; i < i2; i++) {
585: FPoint p2 = points[i];
586:
587: if (!p1.equals(p2) && (types[i] == PathIterator.SEG_LINETO)) {
588: double segLength = p1.distance(p2);
589: double nextLength = length + segLength;
590:
591: if (length <= t && t <= nextLength) {
592: return new FPoint((p2.x - p1.x) / segLength,
593: (p2.y - p1.y) / segLength);
594: }
595:
596: length = nextLength;
597: }
598:
599: p1 = p2;
600: }
601:
602: return new FPoint(0, 0);
603: }
604:
605: public FPoint normal(double t) {
606: return tangent(t).rotate90();
607: }
608:
609: private double parameterToLength(double t) {
610: if (t < 0.0)
611: return 0.0;
612: if (t >= 1.0)
613: return length();
614: return t * length();
615: }
616:
617: // java.awt.Shape interface implementation below
618:
619: public boolean contains(Point2D p) {
620: return false;
621: }
622:
623: public boolean contains(Rectangle2D r) {
624: return false;
625: }
626:
627: public boolean contains(double x, double y, double w, double h) {
628: return false;
629: }
630:
631: public boolean contains(double x, double y) {
632: return false;
633: }
634:
635: public boolean intersects(Rectangle2D r) {
636: return intersects(r.getX(), r.getY(), r.getWidth(), r
637: .getHeight());
638: }
639:
640: public PathIterator getPathIterator(AffineTransform at) {
641: return new PathPathIterator(at);
642: }
643:
644: public PathIterator getPathIterator(AffineTransform at,
645: double flatness) {
646: return getPathIterator(at);
647: }
648:
649: public boolean intersects(double x, double y, double w, double h) {
650: if (pointCount == 0)
651: return false;
652:
653: if (w < 0.0) {
654: x += w;
655: w = -w;
656: }
657:
658: if (h < 0.0) {
659: y += h;
660: h = -h;
661: }
662:
663: if (maxX < x)
664: return false;
665: if (maxY < y)
666: return false;
667:
668: if (x + w < minX)
669: return false;
670: if (y + h < minY)
671: return false;
672:
673: return true;
674: }
675:
676: public Rectangle2D getBounds2D() {
677: if (pointCount == 0)
678: return new Rectangle2D.Float();
679:
680: return new Rectangle2D.Float(minX, minY, maxX - minX, maxY
681: - minY);
682: }
683:
684: public Rectangle getBounds() {
685: if (pointCount == 0)
686: return new Rectangle();
687:
688: int x = (int) Math.floor(minX);
689: int y = (int) Math.floor(minY);
690:
691: return new Rectangle(x, y, (int) Math.ceil(maxX) - x,
692: (int) Math.ceil(maxY) - y);
693: }
694:
695: private class PathPathIterator implements PathIterator {
696: private int index = 0;
697: private AffineTransform at;
698:
699: public PathPathIterator(AffineTransform at) {
700: this .at = at;
701: }
702:
703: public int currentSegment(double[] coords) {
704: FPoint p = points[index];
705:
706: coords[0] = p.x;
707: coords[1] = p.y;
708:
709: if (at != null) {
710: at.transform(coords, 0, coords, 0, 1);
711: }
712:
713: return types[index];
714: }
715:
716: public int currentSegment(float[] coords) {
717: FPoint p = points[index];
718:
719: coords[0] = p.x;
720: coords[1] = p.y;
721:
722: if (at != null) {
723: at.transform(coords, 0, coords, 0, 1);
724: }
725:
726: return types[index];
727: }
728:
729: public void next() {
730: index++;
731: }
732:
733: public boolean isDone() {
734: return (index >= pointCount);
735: }
736:
737: public int getWindingRule() {
738: return PathIterator.WIND_NON_ZERO;
739: }
740: }
741:
742: private static final int MAX_GROW = 10;
743: private static final int INITIAL_SIZE = 10;
744:
745: }
|