1 7 8 package java.awt.geom; 9 10 import java.awt.Shape ; 11 import java.awt.Rectangle ; 12 13 25 public abstract class QuadCurve2D implements Shape , Cloneable { 26 30 31 public static class Float extends QuadCurve2D { 32 33 37 public float x1; 38 39 43 public float y1; 44 45 49 public float ctrlx; 50 51 55 public float ctrly; 56 57 61 public float x2; 62 63 67 public float y2; 68 69 73 public Float() { 74 } 75 76 83 public Float(float x1, float y1, 84 float ctrlx, float ctrly, 85 float x2, float y2) { 86 setCurve(x1, y1, ctrlx, ctrly, x2, y2); 87 } 88 89 94 public double getX1() { 95 return (double) x1; 96 } 97 98 103 public double getY1() { 104 return (double) y1; 105 } 106 107 112 public Point2D getP1() { 113 return new Point2D.Float (x1, y1); 114 } 115 116 121 public double getCtrlX() { 122 return (double) ctrlx; 123 } 124 125 130 public double getCtrlY() { 131 return (double) ctrly; 132 } 133 134 139 public Point2D getCtrlPt() { 140 return new Point2D.Float (ctrlx, ctrly); 141 } 142 143 148 public double getX2() { 149 return (double) x2; 150 } 151 152 157 public double getY2() { 158 return (double) y2; 159 } 160 161 166 public Point2D getP2() { 167 return new Point2D.Float (x2, y2); 168 } 169 170 178 public void setCurve(double x1, double y1, 179 double ctrlx, double ctrly, 180 double x2, double y2) { 181 this.x1 = (float) x1; 182 this.y1 = (float) y1; 183 this.ctrlx = (float) ctrlx; 184 this.ctrly = (float) ctrly; 185 this.x2 = (float) x2; 186 this.y2 = (float) y2; 187 } 188 189 196 public void setCurve(float x1, float y1, 197 float ctrlx, float ctrly, 198 float x2, float y2) { 199 this.x1 = x1; 200 this.y1 = y1; 201 this.ctrlx = ctrlx; 202 this.ctrly = ctrly; 203 this.x2 = x2; 204 this.y2 = y2; 205 } 206 207 212 public Rectangle2D getBounds2D() { 213 float left = Math.min(Math.min(x1, x2), ctrlx); 214 float top = Math.min(Math.min(y1, y2), ctrly); 215 float right = Math.max(Math.max(x1, x2), ctrlx); 216 float bottom = Math.max(Math.max(y1, y2), ctrly); 217 return new Rectangle2D.Float (left, top, 218 right - left, bottom - top); 219 } 220 } 221 222 226 public static class Double extends QuadCurve2D { 227 231 public double x1; 232 233 237 public double y1; 238 239 243 public double ctrlx; 244 245 249 public double ctrly; 250 251 255 public double x2; 256 257 261 public double y2; 262 263 267 public Double() { 268 } 269 270 277 public Double(double x1, double y1, 278 double ctrlx, double ctrly, 279 double x2, double y2) { 280 setCurve(x1, y1, ctrlx, ctrly, x2, y2); 281 } 282 283 288 public double getX1() { 289 return x1; 290 } 291 292 297 public double getY1() { 298 return y1; 299 } 300 301 306 public Point2D getP1() { 307 return new Point2D.Double (x1, y1); 308 } 309 310 315 public double getCtrlX() { 316 return ctrlx; 317 } 318 319 324 public double getCtrlY() { 325 return ctrly; 326 } 327 328 333 public Point2D getCtrlPt() { 334 return new Point2D.Double (ctrlx, ctrly); 335 } 336 337 342 public double getX2() { 343 return x2; 344 } 345 346 351 public double getY2() { 352 return y2; 353 } 354 355 360 public Point2D getP2() { 361 return new Point2D.Double (x2, y2); 362 } 363 364 371 public void setCurve(double x1, double y1, 372 double ctrlx, double ctrly, 373 double x2, double y2) { 374 this.x1 = x1; 375 this.y1 = y1; 376 this.ctrlx = ctrlx; 377 this.ctrly = ctrly; 378 this.x2 = x2; 379 this.y2 = y2; 380 } 381 382 387 public Rectangle2D getBounds2D() { 388 double left = Math.min(Math.min(x1, x2), ctrlx); 389 double top = Math.min(Math.min(y1, y2), ctrly); 390 double right = Math.max(Math.max(x1, x2), ctrlx); 391 double bottom = Math.max(Math.max(y1, y2), ctrly); 392 return new Rectangle2D.Double (left, top, 393 right - left, bottom - top); 394 } 395 } 396 397 407 protected QuadCurve2D() { 408 } 409 410 415 public abstract double getX1(); 416 417 422 public abstract double getY1(); 423 424 429 public abstract Point2D getP1(); 430 431 436 public abstract double getCtrlX(); 437 438 443 public abstract double getCtrlY(); 444 445 450 public abstract Point2D getCtrlPt(); 451 452 457 public abstract double getX2(); 458 459 464 public abstract double getY2(); 465 466 471 public abstract Point2D getP2(); 472 473 480 public abstract void setCurve(double x1, double y1, 481 double ctrlx, double ctrly, 482 double x2, double y2); 483 484 493 public void setCurve(double[] coords, int offset) { 494 setCurve(coords[offset + 0], coords[offset + 1], 495 coords[offset + 2], coords[offset + 3], 496 coords[offset + 4], coords[offset + 5]); 497 } 498 499 507 public void setCurve(Point2D p1, Point2D cp, Point2D p2) { 508 setCurve(p1.getX(), p1.getY(), 509 cp.getX(), cp.getY(), 510 p2.getX(), p2.getY()); 511 } 512 513 524 public void setCurve(Point2D [] pts, int offset) { 525 setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(), 526 pts[offset + 1].getX(), pts[offset + 1].getY(), 527 pts[offset + 2].getX(), pts[offset + 2].getY()); 528 } 529 530 536 public void setCurve(QuadCurve2D c) { 537 setCurve(c.getX1(), c.getY1(), 538 c.getCtrlX(), c.getCtrlY(), 539 c.getX2(), c.getY2()); 540 } 541 542 552 public static double getFlatnessSq(double x1, double y1, 553 double ctrlx, double ctrly, 554 double x2, double y2) { 555 return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly); 556 } 557 558 568 public static double getFlatness(double x1, double y1, 569 double ctrlx, double ctrly, 570 double x2, double y2) { 571 return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly); 572 } 573 574 586 public static double getFlatnessSq(double coords[], int offset) { 587 return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1], 588 coords[offset + 4], coords[offset + 5], 589 coords[offset + 2], coords[offset + 3]); 590 } 591 592 604 public static double getFlatness(double coords[], int offset) { 605 return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1], 606 coords[offset + 4], coords[offset + 5], 607 coords[offset + 2], coords[offset + 3]); 608 } 609 610 617 public double getFlatnessSq() { 618 return Line2D.ptSegDistSq(getX1(), getY1(), 619 getX2(), getY2(), 620 getCtrlX(), getCtrlY()); 621 } 622 623 629 public double getFlatness() { 630 return Line2D.ptSegDist(getX1(), getY1(), 631 getX2(), getY2(), 632 getCtrlX(), getCtrlY()); 633 } 634 635 647 public void subdivide(QuadCurve2D left, QuadCurve2D right) { 648 subdivide(this, left, right); 649 } 650 651 664 public static void subdivide(QuadCurve2D src, 665 QuadCurve2D left, 666 QuadCurve2D right) { 667 double x1 = src.getX1(); 668 double y1 = src.getY1(); 669 double ctrlx = src.getCtrlX(); 670 double ctrly = src.getCtrlY(); 671 double x2 = src.getX2(); 672 double y2 = src.getY2(); 673 double ctrlx1 = (x1 + ctrlx) / 2.0; 674 double ctrly1 = (y1 + ctrly) / 2.0; 675 double ctrlx2 = (x2 + ctrlx) / 2.0; 676 double ctrly2 = (y2 + ctrly) / 2.0; 677 ctrlx = (ctrlx1 + ctrlx2) / 2.0; 678 ctrly = (ctrly1 + ctrly2) / 2.0; 679 if (left != null) { 680 left.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx, ctrly); 681 } 682 if (right != null) { 683 right.setCurve(ctrlx, ctrly, ctrlx2, ctrly2, x2, y2); 684 } 685 } 686 687 714 public static void subdivide(double src[], int srcoff, 715 double left[], int leftoff, 716 double right[], int rightoff) { 717 double x1 = src[srcoff + 0]; 718 double y1 = src[srcoff + 1]; 719 double ctrlx = src[srcoff + 2]; 720 double ctrly = src[srcoff + 3]; 721 double x2 = src[srcoff + 4]; 722 double y2 = src[srcoff + 5]; 723 if (left != null) { 724 left[leftoff + 0] = x1; 725 left[leftoff + 1] = y1; 726 } 727 if (right != null) { 728 right[rightoff + 4] = x2; 729 right[rightoff + 5] = y2; 730 } 731 x1 = (x1 + ctrlx) / 2.0; 732 y1 = (y1 + ctrly) / 2.0; 733 x2 = (x2 + ctrlx) / 2.0; 734 y2 = (y2 + ctrly) / 2.0; 735 ctrlx = (x1 + x2) / 2.0; 736 ctrly = (y1 + y2) / 2.0; 737 if (left != null) { 738 left[leftoff + 2] = x1; 739 left[leftoff + 3] = y1; 740 left[leftoff + 4] = ctrlx; 741 left[leftoff + 5] = ctrly; 742 } 743 if (right != null) { 744 right[rightoff + 0] = ctrlx; 745 right[rightoff + 1] = ctrly; 746 right[rightoff + 2] = x2; 747 right[rightoff + 3] = y2; 748 } 749 } 750 751 767 public static int solveQuadratic(double eqn[]) { 768 return solveQuadratic(eqn, eqn); 769 } 770 771 790 public static int solveQuadratic(double eqn[], double res[]) { 791 double a = eqn[2]; 792 double b = eqn[1]; 793 double c = eqn[0]; 794 int roots = 0; 795 if (a == 0.0) { 796 if (b == 0.0) { 798 return -1; 800 } 801 res[roots++] = -c / b; 802 } else { 803 double d = b * b - 4.0 * a * c; 805 if (d < 0.0) { 806 return 0; 808 } 809 d = Math.sqrt(d); 810 if (b < 0.0) { 816 d = -d; 817 } 818 double q = (b + d) / -2.0; 819 res[roots++] = q / a; 821 if (q != 0.0) { 822 res[roots++] = c / q; 823 } 824 } 825 return roots; 826 } 827 828 836 public boolean contains(double x, double y) { 837 838 double x1 = getX1(); 839 double y1 = getY1(); 840 double xc = getCtrlX(); 841 double yc = getCtrlY(); 842 double x2 = getX2(); 843 double y2 = getY2(); 844 845 911 double kx = x1 - 2 * xc + x2; 912 double ky = y1 - 2 * yc + y2; 913 double dx = x - x1; 914 double dy = y - y1; 915 double dxl = x2 - x1; 916 double dyl = y2 - y1; 917 918 double t0 = (dx * ky - dy * kx) / (dxl * ky - dyl * kx); 919 if (t0 < 0 || t0 > 1 || t0 != t0) { 920 return false; 921 } 922 923 double xb = kx * t0 * t0 + 2 * (xc - x1) * t0 + x1; 924 double yb = ky * t0 * t0 + 2 * (yc - y1) * t0 + y1; 925 double xl = dxl * t0 + x1; 926 double yl = dyl * t0 + y1; 927 928 return (x >= xb && x < xl) || 929 (x >= xl && x < xb) || 930 (y >= yb && y < yl) || 931 (y >= yl && y < yb); 932 } 933 934 942 public boolean contains(Point2D p) { 943 return contains(p.getX(), p.getY()); 944 } 945 946 959 private static void fillEqn(double eqn[], double val, 960 double c1, double cp, double c2) { 961 eqn[0] = c1 - val; 962 eqn[1] = cp + cp - c1 - c1; 963 eqn[2] = c1 - cp - cp + c2; 964 return; 965 } 966 967 976 private static int evalQuadratic(double vals[], int num, 977 boolean include0, 978 boolean include1, 979 double inflect[], 980 double c1, double ctrl, double c2) { 981 int j = 0; 982 for (int i = 0; i < num; i++) { 983 double t = vals[i]; 984 if ((include0 ? t >= 0 : t > 0) && 985 (include1 ? t <= 1 : t < 1) && 986 (inflect == null || 987 inflect[1] + 2*inflect[2]*t != 0)) 988 { 989 double u = 1 - t; 990 vals[j++] = c1*u*u + 2*ctrl*t*u + c2*t*t; 991 } 992 } 993 return j; 994 } 995 996 private static final int BELOW = -2; 997 private static final int LOWEDGE = -1; 998 private static final int INSIDE = 0; 999 private static final int HIGHEDGE = 1; 1000 private static final int ABOVE = 2; 1001 1002 1008 private static int getTag(double coord, double low, double high) { 1009 if (coord <= low) { 1010 return (coord < low ? BELOW : LOWEDGE); 1011 } 1012 if (coord >= high) { 1013 return (coord > high ? ABOVE : HIGHEDGE); 1014 } 1015 return INSIDE; 1016 } 1017 1018 1025 private static boolean inwards(int pttag, int opt1tag, int opt2tag) { 1026 switch (pttag) { 1027 case BELOW: 1028 case ABOVE: 1029 default: 1030 return false; 1031 case LOWEDGE: 1032 return (opt1tag >= INSIDE || opt2tag >= INSIDE); 1033 case INSIDE: 1034 return true; 1035 case HIGHEDGE: 1036 return (opt1tag <= INSIDE || opt2tag <= INSIDE); 1037 } 1038 } 1039 1040 1052 public boolean intersects(double x, double y, double w, double h) { 1053 if (w < 0 || h < 0) { 1055 return false; 1056 } 1057 1058 double x1 = getX1(); 1063 double y1 = getY1(); 1064 int x1tag = getTag(x1, x, x+w); 1065 int y1tag = getTag(y1, y, y+h); 1066 if (x1tag == INSIDE && y1tag == INSIDE) { 1067 return true; 1068 } 1069 double x2 = getX2(); 1070 double y2 = getY2(); 1071 int x2tag = getTag(x2, x, x+w); 1072 int y2tag = getTag(y2, y, y+h); 1073 if (x2tag == INSIDE && y2tag == INSIDE) { 1074 return true; 1075 } 1076 double ctrlx = getCtrlX(); 1077 double ctrly = getCtrlY(); 1078 int ctrlxtag = getTag(ctrlx, x, x+w); 1079 int ctrlytag = getTag(ctrly, y, y+h); 1080 1081 if (x1tag < INSIDE && x2tag < INSIDE && ctrlxtag < INSIDE) { 1084 return false; } 1086 if (y1tag < INSIDE && y2tag < INSIDE && ctrlytag < INSIDE) { 1087 return false; } 1089 if (x1tag > INSIDE && x2tag > INSIDE && ctrlxtag > INSIDE) { 1090 return false; } 1092 if (y1tag > INSIDE && y2tag > INSIDE && ctrlytag > INSIDE) { 1093 return false; } 1095 1096 if (inwards(x1tag, x2tag, ctrlxtag) && 1102 inwards(y1tag, y2tag, ctrlytag)) 1103 { 1104 return true; 1106 } 1107 if (inwards(x2tag, x1tag, ctrlxtag) && 1108 inwards(y2tag, y1tag, ctrlytag)) 1109 { 1110 return true; 1112 } 1113 1114 boolean xoverlap = (x1tag * x2tag <= 0); 1116 boolean yoverlap = (y1tag * y2tag <= 0); 1117 if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) { 1118 return true; 1119 } 1120 if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) { 1121 return true; 1122 } 1123 1124 1130 double[] eqn = new double[3]; 1131 double[] res = new double[3]; 1132 if (!yoverlap) { 1133 fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly, y2); 1139 return (solveQuadratic(eqn, res) == 2 && 1140 evalQuadratic(res, 2, true, true, null, 1141 x1, ctrlx, x2) == 2 && 1142 getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0); 1143 } 1144 1145 if (!xoverlap) { 1147 fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx, x2); 1153 return (solveQuadratic(eqn, res) == 2 && 1154 evalQuadratic(res, 2, true, true, null, 1155 y1, ctrly, y2) == 2 && 1156 getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0); 1157 } 1158 1159 double dx = x2 - x1; 1163 double dy = y2 - y1; 1164 double k = y2 * x1 - x2 * y1; 1165 int c1tag, c2tag; 1166 if (y1tag == INSIDE) { 1167 c1tag = x1tag; 1168 } else { 1169 c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w); 1170 } 1171 if (y2tag == INSIDE) { 1172 c2tag = x2tag; 1173 } else { 1174 c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w); 1175 } 1176 if (c1tag * c2tag <= 0) { 1179 return true; 1180 } 1181 1182 1202 c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag); 1209 1210 fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx, x2); 1216 int num = solveQuadratic(eqn, res); 1217 1218 evalQuadratic(res, num, true, true, null, y1, ctrly, y2); 1222 1223 c2tag = getTag(res[0], y, y+h); 1226 1227 return (c1tag * c2tag <= 0); 1230 } 1231 1232 1241 public boolean intersects(Rectangle2D r) { 1242 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 1243 } 1244 1245 1257 public boolean contains(double x, double y, double w, double h) { 1258 return (contains(x, y) && 1261 contains(x + w, y) && 1262 contains(x + w, y + h) && 1263 contains(x, y + h)); 1264 } 1265 1266 1275 public boolean contains(Rectangle2D r) { 1276 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 1277 } 1278 1279 1284 public Rectangle getBounds() { 1285 return getBounds2D().getBounds(); 1286 } 1287 1288 1301 public PathIterator getPathIterator(AffineTransform at) { 1302 return new QuadIterator (this, at); 1303 } 1304 1305 1322 public PathIterator getPathIterator(AffineTransform at, double flatness) { 1323 return new FlatteningPathIterator (getPathIterator(at), flatness); 1324 } 1325 1326 1335 public Object clone() { 1336 try { 1337 return super.clone(); 1338 } catch (CloneNotSupportedException e) { 1339 throw new InternalError (); 1341 } 1342 } 1343} 1344 | Popular Tags |