1 7 8 package java.awt.geom; 9 10 import java.awt.Shape ; 11 import java.awt.Rectangle ; 12 import sun.awt.geom.Curve; 13 import java.io.Serializable ; 14 import java.io.StreamCorruptedException ; 15 import java.util.Arrays ; 16 17 53 public abstract class Path2D implements Shape , Cloneable { 54 61 public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; 62 63 70 public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; 71 72 private static final byte SEG_MOVETO = (byte) PathIterator.SEG_MOVETO; 75 private static final byte SEG_LINETO = (byte) PathIterator.SEG_LINETO; 76 private static final byte SEG_QUADTO = (byte) PathIterator.SEG_QUADTO; 77 private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO; 78 private static final byte SEG_CLOSE = (byte) PathIterator.SEG_CLOSE; 79 80 transient byte[] pointTypes; 81 transient int numTypes; 82 transient int numCoords; 83 transient int windingRule; 84 85 static final int INIT_SIZE = 20; 86 static final int EXPAND_MAX = 500; 87 88 95 96 Path2D() { 97 } 98 99 111 112 Path2D(int rule, int initialTypes) { 113 setWindingRule(rule); 114 this.pointTypes = new byte[initialTypes]; 115 } 116 117 abstract float[] cloneCoordsFloat(AffineTransform at); 118 abstract double[] cloneCoordsDouble(AffineTransform at); 119 abstract void append(float x, float y); 120 abstract void append(double x, double y); 121 abstract Point2D getPoint(int coordindex); 122 abstract void needRoom(boolean needMove, int newCoords); 123 abstract int pointCrossings(double px, double py); 124 abstract int rectCrossings(double rxmin, double rymin, 125 double rxmax, double rymax); 126 127 133 public static class Float extends Path2D implements Serializable { 134 transient float floatCoords[]; 135 136 142 public Float() { 143 this(WIND_NON_ZERO, INIT_SIZE); 144 } 145 146 156 public Float(int rule) { 157 this(rule, INIT_SIZE); 158 } 159 160 175 public Float(int rule, int initialCapacity) { 176 super(rule, initialCapacity); 177 floatCoords = new float[initialCapacity * 2]; 178 } 179 180 189 public Float(Shape s) { 190 this(s, null); 191 } 192 193 205 public Float(Shape s, AffineTransform at) { 206 if (s instanceof Path2D ) { 207 Path2D p2d = (Path2D ) s; 208 setWindingRule(p2d.windingRule); 209 this.numTypes = p2d.numTypes; 210 this.pointTypes = Arrays.copyOf(p2d.pointTypes, 211 p2d.pointTypes.length); 212 this.numCoords = p2d.numCoords; 213 this.floatCoords = p2d.cloneCoordsFloat(at); 214 } else { 215 PathIterator pi = s.getPathIterator(at); 216 setWindingRule(pi.getWindingRule()); 217 this.pointTypes = new byte[INIT_SIZE]; 218 this.floatCoords = new float[INIT_SIZE * 2]; 219 append(pi, false); 220 } 221 } 222 223 float[] cloneCoordsFloat(AffineTransform at) { 224 float ret[]; 225 if (at == null) { 226 ret = Arrays.copyOf(this.floatCoords, this.floatCoords.length); 227 } else { 228 ret = new float[floatCoords.length]; 229 at.transform(floatCoords, 0, ret, 0, numCoords / 2); 230 } 231 return ret; 232 } 233 234 double[] cloneCoordsDouble(AffineTransform at) { 235 double ret[] = new double[floatCoords.length]; 236 if (at == null) { 237 for (int i = 0; i < numCoords; i++) { 238 ret[i] = floatCoords[i]; 239 } 240 } else { 241 at.transform(floatCoords, 0, ret, 0, numCoords / 2); 242 } 243 return ret; 244 } 245 246 void append(float x, float y) { 247 floatCoords[numCoords++] = x; 248 floatCoords[numCoords++] = y; 249 } 250 251 void append(double x, double y) { 252 floatCoords[numCoords++] = (float) x; 253 floatCoords[numCoords++] = (float) y; 254 } 255 256 Point2D getPoint(int coordindex) { 257 return new Point2D.Float (floatCoords[coordindex], 258 floatCoords[coordindex+1]); 259 } 260 261 void needRoom(boolean needMove, int newCoords) { 262 if (needMove && numTypes == 0) { 263 throw new IllegalPathStateException ("missing initial moveto "+ 264 "in path definition"); 265 } 266 int size = pointTypes.length; 267 if (numTypes >= size) { 268 int grow = size; 269 if (grow > EXPAND_MAX) { 270 grow = EXPAND_MAX; 271 } 272 pointTypes = Arrays.copyOf(pointTypes, size+grow); 273 } 274 size = floatCoords.length; 275 if (numCoords + newCoords > size) { 276 int grow = size; 277 if (grow > EXPAND_MAX * 2) { 278 grow = EXPAND_MAX * 2; 279 } 280 if (grow < newCoords) { 281 grow = newCoords; 282 } 283 floatCoords = Arrays.copyOf(floatCoords, size+grow); 284 } 285 } 286 287 291 public final synchronized void moveTo(double x, double y) { 292 if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) { 293 floatCoords[numCoords-2] = (float) x; 294 floatCoords[numCoords-1] = (float) y; 295 } else { 296 needRoom(false, 2); 297 pointTypes[numTypes++] = SEG_MOVETO; 298 floatCoords[numCoords++] = (float) x; 299 floatCoords[numCoords++] = (float) y; 300 } 301 } 302 303 316 public final synchronized void moveTo(float x, float y) { 317 if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) { 318 floatCoords[numCoords-2] = x; 319 floatCoords[numCoords-1] = y; 320 } else { 321 needRoom(false, 2); 322 pointTypes[numTypes++] = SEG_MOVETO; 323 floatCoords[numCoords++] = x; 324 floatCoords[numCoords++] = y; 325 } 326 } 327 328 332 public final synchronized void lineTo(double x, double y) { 333 needRoom(true, 2); 334 pointTypes[numTypes++] = SEG_LINETO; 335 floatCoords[numCoords++] = (float) x; 336 floatCoords[numCoords++] = (float) y; 337 } 338 339 353 public final synchronized void lineTo(float x, float y) { 354 needRoom(true, 2); 355 pointTypes[numTypes++] = SEG_LINETO; 356 floatCoords[numCoords++] = x; 357 floatCoords[numCoords++] = y; 358 } 359 360 364 public final synchronized void quadTo(double x1, double y1, 365 double x2, double y2) 366 { 367 needRoom(true, 4); 368 pointTypes[numTypes++] = SEG_QUADTO; 369 floatCoords[numCoords++] = (float) x1; 370 floatCoords[numCoords++] = (float) y1; 371 floatCoords[numCoords++] = (float) x2; 372 floatCoords[numCoords++] = (float) y2; 373 } 374 375 394 public final synchronized void quadTo(float x1, float y1, 395 float x2, float y2) 396 { 397 needRoom(true, 4); 398 pointTypes[numTypes++] = SEG_QUADTO; 399 floatCoords[numCoords++] = x1; 400 floatCoords[numCoords++] = y1; 401 floatCoords[numCoords++] = x2; 402 floatCoords[numCoords++] = y2; 403 } 404 405 409 public final synchronized void curveTo(double x1, double y1, 410 double x2, double y2, 411 double x3, double y3) 412 { 413 needRoom(true, 6); 414 pointTypes[numTypes++] = SEG_CUBICTO; 415 floatCoords[numCoords++] = (float) x1; 416 floatCoords[numCoords++] = (float) y1; 417 floatCoords[numCoords++] = (float) x2; 418 floatCoords[numCoords++] = (float) y2; 419 floatCoords[numCoords++] = (float) x3; 420 floatCoords[numCoords++] = (float) y3; 421 } 422 423 444 public final synchronized void curveTo(float x1, float y1, 445 float x2, float y2, 446 float x3, float y3) 447 { 448 needRoom(true, 6); 449 pointTypes[numTypes++] = SEG_CUBICTO; 450 floatCoords[numCoords++] = x1; 451 floatCoords[numCoords++] = y1; 452 floatCoords[numCoords++] = x2; 453 floatCoords[numCoords++] = y2; 454 floatCoords[numCoords++] = x3; 455 floatCoords[numCoords++] = y3; 456 } 457 458 int pointCrossings(double px, double py) { 459 double movx, movy, curx, cury, endx, endy; 460 float coords[] = floatCoords; 461 curx = movx = coords[0]; 462 cury = movy = coords[1]; 463 int crossings = 0; 464 int ci = 2; 465 for (int i = 1; i < numTypes; i++) { 466 switch (pointTypes[i]) { 467 case PathIterator.SEG_MOVETO: 468 if (cury != movy) { 469 crossings += 470 Curve.pointCrossingsForLine(px, py, 471 curx, cury, 472 movx, movy); 473 } 474 movx = curx = coords[ci++]; 475 movy = cury = coords[ci++]; 476 break; 477 case PathIterator.SEG_LINETO: 478 crossings += 479 Curve.pointCrossingsForLine(px, py, 480 curx, cury, 481 endx = coords[ci++], 482 endy = coords[ci++]); 483 curx = endx; 484 cury = endy; 485 break; 486 case PathIterator.SEG_QUADTO: 487 crossings += 488 Curve.pointCrossingsForQuad(px, py, 489 curx, cury, 490 coords[ci++], 491 coords[ci++], 492 endx = coords[ci++], 493 endy = coords[ci++], 494 0); 495 curx = endx; 496 cury = endy; 497 break; 498 case PathIterator.SEG_CUBICTO: 499 crossings += 500 Curve.pointCrossingsForCubic(px, py, 501 curx, cury, 502 coords[ci++], 503 coords[ci++], 504 coords[ci++], 505 coords[ci++], 506 endx = coords[ci++], 507 endy = coords[ci++], 508 0); 509 curx = endx; 510 cury = endy; 511 break; 512 case PathIterator.SEG_CLOSE: 513 if (cury != movy) { 514 crossings += 515 Curve.pointCrossingsForLine(px, py, 516 curx, cury, 517 movx, movy); 518 } 519 curx = movx; 520 cury = movy; 521 break; 522 } 523 } 524 if (cury != movy) { 525 crossings += 526 Curve.pointCrossingsForLine(px, py, 527 curx, cury, 528 movx, movy); 529 } 530 return crossings; 531 } 532 533 int rectCrossings(double rxmin, double rymin, 534 double rxmax, double rymax) 535 { 536 float coords[] = floatCoords; 537 double curx, cury, movx, movy, endx, endy; 538 curx = movx = coords[0]; 539 cury = movy = coords[1]; 540 int crossings = 0; 541 int ci = 2; 542 for (int i = 1; 543 crossings != Curve.RECT_INTERSECTS && i < numTypes; 544 i++) 545 { 546 switch (pointTypes[i]) { 547 case PathIterator.SEG_MOVETO: 548 if (curx != movx || cury != movy) { 549 crossings = 550 Curve.rectCrossingsForLine(crossings, 551 rxmin, rymin, 552 rxmax, rymax, 553 curx, cury, 554 movx, movy); 555 } 556 movx = curx = coords[ci++]; 559 movy = cury = coords[ci++]; 560 break; 561 case PathIterator.SEG_LINETO: 562 crossings = 563 Curve.rectCrossingsForLine(crossings, 564 rxmin, rymin, 565 rxmax, rymax, 566 curx, cury, 567 endx = coords[ci++], 568 endy = coords[ci++]); 569 curx = endx; 570 cury = endy; 571 break; 572 case PathIterator.SEG_QUADTO: 573 crossings = 574 Curve.rectCrossingsForQuad(crossings, 575 rxmin, rymin, 576 rxmax, rymax, 577 curx, cury, 578 coords[ci++], 579 coords[ci++], 580 endx = coords[ci++], 581 endy = coords[ci++], 582 0); 583 curx = endx; 584 cury = endy; 585 break; 586 case PathIterator.SEG_CUBICTO: 587 crossings = 588 Curve.rectCrossingsForCubic(crossings, 589 rxmin, rymin, 590 rxmax, rymax, 591 curx, cury, 592 coords[ci++], 593 coords[ci++], 594 coords[ci++], 595 coords[ci++], 596 endx = coords[ci++], 597 endy = coords[ci++], 598 0); 599 curx = endx; 600 cury = endy; 601 break; 602 case PathIterator.SEG_CLOSE: 603 if (curx != movx || cury != movy) { 604 crossings = 605 Curve.rectCrossingsForLine(crossings, 606 rxmin, rymin, 607 rxmax, rymax, 608 curx, cury, 609 movx, movy); 610 } 611 curx = movx; 612 cury = movy; 613 break; 616 } 617 } 618 if (crossings != Curve.RECT_INTERSECTS && 619 (curx != movx || cury != movy)) 620 { 621 crossings = 622 Curve.rectCrossingsForLine(crossings, 623 rxmin, rymin, 624 rxmax, rymax, 625 curx, cury, 626 movx, movy); 627 } 628 return crossings; 631 } 632 633 637 public final void append(PathIterator pi, boolean connect) { 638 float coords[] = new float[6]; 639 while (!pi.isDone()) { 640 switch (pi.currentSegment(coords)) { 641 case SEG_MOVETO: 642 if (!connect || numTypes < 1 || numCoords < 1) { 643 moveTo(coords[0], coords[1]); 644 break; 645 } 646 if (pointTypes[numTypes - 1] != SEG_CLOSE && 647 floatCoords[numCoords-2] == coords[0] && 648 floatCoords[numCoords-1] == coords[1]) 649 { 650 break; 652 } 653 case SEG_LINETO: 655 lineTo(coords[0], coords[1]); 656 break; 657 case SEG_QUADTO: 658 quadTo(coords[0], coords[1], 659 coords[2], coords[3]); 660 break; 661 case SEG_CUBICTO: 662 curveTo(coords[0], coords[1], 663 coords[2], coords[3], 664 coords[4], coords[5]); 665 break; 666 case SEG_CLOSE: 667 closePath(); 668 break; 669 } 670 pi.next(); 671 connect = false; 672 } 673 } 674 675 679 public final void transform(AffineTransform at) { 680 at.transform(floatCoords, 0, floatCoords, 0, numCoords / 2); 681 } 682 683 687 public final synchronized Rectangle2D getBounds2D() { 688 float x1, y1, x2, y2; 689 int i = numCoords; 690 if (i > 0) { 691 y1 = y2 = floatCoords[--i]; 692 x1 = x2 = floatCoords[--i]; 693 while (i > 0) { 694 float y = floatCoords[--i]; 695 float x = floatCoords[--i]; 696 if (x < x1) x1 = x; 697 if (y < y1) y1 = y; 698 if (x > x2) x2 = x; 699 if (y > y2) y2 = y; 700 } 701 } else { 702 x1 = y1 = x2 = y2 = 0.0f; 703 } 704 return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1); 705 } 706 707 718 public PathIterator getPathIterator(AffineTransform at) { 719 if (at == null) { 720 return new CopyIterator(this); 721 } else { 722 return new TxIterator(this, at); 723 } 724 } 725 726 734 public final Object clone() { 735 if (this instanceof GeneralPath ) { 741 return new GeneralPath (this); 742 } else { 743 return new Path2D.Float (this); 744 } 745 } 746 747 750 private static final long serialVersionUID = 6990832515060788886L; 751 752 873 private void writeObject(java.io.ObjectOutputStream s) 874 throws java.io.IOException 875 { 876 super.writeObject(s, false); 877 } 878 879 892 private void readObject(java.io.ObjectInputStream s) 893 throws java.lang.ClassNotFoundException , java.io.IOException 894 { 895 super.readObject(s, false); 896 } 897 898 static class CopyIterator extends Path2D.Iterator { 899 float floatCoords[]; 900 901 CopyIterator(Path2D.Float p2df) { 902 super(p2df); 903 this.floatCoords = p2df.floatCoords; 904 } 905 906 public int currentSegment(float[] coords) { 907 int type = path.pointTypes[typeIdx]; 908 int numCoords = curvecoords[type]; 909 if (numCoords > 0) { 910 System.arraycopy(floatCoords, pointIdx, 911 coords, 0, numCoords); 912 } 913 return type; 914 } 915 916 public int currentSegment(double[] coords) { 917 int type = path.pointTypes[typeIdx]; 918 int numCoords = curvecoords[type]; 919 if (numCoords > 0) { 920 for (int i = 0; i < numCoords; i++) { 921 coords[i] = floatCoords[pointIdx + i]; 922 } 923 } 924 return type; 925 } 926 } 927 928 static class TxIterator extends Path2D.Iterator { 929 float floatCoords[]; 930 AffineTransform affine; 931 932 TxIterator(Path2D.Float p2df, AffineTransform at) { 933 super(p2df); 934 this.floatCoords = p2df.floatCoords; 935 this.affine = at; 936 } 937 938 public int currentSegment(float[] coords) { 939 int type = path.pointTypes[typeIdx]; 940 int numCoords = curvecoords[type]; 941 if (numCoords > 0) { 942 affine.transform(floatCoords, pointIdx, 943 coords, 0, numCoords / 2); 944 } 945 return type; 946 } 947 948 public int currentSegment(double[] coords) { 949 int type = path.pointTypes[typeIdx]; 950 int numCoords = curvecoords[type]; 951 if (numCoords > 0) { 952 affine.transform(floatCoords, pointIdx, 953 coords, 0, numCoords / 2); 954 } 955 return type; 956 } 957 } 958 959 } 960 961 967 public static class Double extends Path2D implements Serializable { 968 transient double doubleCoords[]; 969 970 976 public Double() { 977 this(WIND_NON_ZERO, INIT_SIZE); 978 } 979 980 990 public Double(int rule) { 991 this(rule, INIT_SIZE); 992 } 993 994 1009 public Double(int rule, int initialCapacity) { 1010 super(rule, initialCapacity); 1011 doubleCoords = new double[initialCapacity * 2]; 1012 } 1013 1014 1023 public Double(Shape s) { 1024 this(s, null); 1025 } 1026 1027 1039 public Double(Shape s, AffineTransform at) { 1040 if (s instanceof Path2D ) { 1041 Path2D p2d = (Path2D ) s; 1042 setWindingRule(p2d.windingRule); 1043 this.numTypes = p2d.numTypes; 1044 this.pointTypes = Arrays.copyOf(p2d.pointTypes, 1045 p2d.pointTypes.length); 1046 this.numCoords = p2d.numCoords; 1047 this.doubleCoords = p2d.cloneCoordsDouble(at); 1048 } else { 1049 PathIterator pi = s.getPathIterator(at); 1050 setWindingRule(pi.getWindingRule()); 1051 this.pointTypes = new byte[INIT_SIZE]; 1052 this.doubleCoords = new double[INIT_SIZE * 2]; 1053 append(pi, false); 1054 } 1055 } 1056 1057 float[] cloneCoordsFloat(AffineTransform at) { 1058 float ret[] = new float[doubleCoords.length]; 1059 if (at == null) { 1060 for (int i = 0; i < numCoords; i++) { 1061 ret[i] = (float) doubleCoords[i]; 1062 } 1063 } else { 1064 at.transform(doubleCoords, 0, ret, 0, numCoords / 2); 1065 } 1066 return ret; 1067 } 1068 1069 double[] cloneCoordsDouble(AffineTransform at) { 1070 double ret[]; 1071 if (at == null) { 1072 ret = Arrays.copyOf(this.doubleCoords, 1073 this.doubleCoords.length); 1074 } else { 1075 ret = new double[doubleCoords.length]; 1076 at.transform(doubleCoords, 0, ret, 0, numCoords / 2); 1077 } 1078 return ret; 1079 } 1080 1081 void append(float x, float y) { 1082 doubleCoords[numCoords++] = x; 1083 doubleCoords[numCoords++] = y; 1084 } 1085 1086 void append(double x, double y) { 1087 doubleCoords[numCoords++] = x; 1088 doubleCoords[numCoords++] = y; 1089 } 1090 1091 Point2D getPoint(int coordindex) { 1092 return new Point2D.Double (doubleCoords[coordindex], 1093 doubleCoords[coordindex+1]); 1094 } 1095 1096 void needRoom(boolean needMove, int newCoords) { 1097 if (needMove && numTypes == 0) { 1098 throw new IllegalPathStateException ("missing initial moveto "+ 1099 "in path definition"); 1100 } 1101 int size = pointTypes.length; 1102 if (numTypes >= size) { 1103 int grow = size; 1104 if (grow > EXPAND_MAX) { 1105 grow = EXPAND_MAX; 1106 } 1107 pointTypes = Arrays.copyOf(pointTypes, size+grow); 1108 } 1109 size = doubleCoords.length; 1110 if (numCoords + newCoords > size) { 1111 int grow = size; 1112 if (grow > EXPAND_MAX * 2) { 1113 grow = EXPAND_MAX * 2; 1114 } 1115 if (grow < newCoords) { 1116 grow = newCoords; 1117 } 1118 doubleCoords = Arrays.copyOf(doubleCoords, size+grow); 1119 } 1120 } 1121 1122 1126 public final synchronized void moveTo(double x, double y) { 1127 if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) { 1128 doubleCoords[numCoords-2] = x; 1129 doubleCoords[numCoords-1] = y; 1130 } else { 1131 needRoom(false, 2); 1132 pointTypes[numTypes++] = SEG_MOVETO; 1133 doubleCoords[numCoords++] = x; 1134 doubleCoords[numCoords++] = y; 1135 } 1136 } 1137 1138 1142 public final synchronized void lineTo(double x, double y) { 1143 needRoom(true, 2); 1144 pointTypes[numTypes++] = SEG_LINETO; 1145 doubleCoords[numCoords++] = x; 1146 doubleCoords[numCoords++] = y; 1147 } 1148 1149 1153 public final synchronized void quadTo(double x1, double y1, 1154 double x2, double y2) 1155 { 1156 needRoom(true, 4); 1157 pointTypes[numTypes++] = SEG_QUADTO; 1158 doubleCoords[numCoords++] = x1; 1159 doubleCoords[numCoords++] = y1; 1160 doubleCoords[numCoords++] = x2; 1161 doubleCoords[numCoords++] = y2; 1162 } 1163 1164 1168 public final synchronized void curveTo(double x1, double y1, 1169 double x2, double y2, 1170 double x3, double y3) 1171 { 1172 needRoom(true, 6); 1173 pointTypes[numTypes++] = SEG_CUBICTO; 1174 doubleCoords[numCoords++] = x1; 1175 doubleCoords[numCoords++] = y1; 1176 doubleCoords[numCoords++] = x2; 1177 doubleCoords[numCoords++] = y2; 1178 doubleCoords[numCoords++] = x3; 1179 doubleCoords[numCoords++] = y3; 1180 } 1181 1182 int pointCrossings(double px, double py) { 1183 double movx, movy, curx, cury, endx, endy; 1184 double coords[] = doubleCoords; 1185 curx = movx = coords[0]; 1186 cury = movy = coords[1]; 1187 int crossings = 0; 1188 int ci = 2; 1189 for (int i = 1; i < numTypes; i++) { 1190 switch (pointTypes[i]) { 1191 case PathIterator.SEG_MOVETO: 1192 if (cury != movy) { 1193 crossings += 1194 Curve.pointCrossingsForLine(px, py, 1195 curx, cury, 1196 movx, movy); 1197 } 1198 movx = curx = coords[ci++]; 1199 movy = cury = coords[ci++]; 1200 break; 1201 case PathIterator.SEG_LINETO: 1202 crossings += 1203 Curve.pointCrossingsForLine(px, py, 1204 curx, cury, 1205 endx = coords[ci++], 1206 endy = coords[ci++]); 1207 curx = endx; 1208 cury = endy; 1209 break; 1210 case PathIterator.SEG_QUADTO: 1211 crossings += 1212 Curve.pointCrossingsForQuad(px, py, 1213 curx, cury, 1214 coords[ci++], 1215 coords[ci++], 1216 endx = coords[ci++], 1217 endy = coords[ci++], 1218 0); 1219 curx = endx; 1220 cury = endy; 1221 break; 1222 case PathIterator.SEG_CUBICTO: 1223 crossings += 1224 Curve.pointCrossingsForCubic(px, py, 1225 curx, cury, 1226 coords[ci++], 1227 coords[ci++], 1228 coords[ci++], 1229 coords[ci++], 1230 endx = coords[ci++], 1231 endy = coords[ci++], 1232 0); 1233 curx = endx; 1234 cury = endy; 1235 break; 1236 case PathIterator.SEG_CLOSE: 1237 if (cury != movy) { 1238 crossings += 1239 Curve.pointCrossingsForLine(px, py, 1240 curx, cury, 1241 movx, movy); 1242 } 1243 curx = movx; 1244 cury = movy; 1245 break; 1246 } 1247 } 1248 if (cury != movy) { 1249 crossings += 1250 Curve.pointCrossingsForLine(px, py, 1251 curx, cury, 1252 movx, movy); 1253 } 1254 return crossings; 1255 } 1256 1257 int rectCrossings(double rxmin, double rymin, 1258 double rxmax, double rymax) 1259 { 1260 double coords[] = doubleCoords; 1261 double curx, cury, movx, movy, endx, endy; 1262 curx = movx = coords[0]; 1263 cury = movy = coords[1]; 1264 int crossings = 0; 1265 int ci = 2; 1266 for (int i = 1; 1267 crossings != Curve.RECT_INTERSECTS && i < numTypes; 1268 i++) 1269 { 1270 switch (pointTypes[i]) { 1271 case PathIterator.SEG_MOVETO: 1272 if (curx != movx || cury != movy) { 1273 crossings = 1274 Curve.rectCrossingsForLine(crossings, 1275 rxmin, rymin, 1276 rxmax, rymax, 1277 curx, cury, 1278 movx, movy); 1279 } 1280 movx = curx = coords[ci++]; 1283 movy = cury = coords[ci++]; 1284 break; 1285 case PathIterator.SEG_LINETO: 1286 endx = coords[ci++]; 1287 endy = coords[ci++]; 1288 crossings = 1289 Curve.rectCrossingsForLine(crossings, 1290 rxmin, rymin, 1291 rxmax, rymax, 1292 curx, cury, 1293 endx, endy); 1294 curx = endx; 1295 cury = endy; 1296 break; 1297 case PathIterator.SEG_QUADTO: 1298 crossings = 1299 Curve.rectCrossingsForQuad(crossings, 1300 rxmin, rymin, 1301 rxmax, rymax, 1302 curx, cury, 1303 coords[ci++], 1304 coords[ci++], 1305 endx = coords[ci++], 1306 endy = coords[ci++], 1307 0); 1308 curx = endx; 1309 cury = endy; 1310 break; 1311 case PathIterator.SEG_CUBICTO: 1312 crossings = 1313 Curve.rectCrossingsForCubic(crossings, 1314 rxmin, rymin, 1315 rxmax, rymax, 1316 curx, cury, 1317 coords[ci++], 1318 coords[ci++], 1319 coords[ci++], 1320 coords[ci++], 1321 endx = coords[ci++], 1322 endy = coords[ci++], 1323 0); 1324 curx = endx; 1325 cury = endy; 1326 break; 1327 case PathIterator.SEG_CLOSE: 1328 if (curx != movx || cury != movy) { 1329 crossings = 1330 Curve.rectCrossingsForLine(crossings, 1331 rxmin, rymin, 1332 rxmax, rymax, 1333 curx, cury, 1334 movx, movy); 1335 } 1336 curx = movx; 1337 cury = movy; 1338 break; 1341 } 1342 } 1343 if (crossings != Curve.RECT_INTERSECTS && 1344 (curx != movx || cury != movy)) 1345 { 1346 crossings = 1347 Curve.rectCrossingsForLine(crossings, 1348 rxmin, rymin, 1349 rxmax, rymax, 1350 curx, cury, 1351 movx, movy); 1352 } 1353 return crossings; 1356 } 1357 1358 1362 public final void append(PathIterator pi, boolean connect) { 1363 double coords[] = new double[6]; 1364 while (!pi.isDone()) { 1365 switch (pi.currentSegment(coords)) { 1366 case SEG_MOVETO: 1367 if (!connect || numTypes < 1 || numCoords < 1) { 1368 moveTo(coords[0], coords[1]); 1369 break; 1370 } 1371 if (pointTypes[numTypes - 1] != SEG_CLOSE && 1372 doubleCoords[numCoords-2] == coords[0] && 1373 doubleCoords[numCoords-1] == coords[1]) 1374 { 1375 break; 1377 } 1378 case SEG_LINETO: 1380 lineTo(coords[0], coords[1]); 1381 break; 1382 case SEG_QUADTO: 1383 quadTo(coords[0], coords[1], 1384 coords[2], coords[3]); 1385 break; 1386 case SEG_CUBICTO: 1387 curveTo(coords[0], coords[1], 1388 coords[2], coords[3], 1389 coords[4], coords[5]); 1390 break; 1391 case SEG_CLOSE: 1392 closePath(); 1393 break; 1394 } 1395 pi.next(); 1396 connect = false; 1397 } 1398 } 1399 1400 1404 public final void transform(AffineTransform at) { 1405 at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2); 1406 } 1407 1408 1412 public final synchronized Rectangle2D getBounds2D() { 1413 double x1, y1, x2, y2; 1414 int i = numCoords; 1415 if (i > 0) { 1416 y1 = y2 = doubleCoords[--i]; 1417 x1 = x2 = doubleCoords[--i]; 1418 while (i > 0) { 1419 double y = doubleCoords[--i]; 1420 double x = doubleCoords[--i]; 1421 if (x < x1) x1 = x; 1422 if (y < y1) y1 = y; 1423 if (x > x2) x2 = x; 1424 if (y > y2) y2 = y; 1425 } 1426 } else { 1427 x1 = y1 = x2 = y2 = 0.0; 1428 } 1429 return new Rectangle2D.Double (x1, y1, x2 - x1, y2 - y1); 1430 } 1431 1432 1447 public PathIterator getPathIterator(AffineTransform at) { 1448 if (at == null) { 1449 return new CopyIterator(this); 1450 } else { 1451 return new TxIterator(this, at); 1452 } 1453 } 1454 1455 1463 public final Object clone() { 1464 return new Path2D.Double (this); 1470 } 1471 1472 1475 private static final long serialVersionUID = 1826762518450014216L; 1476 1477 1598 private void writeObject(java.io.ObjectOutputStream s) 1599 throws java.io.IOException 1600 { 1601 super.writeObject(s, true); 1602 } 1603 1604 1617 private void readObject(java.io.ObjectInputStream s) 1618 throws java.lang.ClassNotFoundException , java.io.IOException 1619 { 1620 super.readObject(s, true); 1621 } 1622 1623 static class CopyIterator extends Path2D.Iterator { 1624 double doubleCoords[]; 1625 1626 CopyIterator(Path2D.Double p2dd) { 1627 super(p2dd); 1628 this.doubleCoords = p2dd.doubleCoords; 1629 } 1630 1631 public int currentSegment(float[] coords) { 1632 int type = path.pointTypes[typeIdx]; 1633 int numCoords = curvecoords[type]; 1634 if (numCoords > 0) { 1635 for (int i = 0; i < numCoords; i++) { 1636 coords[i] = (float) doubleCoords[pointIdx + i]; 1637 } 1638 } 1639 return type; 1640 } 1641 1642 public int currentSegment(double[] coords) { 1643 int type = path.pointTypes[typeIdx]; 1644 int numCoords = curvecoords[type]; 1645 if (numCoords > 0) { 1646 System.arraycopy(doubleCoords, pointIdx, 1647 coords, 0, numCoords); 1648 } 1649 return type; 1650 } 1651 } 1652 1653 static class TxIterator extends Path2D.Iterator { 1654 double doubleCoords[]; 1655 AffineTransform affine; 1656 1657 TxIterator(Path2D.Double p2dd, AffineTransform at) { 1658 super(p2dd); 1659 this.doubleCoords = p2dd.doubleCoords; 1660 this.affine = at; 1661 } 1662 1663 public int currentSegment(float[] coords) { 1664 int type = path.pointTypes[typeIdx]; 1665 int numCoords = curvecoords[type]; 1666 if (numCoords > 0) { 1667 affine.transform(doubleCoords, pointIdx, 1668 coords, 0, numCoords / 2); 1669 } 1670 return type; 1671 } 1672 1673 public int currentSegment(double[] coords) { 1674 int type = path.pointTypes[typeIdx]; 1675 int numCoords = curvecoords[type]; 1676 if (numCoords > 0) { 1677 affine.transform(doubleCoords, pointIdx, 1678 coords, 0, numCoords / 2); 1679 } 1680 return type; 1681 } 1682 } 1683 } 1684 1685 1693 public abstract void moveTo(double x, double y); 1694 1695 1704 public abstract void lineTo(double x, double y); 1705 1706 1720 public abstract void quadTo(double x1, double y1, 1721 double x2, double y2); 1722 1723 1739 public abstract void curveTo(double x1, double y1, 1740 double x2, double y2, 1741 double x3, double y3); 1742 1743 1750 public final synchronized void closePath() { 1751 if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) { 1752 needRoom(true, 0); 1753 pointTypes[numTypes++] = SEG_CLOSE; 1754 } 1755 } 1756 1757 1779 public final void append(Shape s, boolean connect) { 1780 append(s.getPathIterator(null), connect); 1781 } 1782 1783 1806 public abstract void append(PathIterator pi, boolean connect); 1807 1808 1817 public final synchronized int getWindingRule() { 1818 return windingRule; 1819 } 1820 1821 1833 public final void setWindingRule(int rule) { 1834 if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) { 1835 throw new IllegalArgumentException ("winding rule must be "+ 1836 "WIND_EVEN_ODD or "+ 1837 "WIND_NON_ZERO"); 1838 } 1839 windingRule = rule; 1840 } 1841 1842 1850 public final synchronized Point2D getCurrentPoint() { 1851 int index = numCoords; 1852 if (numTypes < 1 || index < 1) { 1853 return null; 1854 } 1855 if (pointTypes[numTypes - 1] == SEG_CLOSE) { 1856 loop: 1857 for (int i = numTypes - 2; i > 0; i--) { 1858 switch (pointTypes[i]) { 1859 case SEG_MOVETO: 1860 break loop; 1861 case SEG_LINETO: 1862 index -= 2; 1863 break; 1864 case SEG_QUADTO: 1865 index -= 4; 1866 break; 1867 case SEG_CUBICTO: 1868 index -= 6; 1869 break; 1870 case SEG_CLOSE: 1871 break; 1872 } 1873 } 1874 } 1875 return getPoint(index - 2); 1876 } 1877 1878 1885 public final synchronized void reset() { 1886 numTypes = numCoords = 0; 1887 } 1888 1889 1898 public abstract void transform(AffineTransform at); 1899 1900 1921 public final synchronized Shape createTransformedShape(AffineTransform at) { 1922 Path2D p2d = (Path2D ) clone(); 1923 if (at != null) { 1924 p2d.transform(at); 1925 } 1926 return p2d; 1927 } 1928 1929 1933 public final Rectangle getBounds() { 1934 return getBounds2D().getBounds(); 1935 } 1936 1937 1952 public static boolean contains(PathIterator pi, double x, double y) { 1953 if (x * 0.0 + y * 0.0 == 0.0) { 1954 1957 int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1); 1958 int cross = Curve.pointCrossingsForPath(pi, x, y); 1959 return ((cross & mask) != 0); 1960 } else { 1961 1966 return false; 1967 } 1968 } 1969 1970 1984 public static boolean contains(PathIterator pi, Point2D p) { 1985 return contains(pi, p.getX(), p.getY()); 1986 } 1987 1988 1992 public final boolean contains(double x, double y) { 1993 if (x * 0.0 + y * 0.0 == 0.0) { 1994 1997 if (numTypes < 2) { 1998 return false; 1999 } 2000 int mask = (windingRule == WIND_NON_ZERO ? -1 : 1); 2001 return ((pointCrossings(x, y) & mask) != 0); 2002 } else { 2003 2008 return false; 2009 } 2010 } 2011 2012 2016 public final boolean contains(Point2D p) { 2017 return contains(p.getX(), p.getY()); 2018 } 2019 2020 2051 public static boolean contains(PathIterator pi, 2052 double x, double y, double w, double h) 2053 { 2054 if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) { 2055 2063 return false; 2064 } 2065 if (w <= 0 || h <= 0) { 2066 return false; 2067 } 2068 int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2); 2069 int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h); 2070 return (crossings != Curve.RECT_INTERSECTS && 2071 (crossings & mask) != 0); 2072 } 2073 2074 2102 public static boolean contains(PathIterator pi, Rectangle2D r) { 2103 return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight()); 2104 } 2105 2106 2125 public final boolean contains(double x, double y, double w, double h) { 2126 if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) { 2127 2135 return false; 2136 } 2137 if (w <= 0 || h <= 0) { 2138 return false; 2139 } 2140 int mask = (windingRule == WIND_NON_ZERO ? -1 : 2); 2141 int crossings = rectCrossings(x, y, x+w, y+h); 2142 return (crossings != Curve.RECT_INTERSECTS && 2143 (crossings & mask) != 0); 2144 } 2145 2146 2165 public final boolean contains(Rectangle2D r) { 2166 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 2167 } 2168 2169 2201 public static boolean intersects(PathIterator pi, 2202 double x, double y, double w, double h) 2203 { 2204 if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) { 2205 2213 return false; 2214 } 2215 if (w <= 0 || h <= 0) { 2216 return false; 2217 } 2218 int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2); 2219 int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h); 2220 return (crossings == Curve.RECT_INTERSECTS || 2221 (crossings & mask) != 0); 2222 } 2223 2224 2252 public static boolean intersects(PathIterator pi, Rectangle2D r) { 2253 return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight()); 2254 } 2255 2256 2274 public final boolean intersects(double x, double y, double w, double h) { 2275 if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) { 2276 2284 return false; 2285 } 2286 if (w <= 0 || h <= 0) { 2287 return false; 2288 } 2289 int mask = (windingRule == WIND_NON_ZERO ? -1 : 2); 2290 int crossings = rectCrossings(x, y, x+w, y+h); 2291 return (crossings == Curve.RECT_INTERSECTS || 2292 (crossings & mask) != 0); 2293 } 2294 2295 2313 public final boolean intersects(Rectangle2D r) { 2314 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 2315 } 2316 2317 2328 public PathIterator getPathIterator(AffineTransform at, 2329 double flatness) 2330 { 2331 return new FlatteningPathIterator (getPathIterator(at), flatness); 2332 } 2333 2334 2342 public abstract Object clone(); 2343 2349 2352 private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30; 2353 private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31; 2354 2355 private static final byte SERIAL_SEG_FLT_MOVETO = 0x40; 2356 private static final byte SERIAL_SEG_FLT_LINETO = 0x41; 2357 private static final byte SERIAL_SEG_FLT_QUADTO = 0x42; 2358 private static final byte SERIAL_SEG_FLT_CUBICTO = 0x43; 2359 2360 private static final byte SERIAL_SEG_DBL_MOVETO = 0x50; 2361 private static final byte SERIAL_SEG_DBL_LINETO = 0x51; 2362 private static final byte SERIAL_SEG_DBL_QUADTO = 0x52; 2363 private static final byte SERIAL_SEG_DBL_CUBICTO = 0x53; 2364 2365 private static final byte SERIAL_SEG_CLOSE = 0x60; 2366 private static final byte SERIAL_PATH_END = 0x61; 2367 2368 final void writeObject(java.io.ObjectOutputStream s, boolean isdbl) 2369 throws java.io.IOException 2370 { 2371 s.defaultWriteObject(); 2372 2373 float fCoords[]; 2374 double dCoords[]; 2375 2376 if (isdbl) { 2377 dCoords = ((Path2D.Double ) this).doubleCoords; 2378 fCoords = null; 2379 } else { 2380 fCoords = ((Path2D.Float ) this).floatCoords; 2381 dCoords = null; 2382 } 2383 2384 int numTypes = this.numTypes; 2385 2386 s.writeByte(isdbl 2387 ? SERIAL_STORAGE_DBL_ARRAY 2388 : SERIAL_STORAGE_FLT_ARRAY); 2389 s.writeInt(numTypes); 2390 s.writeInt(numCoords); 2391 s.writeByte((byte) windingRule); 2392 2393 int cindex = 0; 2394 for (int i = 0; i < numTypes; i++) { 2395 int npoints; 2396 byte serialtype; 2397 switch (pointTypes[i]) { 2398 case SEG_MOVETO: 2399 npoints = 1; 2400 serialtype = (isdbl 2401 ? SERIAL_SEG_DBL_MOVETO 2402 : SERIAL_SEG_FLT_MOVETO); 2403 break; 2404 case SEG_LINETO: 2405 npoints = 1; 2406 serialtype = (isdbl 2407 ? SERIAL_SEG_DBL_LINETO 2408 : SERIAL_SEG_FLT_LINETO); 2409 break; 2410 case SEG_QUADTO: 2411 npoints = 2; 2412 serialtype = (isdbl 2413 ? SERIAL_SEG_DBL_QUADTO 2414 : SERIAL_SEG_FLT_QUADTO); 2415 break; 2416 case SEG_CUBICTO: 2417 npoints = 3; 2418 serialtype = (isdbl 2419 ? SERIAL_SEG_DBL_CUBICTO 2420 : SERIAL_SEG_FLT_CUBICTO); 2421 break; 2422 case SEG_CLOSE: 2423 npoints = 0; 2424 serialtype = SERIAL_SEG_CLOSE; 2425 break; 2426 2427 default: 2428 throw new InternalError ("unrecognized path type"); 2430 } 2431 s.writeByte(serialtype); 2432 while (--npoints >= 0) { 2433 if (isdbl) { 2434 s.writeDouble(dCoords[cindex++]); 2435 s.writeDouble(dCoords[cindex++]); 2436 } else { 2437 s.writeFloat(fCoords[cindex++]); 2438 s.writeFloat(fCoords[cindex++]); 2439 } 2440 } 2441 } 2442 s.writeByte((byte) SERIAL_PATH_END); 2443 } 2444 2445 final void readObject(java.io.ObjectInputStream s, boolean storedbl) 2446 throws java.lang.ClassNotFoundException , java.io.IOException 2447 { 2448 s.defaultReadObject(); 2449 2450 s.readByte(); 2454 int nT = s.readInt(); 2455 int nC = s.readInt(); 2456 try { 2457 setWindingRule(s.readByte()); 2458 } catch (IllegalArgumentException iae) { 2459 throw new java.io.InvalidObjectException (iae.getMessage()); 2460 } 2461 2462 pointTypes = new byte[(nT < 0) ? INIT_SIZE : nT]; 2463 if (nC < 0) { 2464 nC = INIT_SIZE * 2; 2465 } 2466 if (storedbl) { 2467 ((Path2D.Double ) this).doubleCoords = new double[nC]; 2468 } else { 2469 ((Path2D.Float ) this).floatCoords = new float[nC]; 2470 } 2471 2472 PATHDONE: 2473 for (int i = 0; nT < 0 || i < nT; i++) { 2474 boolean isdbl; 2475 int npoints; 2476 byte segtype; 2477 2478 byte serialtype = s.readByte(); 2479 switch (serialtype) { 2480 case SERIAL_SEG_FLT_MOVETO: 2481 isdbl = false; 2482 npoints = 1; 2483 segtype = SEG_MOVETO; 2484 break; 2485 case SERIAL_SEG_FLT_LINETO: 2486 isdbl = false; 2487 npoints = 1; 2488 segtype = SEG_LINETO; 2489 break; 2490 case SERIAL_SEG_FLT_QUADTO: 2491 isdbl = false; 2492 npoints = 2; 2493 segtype = SEG_QUADTO; 2494 break; 2495 case SERIAL_SEG_FLT_CUBICTO: 2496 isdbl = false; 2497 npoints = 3; 2498 segtype = SEG_CUBICTO; 2499 break; 2500 2501 case SERIAL_SEG_DBL_MOVETO: 2502 isdbl = true; 2503 npoints = 1; 2504 segtype = SEG_MOVETO; 2505 break; 2506 case SERIAL_SEG_DBL_LINETO: 2507 isdbl = true; 2508 npoints = 1; 2509 segtype = SEG_LINETO; 2510 break; 2511 case SERIAL_SEG_DBL_QUADTO: 2512 isdbl = true; 2513 npoints = 2; 2514 segtype = SEG_QUADTO; 2515 break; 2516 case SERIAL_SEG_DBL_CUBICTO: 2517 isdbl = true; 2518 npoints = 3; 2519 segtype = SEG_CUBICTO; 2520 break; 2521 2522 case SERIAL_SEG_CLOSE: 2523 isdbl = false; 2524 npoints = 0; 2525 segtype = SEG_CLOSE; 2526 break; 2527 2528 case SERIAL_PATH_END: 2529 if (nT < 0) { 2530 break PATHDONE; 2531 } 2532 throw new StreamCorruptedException ("unexpected PATH_END"); 2533 2534 default: 2535 throw new StreamCorruptedException ("unrecognized path type"); 2536 } 2537 needRoom(segtype != SEG_MOVETO, npoints * 2); 2538 if (isdbl) { 2539 while (--npoints >= 0) { 2540 append(s.readDouble(), s.readDouble()); 2541 } 2542 } else { 2543 while (--npoints >= 0) { 2544 append(s.readFloat(), s.readFloat()); 2545 } 2546 } 2547 pointTypes[numTypes++] = segtype; 2548 } 2549 if (nT >= 0 && s.readByte() != SERIAL_PATH_END) { 2550 throw new StreamCorruptedException ("missing PATH_END"); 2551 } 2552 } 2553 2554 static abstract class Iterator implements PathIterator { 2555 int typeIdx; 2556 int pointIdx; 2557 Path2D path; 2558 2559 static final int curvecoords[] = {2, 2, 4, 6, 0}; 2560 2561 Iterator(Path2D path) { 2562 this.path = path; 2563 } 2564 2565 public int getWindingRule() { 2566 return path.getWindingRule(); 2567 } 2568 2569 public boolean isDone() { 2570 return (typeIdx >= path.numTypes); 2571 } 2572 2573 public void next() { 2574 int type = path.pointTypes[typeIdx++]; 2575 pointIdx += curvecoords[type]; 2576 } 2577 } 2578} 2579 | Popular Tags |