1 8 package com.nightlabs.editor2d.j2d; 9 10 import java.awt.Shape ; 11 import java.awt.geom.AffineTransform ; 12 import java.awt.geom.FlatteningPathIterator ; 13 import java.awt.geom.IllegalPathStateException ; 14 import java.awt.geom.PathIterator ; 15 import java.awt.geom.Point2D ; 16 import java.awt.geom.Rectangle2D ; 17 import java.io.Serializable ; 18 import java.util.ArrayList ; 19 import java.util.Iterator ; 20 import java.util.List ; 21 22 import sun.awt.geom.Crossings; 23 import sun.awt.geom.Curve; 24 25 26 48 public class GeneralShape 49 implements Shape , Cloneable , Serializable  50 { 51 55 public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; 56 57 61 public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; 62 63 private static final byte SEG_MOVETO = (byte) PathIterator.SEG_MOVETO; 66 private static final byte SEG_LINETO = (byte) PathIterator.SEG_LINETO; 67 private static final byte SEG_QUADTO = (byte) PathIterator.SEG_QUADTO; 68 private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO; 69 private static final byte SEG_CLOSE = (byte) PathIterator.SEG_CLOSE; 70 71 protected byte[] pointTypes; 72 protected float[] pointCoords; 73 int numTypes; 74 int numCoords; 75 int windingRule; 76 77 public byte[] getPointTypes() { 79 return pointTypes; 80 } 81 public void setPointTypes(byte[] _pointTypes) { 82 pointTypes = _pointTypes; 83 bounds = null; 84 } 85 86 public int getNumCoords() { 87 return numCoords; 88 } 89 public void setNumCoords(int numCoords) { 90 this.numCoords = numCoords; 91 bounds = null; 92 } 93 94 public int getNumTypes() { 95 return numTypes; 96 } 97 public void setNumTypes(int numTypes) { 98 this.numTypes = numTypes; 99 bounds = null; 100 } 101 102 public int getSize() { 103 return numTypes; 104 } 105 106 public float[] getPointCoords() { 107 return pointCoords; 108 } 109 public void setPointCoords(float[] pointCoords) { 110 this.pointCoords = pointCoords; 111 bounds = null; 112 } 113 115 static final int INIT_SIZE = 20; 116 static final int EXPAND_MAX = 500; 117 118 125 public GeneralShape() { 126 this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE); 127 } 128 129 137 public GeneralShape(int rule) { 138 this(rule, INIT_SIZE, INIT_SIZE); 139 } 140 141 153 public GeneralShape(int rule, int initialCapacity) { 154 this(rule, initialCapacity, initialCapacity); 155 } 156 157 172 GeneralShape(int rule, int initialTypes, int initialCoords) { 173 setWindingRule(rule); 174 pointTypes = new byte[initialTypes]; 175 pointCoords = new float[initialCoords * 2]; 176 } 177 178 185 public GeneralShape(Shape s) { 186 this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE); 187 PathIterator pi = s.getPathIterator(null); 188 setWindingRule(pi.getWindingRule()); 189 append(pi, false); 190 } 191 192 private void needRoom(int newTypes, int newCoords, boolean needMove) { 193 if (needMove && numTypes == 0) { 194 throw new IllegalPathStateException ("missing initial moveto "+ 195 "in path definition"); 196 } 197 int size = pointCoords.length; 198 if (numCoords + newCoords > size) { 199 int grow = size; 200 if (grow > EXPAND_MAX * 2) { 201 grow = EXPAND_MAX * 2; 202 } 203 if (grow < newCoords) { 204 grow = newCoords; 205 } 206 float[] arr = new float[size + grow]; 207 System.arraycopy(pointCoords, 0, arr, 0, numCoords); 208 pointCoords = arr; 209 } 210 size = pointTypes.length; 211 if (numTypes + newTypes > size) { 212 int grow = size; 213 if (grow > EXPAND_MAX) { 214 grow = EXPAND_MAX; 215 } 216 if (grow < newTypes) { 217 grow = newTypes; 218 } 219 byte[] arr = new byte[size + grow]; 220 System.arraycopy(pointTypes, 0, arr, 0, numTypes); 221 pointTypes = arr; 222 } 223 } 224 225 230 public synchronized void moveTo(float x, float y) { 231 if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) { 232 pointCoords[numCoords - 2] = x; 233 pointCoords[numCoords - 1] = y; 234 } else { 235 needRoom(1, 2, false); 236 pointTypes[numTypes++] = SEG_MOVETO; 237 pointCoords[numCoords++] = x; 238 pointCoords[numCoords++] = y; 239 } 240 pathSegments = null; 241 } 242 243 248 public synchronized void lineTo(float x, float y) { 249 needRoom(1, 2, true); 250 pointTypes[numTypes++] = SEG_LINETO; 251 pointCoords[numCoords++] = x; 252 pointCoords[numCoords++] = y; 253 pathSegments = null; 254 bounds = null; 255 } 256 257 267 public synchronized void quadTo(float x1, float y1, float x2, float y2) { 268 needRoom(1, 4, true); 269 pointTypes[numTypes++] = SEG_QUADTO; 270 pointCoords[numCoords++] = x1; 271 pointCoords[numCoords++] = y1; 272 pointCoords[numCoords++] = x2; 273 pointCoords[numCoords++] = y2; 274 pathSegments = null; 275 bounds = null; 276 } 277 278 290 public synchronized void curveTo(float x1, float y1, 291 float x2, float y2, 292 float x3, float y3) { 293 needRoom(1, 6, true); 294 pointTypes[numTypes++] = SEG_CUBICTO; 295 pointCoords[numCoords++] = x1; 296 pointCoords[numCoords++] = y1; 297 pointCoords[numCoords++] = x2; 298 pointCoords[numCoords++] = y2; 299 pointCoords[numCoords++] = x3; 300 pointCoords[numCoords++] = y3; 301 pathSegments = null; 302 bounds = null; 303 } 304 305 310 public synchronized void closePath() 311 { 312 if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) { 313 needRoom(1, 0, true); 314 pointTypes[numTypes++] = SEG_CLOSE; 315 } 316 bounds = null; 317 } 318 319 339 public void append(Shape s, boolean connect) { 340 PathIterator pi = s.getPathIterator(null); 341 append(pi,connect); 342 } 343 344 365 public void append(PathIterator pi, boolean connect) { 366 float coords[] = new float[6]; 367 while (!pi.isDone()) { 368 switch (pi.currentSegment(coords)) { 369 case SEG_MOVETO: 370 if (!connect || numTypes < 1 || numCoords < 2) { 371 moveTo(coords[0], coords[1]); 372 break; 373 } 374 if (pointTypes[numTypes - 1] != SEG_CLOSE && 375 pointCoords[numCoords - 2] == coords[0] && 376 pointCoords[numCoords - 1] == coords[1]) 377 { 378 break; 380 } 381 case SEG_LINETO: 383 lineTo(coords[0], coords[1]); 384 break; 385 case SEG_QUADTO: 386 quadTo(coords[0], coords[1], 387 coords[2], coords[3]); 388 break; 389 case SEG_CUBICTO: 390 curveTo(coords[0], coords[1], 391 coords[2], coords[3], 392 coords[4], coords[5]); 393 break; 394 case SEG_CLOSE: 395 closePath(); 396 break; 397 } 398 pi.next(); 399 connect = false; 400 } 401 pathSegments = null; 402 bounds = null; 403 } 404 405 412 public synchronized int getWindingRule() { 413 return windingRule; 414 } 415 416 428 public void setWindingRule(int rule) { 429 if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) { 430 throw new IllegalArgumentException ("winding rule must be "+ 431 "WIND_EVEN_ODD or "+ 432 "WIND_NON_ZERO"); 433 } 434 windingRule = rule; 435 } 436 437 444 public synchronized Point2D getCurrentPoint() { 445 if (numTypes < 1 || numCoords < 2) { 446 return null; 447 } 448 int index = numCoords; 449 if (pointTypes[numTypes - 1] == SEG_CLOSE) { 450 loop: 451 for (int i = numTypes - 2; i > 0; i--) { 452 switch (pointTypes[i]) { 453 case SEG_MOVETO: 454 break loop; 455 case SEG_LINETO: 456 index -= 2; 457 break; 458 case SEG_QUADTO: 459 index -= 4; 460 break; 461 case SEG_CUBICTO: 462 index -= 6; 463 break; 464 case SEG_CLOSE: 465 break; 466 } 467 } 468 } 469 return new Point2D.Float (pointCoords[index - 2], 470 pointCoords[index - 1]); 471 } 472 473 478 public synchronized void reset() { 479 numTypes = numCoords = 0; 480 bounds = null; 481 } 482 483 491 protected List transformListeners; 492 public void addTransformListener(TransformListener listener) 493 { 494 if (transformListeners == null) 495 transformListeners = new ArrayList (); 496 497 transformListeners.add(listener); 498 } 499 public void removeTransformListener(TransformListener listener) 500 { 501 if (transformListeners == null) 502 transformListeners = new ArrayList (); 503 504 transformListeners.remove(listener); 505 } 506 507 protected void fireTransformChanged(AffineTransform _at) 508 { 509 if (transformListeners == null) 510 return; 511 512 for (Iterator it = transformListeners.iterator(); it.hasNext(); ) 513 { 514 TransformListener listener = (TransformListener) it.next(); 515 listener.transformChanged(_at); 516 } 517 } 518 519 526 public void transform(AffineTransform at) 527 { 528 at.transform(pointCoords, 0, pointCoords, 0, numCoords / 2); 529 pathSegments = null; 530 bounds = null; 531 fireTransformChanged(at); 532 } 533 534 541 public synchronized Shape createTransformedShape(AffineTransform at) { 542 GeneralShape gp = (GeneralShape) clone(); 543 if (at != null) { 544 gp.transform(at); 545 } 546 return gp; 547 } 548 549 554 public java.awt.Rectangle getBounds() { 555 return getBounds2D().getBounds(); 556 } 557 558 protected Rectangle2D bounds; 559 560 565 public synchronized Rectangle2D getBounds2D() 566 { 567 if (bounds == null) 568 { 569 float x1, y1, x2, y2; 570 int i = numCoords; 571 if (i > 0) { 572 y1 = y2 = pointCoords[--i]; 573 x1 = x2 = pointCoords[--i]; 574 while (i > 0) { 575 float y = pointCoords[--i]; 576 float x = pointCoords[--i]; 577 if (x < x1) x1 = x; 578 if (y < y1) y1 = y; 579 if (x > x2) x2 = x; 580 if (y > y2) y2 = y; 581 } 582 } else { 583 x1 = y1 = x2 = y2 = 0.0f; 584 } 585 return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1); 586 } 587 else 588 return bounds; 589 } 590 591 598 public boolean contains(double x, double y) { 599 if (numTypes < 2) { 600 return false; 601 } 602 int cross = Curve.crossingsForPath(getPathIterator(null), x, y); 603 if (windingRule == WIND_NON_ZERO) { 604 return (cross != 0); 605 } else { 606 return ((cross & 1) != 0); 607 } 608 } 609 610 617 public boolean contains(Point2D p) { 618 return contains(p.getX(), p.getY()); 619 } 620 621 630 public boolean contains(double x, double y, double w, double h) { 631 Crossings c = Crossings.findCrossings(getPathIterator(null), 632 x, y, x+w, y+h); 633 return (c != null && c.covers(y, y+h)); 634 } 635 636 643 public boolean contains(Rectangle2D r) { 644 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 645 } 646 647 657 public boolean intersects(double x, double y, double w, double h) { 658 Crossings c = Crossings.findCrossings(getPathIterator(null), 659 x, y, x+w, y+h); 660 return (c == null || !c.isEmpty()); 661 } 662 663 671 public boolean intersects(Rectangle2D r) { 672 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 673 } 674 675 689 public PathIterator getPathIterator(AffineTransform at) { 690 return new GeneralShapeIterator(this, at); 691 } 692 693 709 public PathIterator getPathIterator(AffineTransform at, double flatness) { 710 return new FlatteningPathIterator (getPathIterator(at), flatness); 711 } 712 713 721 public Object clone() 722 { 723 int pointTypesLength = this.pointTypes.length; 726 byte[] copyPointTypes = new byte[pointTypesLength]; 727 System.arraycopy(pointTypes, 0, copyPointTypes, 0, pointTypesLength); 731 int pointCoordsLength = this.pointCoords.length; 732 float[] copyPointCoords = new float[pointCoordsLength]; 733 System.arraycopy(pointCoords, 0, copyPointCoords, 0, pointCoordsLength); 737 GeneralShape copy = new GeneralShape(); 739 copy.windingRule = this.windingRule; 740 copy.numTypes = this.numTypes; 741 copy.pointTypes = copyPointTypes; 742 copy.numCoords = this.numCoords; 743 copy.pointCoords = copyPointCoords; 744 return copy; 745 } 751 752 GeneralShape(int windingRule, 753 byte[] pointTypes, 754 int numTypes, 755 float[] pointCoords, 756 int numCoords) 757 { 758 this.windingRule = windingRule; 760 this.pointTypes = pointTypes; 761 this.numTypes = numTypes; 762 this.pointCoords = pointCoords; 763 this.numCoords = numCoords; 764 } 765 766 public boolean equals(Object o) 767 { 768 if (o instanceof GeneralShape) 769 { 770 GeneralShape gs = (GeneralShape) o; 771 772 if (this.windingRule != gs.getWindingRule()) 774 return false; 775 776 if (this.numCoords != gs.getNumCoords()) 778 return false; 779 780 if (this.numTypes != gs.getNumTypes()) 782 return false; 783 784 if (this.pointCoords.length != gs.getPointCoords().length) { 786 return false; 787 } 788 else { 789 float[] gsPointCoords = gs.getPointCoords(); 790 for (int i=0; i<pointCoords.length; i++) { 791 float f = pointCoords[i]; 792 if (f != gsPointCoords[i]) 793 return false; 794 } 795 } 796 797 if (this.pointTypes.length != gs.pointTypes.length) { 799 return false; 800 } 801 else { 802 byte[] gsPointTypes = gs.getPointTypes(); 803 for (int i=0; i<pointTypes.length; i++) { 804 byte b = pointTypes[i]; 805 if (b != gsPointTypes[i]) 806 return false; 807 } 808 } 809 810 } else { 812 return false; 813 } 814 return true; 815 } 816 817 824 public synchronized void setLastPoint(float x, float y) 825 { 827 if (numTypes < 1 || numCoords < 2) { 828 return; 829 } 830 int index = numCoords; 831 if (pointTypes[numTypes - 1] == PathIterator.SEG_CLOSE) { 832 loop: 833 for (int i = numTypes - 2; i > 0; i--) { 834 switch (pointTypes[i]) { 835 case PathIterator.SEG_MOVETO: 836 break loop; 837 case PathIterator.SEG_LINETO: 838 index -= 2; 839 break; 840 case PathIterator.SEG_QUADTO: 841 index -= 4; 842 break; 843 case PathIterator.SEG_CUBICTO: 844 index -= 6; 845 break; 846 case PathIterator.SEG_CLOSE: 847 break; 848 } 849 } 850 } 851 pointCoords[index - 2] = x; 852 pointCoords[index - 1] = y; 853 bounds = null; 854 } 855 856 public synchronized void setPathSegment(int type, int index, float[] coords) 857 { 858 System.out.println("GeneralShape.setPathSegment"); 860 switch (type) 861 { 862 case (PathIterator.SEG_MOVETO): 863 pointCoords[index] = coords[0]; 864 pointCoords[index+1] = coords[1]; 865 break; 866 case (PathIterator.SEG_LINETO): 867 pointCoords[index] = coords[0]; 868 pointCoords[index+1] = coords[1]; 869 break; 870 case (PathIterator.SEG_QUADTO): 871 pointCoords[index] = coords[0]; 872 pointCoords[index+1] = coords[1]; 873 pointCoords[index+2] = coords[2]; 874 pointCoords[index+3] = coords[3]; 875 break; 876 case (PathIterator.SEG_CUBICTO): 877 pointCoords[index] = coords[0]; 878 pointCoords[index+1] = coords[1]; 879 pointCoords[index+2] = coords[2]; 880 pointCoords[index+3] = coords[3]; 881 pointCoords[index+4] = coords[4]; 882 pointCoords[index+5] = coords[5]; 883 break; 884 } 885 bounds = null; 886 } 887 888 905 931 949 protected void initPathSegments() 950 { 951 pathSegments = new ArrayList (); 952 int index = 0; 953 float[] coords = new float[6]; 954 for (PathIterator pi = getPathIterator(null); !pi.isDone(); pi.next()) 955 { 956 int segType = pi.currentSegment(coords); 957 switch (segType) 958 { 959 case (PathIterator.SEG_MOVETO): 960 PathSegment ps = new PathSegment(segType, index, coords, this); 961 pathSegments.add(ps); 962 index = index + 2; 963 break; 964 case (PathIterator.SEG_LINETO): 965 PathSegment ps1 = new PathSegment(segType, index, coords, this); 966 pathSegments.add(ps1); 967 index = index + 2; 968 break; 969 case (PathIterator.SEG_QUADTO): 970 PathSegment ps2 = new PathSegment(segType, index, coords, this); 971 pathSegments.add(ps2); 972 index = index + 4; 973 break; 974 case (PathIterator.SEG_CUBICTO): 975 PathSegment ps3 = new PathSegment(segType, index, coords, this); 976 pathSegments.add(ps3); 977 index = index + 6; 978 break; 979 case (PathIterator.SEG_CLOSE): 980 break; 984 } 985 } 986 } 987 988 protected List pathSegments; 989 990 public List getPathSegments() 991 { 992 if (pathSegments == null) 993 initPathSegments(); 994 995 return pathSegments; 996 } 997 998 public PathSegment getPathSegment(int index) 999 { 1000 if (pathSegments == null) 1001 initPathSegments(); 1002 1003 return (PathSegment) pathSegments.get(index); 1004 } 1005 1006 public PathSegment getPathSegmentAt(int x, int y) 1007 { 1008 for (Iterator it = getPathSegments().iterator(); it.hasNext(); ) { 1009 PathSegment ps = (PathSegment) it.next(); 1010 int contains = ps.contains(x,y); 1011 if (contains != PathSegment.NO_POINT) 1012 return ps; 1013 } 1014 return null; 1015 } 1016 1017 1029 public int getPointCount() 1030 { 1031 int counter = 0; 1032 for (PathIterator pi = getPathIterator(null); !pi.isDone(); pi.next()) { 1033 counter++; 1034 } 1035 return counter; 1036 } 1037 1038} 1039 1040
| Popular Tags
|