1 /* CubicCurve2D.java -- represents a parameterized cubic curve in 2-D space 2 Copyright (C) 2002, 2003 Free Software Foundation 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.awt.geom; 40 41 import java.awt.Rectangle; 42 import java.awt.Shape; 43 import java.util.NoSuchElementException; 44 45 46 /** 47 * A two-dimensional curve that is parameterized with a cubic 48 * function. 49 * 50 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 51 * alt="A drawing of a CubicCurve2D" /> 52 * 53 * @author Eric Blake (ebb9@email.byu.edu) 54 * @author Graydon Hoare (graydon@redhat.com) 55 * @author Sascha Brawer (brawer@dandelis.ch) 56 * 57 * @since 1.2 58 */ 59 public abstract class CubicCurve2D 60 implements Shape, Cloneable 61 { 62 /** 63 * Constructs a new CubicCurve2D. Typical users will want to 64 * construct instances of a subclass, such as {@link 65 * CubicCurve2D.Float} or {@link CubicCurve2D.Double}. 66 */ CubicCurve2D()67 protected CubicCurve2D() 68 { 69 } 70 71 72 /** 73 * Returns the <i>x</i> coordinate of the curve’s start 74 * point. 75 */ getX1()76 public abstract double getX1(); 77 78 79 /** 80 * Returns the <i>y</i> coordinate of the curve’s start 81 * point. 82 */ getY1()83 public abstract double getY1(); 84 85 86 /** 87 * Returns the curve’s start point. 88 */ getP1()89 public abstract Point2D getP1(); 90 91 92 /** 93 * Returns the <i>x</i> coordinate of the curve’s first 94 * control point. 95 */ getCtrlX1()96 public abstract double getCtrlX1(); 97 98 99 /** 100 * Returns the <i>y</i> coordinate of the curve’s first 101 * control point. 102 */ getCtrlY1()103 public abstract double getCtrlY1(); 104 105 106 /** 107 * Returns the curve’s first control point. 108 */ getCtrlP1()109 public abstract Point2D getCtrlP1(); 110 111 112 /** 113 * Returns the <i>x</i> coordinate of the curve’s second 114 * control point. 115 */ getCtrlX2()116 public abstract double getCtrlX2(); 117 118 119 /** 120 * Returns the <i>y</i> coordinate of the curve’s second 121 * control point. 122 */ getCtrlY2()123 public abstract double getCtrlY2(); 124 125 126 /** 127 * Returns the curve’s second control point. 128 */ getCtrlP2()129 public abstract Point2D getCtrlP2(); 130 131 132 /** 133 * Returns the <i>x</i> coordinate of the curve’s end 134 * point. 135 */ getX2()136 public abstract double getX2(); 137 138 139 /** 140 * Returns the <i>y</i> coordinate of the curve’s end 141 * point. 142 */ getY2()143 public abstract double getY2(); 144 145 146 /** 147 * Returns the curve’s end point. 148 */ getP2()149 public abstract Point2D getP2(); 150 151 152 /** 153 * Changes the curve geometry, separately specifying each coordinate 154 * value. 155 * 156 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 157 * alt="A drawing of a CubicCurve2D" /> 158 * 159 * @param x1 the <i>x</i> coordinate of the curve’s new start 160 * point. 161 * 162 * @param y1 the <i>y</i> coordinate of the curve’s new start 163 * point. 164 * 165 * @param cx1 the <i>x</i> coordinate of the curve’s new 166 * first control point. 167 * 168 * @param cy1 the <i>y</i> coordinate of the curve’s new 169 * first control point. 170 * 171 * @param cx2 the <i>x</i> coordinate of the curve’s new 172 * second control point. 173 * 174 * @param cy2 the <i>y</i> coordinate of the curve’s new 175 * second control point. 176 * 177 * @param x2 the <i>x</i> coordinate of the curve’s new end 178 * point. 179 * 180 * @param y2 the <i>y</i> coordinate of the curve’s new end 181 * point. 182 */ setCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2)183 public abstract void setCurve(double x1, double y1, double cx1, double cy1, 184 double cx2, double cy2, double x2, double y2); 185 186 187 /** 188 * Changes the curve geometry, specifying coordinate values in an 189 * array. 190 * 191 * @param coords an array containing the new coordinate values. The 192 * <i>x</i> coordinate of the new start point is located at 193 * <code>coords[offset]</code>, its <i>y</i> coordinate at 194 * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the 195 * new first control point is located at <code>coords[offset + 196 * 2]</code>, its <i>y</i> coordinate at <code>coords[offset + 197 * 3]</code>. The <i>x</i> coordinate of the new second control 198 * point is located at <code>coords[offset + 4]</code>, its <i>y</i> 199 * coordinate at <code>coords[offset + 5]</code>. The <i>x</i> 200 * coordinate of the new end point is located at <code>coords[offset 201 * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset + 202 * 7]</code>. 203 * 204 * @param offset the offset of the first coordinate value in 205 * <code>coords</code>. 206 */ setCurve(double[] coords, int offset)207 public void setCurve(double[] coords, int offset) 208 { 209 setCurve(coords[offset++], coords[offset++], 210 coords[offset++], coords[offset++], 211 coords[offset++], coords[offset++], 212 coords[offset++], coords[offset++]); 213 } 214 215 216 /** 217 * Changes the curve geometry, specifying coordinate values in 218 * separate Point objects. 219 * 220 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 221 * alt="A drawing of a CubicCurve2D" /> 222 * 223 * <p>The curve does not keep any reference to the passed point 224 * objects. Therefore, a later change to <code>p1</code>, 225 * <code>c1</code>, <code>c2</code> or <code>p2</code> will not 226 * affect the curve geometry. 227 * 228 * @param p1 the new start point. 229 * @param c1 the new first control point. 230 * @param c2 the new second control point. 231 * @param p2 the new end point. 232 */ setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2)233 public void setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2) 234 { 235 setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), 236 c2.getX(), c2.getY(), p2.getX(), p2.getY()); 237 } 238 239 240 /** 241 * Changes the curve geometry, specifying coordinate values in an 242 * array of Point objects. 243 * 244 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 245 * alt="A drawing of a CubicCurve2D" /> 246 * 247 * <p>The curve does not keep references to the passed point 248 * objects. Therefore, a later change to the <code>pts</code> array 249 * or any of its elements will not affect the curve geometry. 250 * 251 * @param pts an array containing the points. The new start point 252 * is located at <code>pts[offset]</code>, the new first control 253 * point at <code>pts[offset + 1]</code>, the new second control 254 * point at <code>pts[offset + 2]</code>, and the new end point 255 * at <code>pts[offset + 3]</code>. 256 * 257 * @param offset the offset of the start point in <code>pts</code>. 258 */ setCurve(Point2D[] pts, int offset)259 public void setCurve(Point2D[] pts, int offset) 260 { 261 setCurve(pts[offset].getX(), pts[offset++].getY(), 262 pts[offset].getX(), pts[offset++].getY(), 263 pts[offset].getX(), pts[offset++].getY(), 264 pts[offset].getX(), pts[offset++].getY()); 265 } 266 267 268 /** 269 * Changes the curve geometry to that of another curve. 270 * 271 * @param c the curve whose coordinates will be copied. 272 */ setCurve(CubicCurve2D c)273 public void setCurve(CubicCurve2D c) 274 { 275 setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(), 276 c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2()); 277 } 278 279 280 /** 281 * Calculates the squared flatness of a cubic curve, directly 282 * specifying each coordinate value. The flatness is the maximal 283 * distance of a control point to the line between start and end 284 * point. 285 * 286 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" 287 * alt="A drawing that illustrates the flatness" /> 288 * 289 * <p>In the above drawing, the straight line connecting start point 290 * P1 and end point P2 is depicted in gray. In comparison to C1, 291 * control point C2 is father away from the gray line. Therefore, 292 * the result will be the square of the distance between C2 and the 293 * gray line, i.e. the squared length of the red line. 294 * 295 * @param x1 the <i>x</i> coordinate of the start point P1. 296 * @param y1 the <i>y</i> coordinate of the start point P1. 297 * @param cx1 the <i>x</i> coordinate of the first control point C1. 298 * @param cy1 the <i>y</i> coordinate of the first control point C1. 299 * @param cx2 the <i>x</i> coordinate of the second control point C2. 300 * @param cy2 the <i>y</i> coordinate of the second control point C2. 301 * @param x2 the <i>x</i> coordinate of the end point P2. 302 * @param y2 the <i>y</i> coordinate of the end point P2. 303 */ getFlatnessSq(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2)304 public static double getFlatnessSq(double x1, double y1, double cx1, 305 double cy1, double cx2, double cy2, 306 double x2, double y2) 307 { 308 return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, cx1, cy1), 309 Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2)); 310 } 311 312 313 /** 314 * Calculates the flatness of a cubic curve, directly specifying 315 * each coordinate value. The flatness is the maximal distance of a 316 * control point to the line between start and end point. 317 * 318 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" 319 * alt="A drawing that illustrates the flatness" /> 320 * 321 * <p>In the above drawing, the straight line connecting start point 322 * P1 and end point P2 is depicted in gray. In comparison to C1, 323 * control point C2 is father away from the gray line. Therefore, 324 * the result will be the distance between C2 and the gray line, 325 * i.e. the length of the red line. 326 * 327 * @param x1 the <i>x</i> coordinate of the start point P1. 328 * @param y1 the <i>y</i> coordinate of the start point P1. 329 * @param cx1 the <i>x</i> coordinate of the first control point C1. 330 * @param cy1 the <i>y</i> coordinate of the first control point C1. 331 * @param cx2 the <i>x</i> coordinate of the second control point C2. 332 * @param cy2 the <i>y</i> coordinate of the second control point C2. 333 * @param x2 the <i>x</i> coordinate of the end point P2. 334 * @param y2 the <i>y</i> coordinate of the end point P2. 335 */ getFlatness(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2)336 public static double getFlatness(double x1, double y1, double cx1, 337 double cy1, double cx2, double cy2, 338 double x2, double y2) 339 { 340 return Math.sqrt(getFlatnessSq(x1, y1, cx1, cy1, cx2, cy2, x2, y2)); 341 } 342 343 344 /** 345 * Calculates the squared flatness of a cubic curve, specifying the 346 * coordinate values in an array. The flatness is the maximal 347 * distance of a control point to the line between start and end 348 * point. 349 * 350 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" 351 * alt="A drawing that illustrates the flatness" /> 352 * 353 * <p>In the above drawing, the straight line connecting start point 354 * P1 and end point P2 is depicted in gray. In comparison to C1, 355 * control point C2 is father away from the gray line. Therefore, 356 * the result will be the square of the distance between C2 and the 357 * gray line, i.e. the squared length of the red line. 358 * 359 * @param coords an array containing the coordinate values. The 360 * <i>x</i> coordinate of the start point P1 is located at 361 * <code>coords[offset]</code>, its <i>y</i> coordinate at 362 * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the 363 * first control point C1 is located at <code>coords[offset + 364 * 2]</code>, its <i>y</i> coordinate at <code>coords[offset + 365 * 3]</code>. The <i>x</i> coordinate of the second control point C2 366 * is located at <code>coords[offset + 4]</code>, its <i>y</i> 367 * coordinate at <code>coords[offset + 5]</code>. The <i>x</i> 368 * coordinate of the end point P2 is located at <code>coords[offset 369 * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset + 370 * 7]</code>. 371 * 372 * @param offset the offset of the first coordinate value in 373 * <code>coords</code>. 374 */ getFlatnessSq(double[] coords, int offset)375 public static double getFlatnessSq(double[] coords, int offset) 376 { 377 return getFlatnessSq(coords[offset++], coords[offset++], 378 coords[offset++], coords[offset++], 379 coords[offset++], coords[offset++], 380 coords[offset++], coords[offset++]); 381 } 382 383 384 /** 385 * Calculates the flatness of a cubic curve, specifying the 386 * coordinate values in an array. The flatness is the maximal 387 * distance of a control point to the line between start and end 388 * point. 389 * 390 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" 391 * alt="A drawing that illustrates the flatness" /> 392 * 393 * <p>In the above drawing, the straight line connecting start point 394 * P1 and end point P2 is depicted in gray. In comparison to C1, 395 * control point C2 is father away from the gray line. Therefore, 396 * the result will be the distance between C2 and the gray line, 397 * i.e. the length of the red line. 398 * 399 * @param coords an array containing the coordinate values. The 400 * <i>x</i> coordinate of the start point P1 is located at 401 * <code>coords[offset]</code>, its <i>y</i> coordinate at 402 * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the 403 * first control point C1 is located at <code>coords[offset + 404 * 2]</code>, its <i>y</i> coordinate at <code>coords[offset + 405 * 3]</code>. The <i>x</i> coordinate of the second control point C2 406 * is located at <code>coords[offset + 4]</code>, its <i>y</i> 407 * coordinate at <code>coords[offset + 5]</code>. The <i>x</i> 408 * coordinate of the end point P2 is located at <code>coords[offset 409 * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset + 410 * 7]</code>. 411 * 412 * @param offset the offset of the first coordinate value in 413 * <code>coords</code>. 414 */ getFlatness(double[] coords, int offset)415 public static double getFlatness(double[] coords, int offset) 416 { 417 return Math.sqrt(getFlatnessSq(coords[offset++], coords[offset++], 418 coords[offset++], coords[offset++], 419 coords[offset++], coords[offset++], 420 coords[offset++], coords[offset++])); 421 } 422 423 424 /** 425 * Calculates the squared flatness of this curve. The flatness is 426 * the maximal distance of a control point to the line between start 427 * and end point. 428 * 429 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" 430 * alt="A drawing that illustrates the flatness" /> 431 * 432 * <p>In the above drawing, the straight line connecting start point 433 * P1 and end point P2 is depicted in gray. In comparison to C1, 434 * control point C2 is father away from the gray line. Therefore, 435 * the result will be the square of the distance between C2 and the 436 * gray line, i.e. the squared length of the red line. 437 */ getFlatnessSq()438 public double getFlatnessSq() 439 { 440 return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), 441 getCtrlX2(), getCtrlY2(), getX2(), getY2()); 442 } 443 444 445 /** 446 * Calculates the flatness of this curve. The flatness is the 447 * maximal distance of a control point to the line between start and 448 * end point. 449 * 450 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" 451 * alt="A drawing that illustrates the flatness" /> 452 * 453 * <p>In the above drawing, the straight line connecting start point 454 * P1 and end point P2 is depicted in gray. In comparison to C1, 455 * control point C2 is father away from the gray line. Therefore, 456 * the result will be the distance between C2 and the gray line, 457 * i.e. the length of the red line. 458 */ getFlatness()459 public double getFlatness() 460 { 461 return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), 462 getCtrlY1(), getCtrlX2(), getCtrlY2(), 463 getX2(), getY2())); 464 } 465 466 467 /** 468 * Subdivides this curve into two halves. 469 * 470 * <p><img src="doc-files/CubicCurve2D-3.png" width="700" 471 * height="180" alt="A drawing that illustrates the effects of 472 * subdividing a CubicCurve2D" /> 473 * 474 * @param left a curve whose geometry will be set to the left half 475 * of this curve, or <code>null</code> if the caller is not 476 * interested in the left half. 477 * 478 * @param right a curve whose geometry will be set to the right half 479 * of this curve, or <code>null</code> if the caller is not 480 * interested in the right half. 481 */ subdivide(CubicCurve2D left, CubicCurve2D right)482 public void subdivide(CubicCurve2D left, CubicCurve2D right) 483 { 484 // Use empty slots at end to share single array. 485 double[] d = new double[] { getX1(), getY1(), getCtrlX1(), getCtrlY1(), 486 getCtrlX2(), getCtrlY2(), getX2(), getY2(), 487 0, 0, 0, 0, 0, 0 }; 488 subdivide(d, 0, d, 0, d, 6); 489 if (left != null) 490 left.setCurve(d, 0); 491 if (right != null) 492 right.setCurve(d, 6); 493 } 494 495 496 /** 497 * Subdivides a cubic curve into two halves. 498 * 499 * <p><img src="doc-files/CubicCurve2D-3.png" width="700" 500 * height="180" alt="A drawing that illustrates the effects of 501 * subdividing a CubicCurve2D" /> 502 * 503 * @param src the curve to be subdivided. 504 * 505 * @param left a curve whose geometry will be set to the left half 506 * of <code>src</code>, or <code>null</code> if the caller is not 507 * interested in the left half. 508 * 509 * @param right a curve whose geometry will be set to the right half 510 * of <code>src</code>, or <code>null</code> if the caller is not 511 * interested in the right half. 512 */ subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right)513 public static void subdivide(CubicCurve2D src, 514 CubicCurve2D left, CubicCurve2D right) 515 { 516 src.subdivide(left, right); 517 } 518 519 520 /** 521 * Subdivides a cubic curve into two halves, passing all coordinates 522 * in an array. 523 * 524 * <p><img src="doc-files/CubicCurve2D-3.png" width="700" 525 * height="180" alt="A drawing that illustrates the effects of 526 * subdividing a CubicCurve2D" /> 527 * 528 * <p>The left end point and the right start point will always be 529 * identical. Memory-concious programmers thus may want to pass the 530 * same array for both <code>left</code> and <code>right</code>, and 531 * set <code>rightOff</code> to <code>leftOff + 6</code>. 532 * 533 * @param src an array containing the coordinates of the curve to be 534 * subdivided. The <i>x</i> coordinate of the start point P1 is 535 * located at <code>src[srcOff]</code>, its <i>y</i> at 536 * <code>src[srcOff + 1]</code>. The <i>x</i> coordinate of the 537 * first control point C1 is located at <code>src[srcOff + 538 * 2]</code>, its <i>y</i> at <code>src[srcOff + 3]</code>. The 539 * <i>x</i> coordinate of the second control point C2 is located at 540 * <code>src[srcOff + 4]</code>, its <i>y</i> at <code>src[srcOff + 541 * 5]</code>. The <i>x</i> coordinate of the end point is located at 542 * <code>src[srcOff + 6]</code>, its <i>y</i> at <code>src[srcOff + 543 * 7]</code>. 544 * 545 * @param srcOff an offset into <code>src</code>, specifying 546 * the index of the start point’s <i>x</i> coordinate. 547 * 548 * @param left an array that will receive the coordinates of the 549 * left half of <code>src</code>. It is acceptable to pass 550 * <code>src</code>. A caller who is not interested in the left half 551 * can pass <code>null</code>. 552 * 553 * @param leftOff an offset into <code>left</code>, specifying the 554 * index where the start point’s <i>x</i> coordinate will be 555 * stored. 556 * 557 * @param right an array that will receive the coordinates of the 558 * right half of <code>src</code>. It is acceptable to pass 559 * <code>src</code> or <code>left</code>. A caller who is not 560 * interested in the right half can pass <code>null</code>. 561 * 562 * @param rightOff an offset into <code>right</code>, specifying the 563 * index where the start point’s <i>x</i> coordinate will be 564 * stored. 565 */ subdivide(double[] src, int srcOff, double[] left, int leftOff, double[] right, int rightOff)566 public static void subdivide(double[] src, int srcOff, 567 double[] left, int leftOff, 568 double[] right, int rightOff) 569 { 570 // To understand this code, please have a look at the image 571 // "CubicCurve2D-3.png" in the sub-directory "doc-files". 572 double src_C1_x, src_C1_y, src_C2_x, src_C2_y; 573 double left_P1_x, left_P1_y; 574 double left_C1_x, left_C1_y, left_C2_x, left_C2_y; 575 double right_C1_x, right_C1_y, right_C2_x, right_C2_y; 576 double right_P2_x, right_P2_y; 577 double Mid_x, Mid_y; // Mid = left.P2 = right.P1 578 579 left_P1_x = src[srcOff]; 580 left_P1_y = src[srcOff + 1]; 581 src_C1_x = src[srcOff + 2]; 582 src_C1_y = src[srcOff + 3]; 583 src_C2_x = src[srcOff + 4]; 584 src_C2_y = src[srcOff + 5]; 585 right_P2_x = src[srcOff + 6]; 586 right_P2_y = src[srcOff + 7]; 587 588 left_C1_x = (left_P1_x + src_C1_x) / 2; 589 left_C1_y = (left_P1_y + src_C1_y) / 2; 590 right_C2_x = (right_P2_x + src_C2_x) / 2; 591 right_C2_y = (right_P2_y + src_C2_y) / 2; 592 Mid_x = (src_C1_x + src_C2_x) / 2; 593 Mid_y = (src_C1_y + src_C2_y) / 2; 594 left_C2_x = (left_C1_x + Mid_x) / 2; 595 left_C2_y = (left_C1_y + Mid_y) / 2; 596 right_C1_x = (Mid_x + right_C2_x) / 2; 597 right_C1_y = (Mid_y + right_C2_y) / 2; 598 Mid_x = (left_C2_x + right_C1_x) / 2; 599 Mid_y = (left_C2_y + right_C1_y) / 2; 600 601 if (left != null) 602 { 603 left[leftOff] = left_P1_x; 604 left[leftOff + 1] = left_P1_y; 605 left[leftOff + 2] = left_C1_x; 606 left[leftOff + 3] = left_C1_y; 607 left[leftOff + 4] = left_C2_x; 608 left[leftOff + 5] = left_C2_y; 609 left[leftOff + 6] = Mid_x; 610 left[leftOff + 7] = Mid_y; 611 } 612 613 if (right != null) 614 { 615 right[rightOff] = Mid_x; 616 right[rightOff + 1] = Mid_y; 617 right[rightOff + 2] = right_C1_x; 618 right[rightOff + 3] = right_C1_y; 619 right[rightOff + 4] = right_C2_x; 620 right[rightOff + 5] = right_C2_y; 621 right[rightOff + 6] = right_P2_x; 622 right[rightOff + 7] = right_P2_y; 623 } 624 } 625 626 627 /** 628 * Finds the non-complex roots of a cubic equation, placing the 629 * results into the same array as the equation coefficients. The 630 * following equation is being solved: 631 * 632 * <blockquote><code>eqn[3]</code> · <i>x</i><sup>3</sup> 633 * + <code>eqn[2]</code> · <i>x</i><sup>2</sup> 634 * + <code>eqn[1]</code> · <i>x</i> 635 * + <code>eqn[0]</code> 636 * = 0 637 * </blockquote> 638 * 639 * <p>For some background about solving cubic equations, see the 640 * article <a 641 * href="http://planetmath.org/encyclopedia/CubicFormula.html" 642 * >“Cubic Formula”</a> in <a 643 * href="http://planetmath.org/" >PlanetMath</a>. For an extensive 644 * library of numerical algorithms written in the C programming 645 * language, see the <a href= "http://www.gnu.org/software/gsl/">GNU 646 * Scientific Library</a>, from which this implementation was 647 * adapted. 648 * 649 * @param eqn an array with the coefficients of the equation. When 650 * this procedure has returned, <code>eqn</code> will contain the 651 * non-complex solutions of the equation, in no particular order. 652 * 653 * @return the number of non-complex solutions. A result of 0 654 * indicates that the equation has no non-complex solutions. A 655 * result of -1 indicates that the equation is constant (i.e., 656 * always or never zero). 657 * 658 * @see #solveCubic(double[], double[]) 659 * @see QuadCurve2D#solveQuadratic(double[],double[]) 660 * 661 * @author <a href="mailto:bjg@network-theory.com">Brian Gough</a> 662 * (original C implementation in the <a href= 663 * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>) 664 * 665 * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> 666 * (adaptation to Java) 667 */ solveCubic(double[] eqn)668 public static int solveCubic(double[] eqn) 669 { 670 return solveCubic(eqn, eqn); 671 } 672 673 674 /** 675 * Finds the non-complex roots of a cubic equation. The following 676 * equation is being solved: 677 * 678 * <blockquote><code>eqn[3]</code> · <i>x</i><sup>3</sup> 679 * + <code>eqn[2]</code> · <i>x</i><sup>2</sup> 680 * + <code>eqn[1]</code> · <i>x</i> 681 * + <code>eqn[0]</code> 682 * = 0 683 * </blockquote> 684 * 685 * <p>For some background about solving cubic equations, see the 686 * article <a 687 * href="http://planetmath.org/encyclopedia/CubicFormula.html" 688 * >“Cubic Formula”</a> in <a 689 * href="http://planetmath.org/" >PlanetMath</a>. For an extensive 690 * library of numerical algorithms written in the C programming 691 * language, see the <a href= "http://www.gnu.org/software/gsl/">GNU 692 * Scientific Library</a>, from which this implementation was 693 * adapted. 694 * 695 * @see QuadCurve2D#solveQuadratic(double[],double[]) 696 * 697 * @param eqn an array with the coefficients of the equation. 698 * 699 * @param res an array into which the non-complex roots will be 700 * stored. The results may be in an arbitrary order. It is safe to 701 * pass the same array object reference for both <code>eqn</code> 702 * and <code>res</code>. 703 * 704 * @return the number of non-complex solutions. A result of 0 705 * indicates that the equation has no non-complex solutions. A 706 * result of -1 indicates that the equation is constant (i.e., 707 * always or never zero). 708 * 709 * @author <a href="mailto:bjg@network-theory.com">Brian Gough</a> 710 * (original C implementation in the <a href= 711 * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>) 712 * 713 * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> 714 * (adaptation to Java) 715 */ solveCubic(double[] eqn, double[] res)716 public static int solveCubic(double[] eqn, double[] res) 717 { 718 // Adapted from poly/solve_cubic.c in the GNU Scientific Library 719 // (GSL), revision 1.7 of 2003-07-26. For the original source, see 720 // http://www.gnu.org/software/gsl/ 721 // 722 // Brian Gough, the author of that code, has granted the 723 // permission to use it in GNU Classpath under the GNU Classpath 724 // license, and has assigned the copyright to the Free Software 725 // Foundation. 726 // 727 // The Java implementation is very similar to the GSL code, but 728 // not a strict one-to-one copy. For example, GSL would sort the 729 // result. 730 731 double a, b, c, q, r, Q, R; 732 double c3, Q3, R2, CR2, CQ3; 733 734 // If the cubic coefficient is zero, we have a quadratic equation. 735 c3 = eqn[3]; 736 if (c3 == 0) 737 return QuadCurve2D.solveQuadratic(eqn, res); 738 739 // Divide the equation by the cubic coefficient. 740 c = eqn[0] / c3; 741 b = eqn[1] / c3; 742 a = eqn[2] / c3; 743 744 // We now need to solve x^3 + ax^2 + bx + c = 0. 745 q = a * a - 3 * b; 746 r = 2 * a * a * a - 9 * a * b + 27 * c; 747 748 Q = q / 9; 749 R = r / 54; 750 751 Q3 = Q * Q * Q; 752 R2 = R * R; 753 754 CR2 = 729 * r * r; 755 CQ3 = 2916 * q * q * q; 756 757 if (R == 0 && Q == 0) 758 { 759 // The GNU Scientific Library would return three identical 760 // solutions in this case. 761 res[0] = -a/3; 762 return 1; 763 } 764 765 if (CR2 == CQ3) 766 { 767 /* this test is actually R2 == Q3, written in a form suitable 768 for exact computation with integers */ 769 770 /* Due to finite precision some double roots may be missed, and 771 considered to be a pair of complex roots z = x +/- epsilon i 772 close to the real axis. */ 773 774 double sqrtQ = Math.sqrt(Q); 775 776 if (R > 0) 777 { 778 res[0] = -2 * sqrtQ - a/3; 779 res[1] = sqrtQ - a/3; 780 } 781 else 782 { 783 res[0] = -sqrtQ - a/3; 784 res[1] = 2 * sqrtQ - a/3; 785 } 786 return 2; 787 } 788 789 if (CR2 < CQ3) /* equivalent to R2 < Q3 */ 790 { 791 double sqrtQ = Math.sqrt(Q); 792 double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; 793 double theta = Math.acos(R / sqrtQ3); 794 double norm = -2 * sqrtQ; 795 res[0] = norm * Math.cos(theta / 3) - a / 3; 796 res[1] = norm * Math.cos((theta + 2.0 * Math.PI) / 3) - a/3; 797 res[2] = norm * Math.cos((theta - 2.0 * Math.PI) / 3) - a/3; 798 799 // The GNU Scientific Library sorts the results. We don't. 800 return 3; 801 } 802 803 double sgnR = (R >= 0 ? 1 : -1); 804 double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0/3.0); 805 double B = Q / A ; 806 res[0] = A + B - a/3; 807 return 1; 808 } 809 810 811 /** 812 * Determines whether a position lies inside the area that is bounded 813 * by the curve and the straight line connecting its end points. 814 * 815 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" 816 * alt="A drawing of the area spanned by the curve" /> 817 * 818 * <p>The above drawing illustrates in which area points are 819 * considered “contained” in a CubicCurve2D. 820 */ contains(double x, double y)821 public boolean contains(double x, double y) 822 { 823 // XXX Implement. 824 throw new Error("not implemented"); 825 } 826 827 828 /** 829 * Determines whether a point lies inside the area that is bounded 830 * by the curve and the straight line connecting its end points. 831 * 832 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" 833 * alt="A drawing of the area spanned by the curve" /> 834 * 835 * <p>The above drawing illustrates in which area points are 836 * considered “contained” in a CubicCurve2D. 837 */ contains(Point2D p)838 public boolean contains(Point2D p) 839 { 840 return contains(p.getX(), p.getY()); 841 } 842 843 intersects(double x, double y, double w, double h)844 public boolean intersects(double x, double y, double w, double h) 845 { 846 // XXX Implement. 847 throw new Error("not implemented"); 848 } 849 850 intersects(Rectangle2D r)851 public boolean intersects(Rectangle2D r) 852 { 853 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 854 } 855 856 contains(double x, double y, double w, double h)857 public boolean contains(double x, double y, double w, double h) 858 { 859 // XXX Implement. 860 throw new Error("not implemented"); 861 } 862 863 contains(Rectangle2D r)864 public boolean contains(Rectangle2D r) 865 { 866 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 867 } 868 869 870 /** 871 * Determines the smallest rectangle that encloses the 872 * curve’s start, end and control points. As the illustration 873 * below shows, the invisible control points may cause the bounds to 874 * be much larger than the area that is actually covered by the 875 * curve. 876 * 877 * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180" 878 * alt="An illustration of the bounds of a CubicCurve2D" /> 879 */ getBounds()880 public Rectangle getBounds() 881 { 882 return getBounds2D().getBounds(); 883 } 884 885 getPathIterator(final AffineTransform at)886 public PathIterator getPathIterator(final AffineTransform at) 887 { 888 return new PathIterator() 889 { 890 /** Current coordinate. */ 891 private int current = 0; 892 893 public int getWindingRule() 894 { 895 return WIND_NON_ZERO; 896 } 897 898 public boolean isDone() 899 { 900 return current >= 2; 901 } 902 903 public void next() 904 { 905 current++; 906 } 907 908 public int currentSegment(float[] coords) 909 { 910 int result; 911 switch (current) 912 { 913 case 0: 914 coords[0] = (float) getX1(); 915 coords[1] = (float) getY1(); 916 result = SEG_MOVETO; 917 break; 918 case 1: 919 coords[0] = (float) getCtrlX1(); 920 coords[1] = (float) getCtrlY1(); 921 coords[2] = (float) getCtrlX2(); 922 coords[3] = (float) getCtrlY2(); 923 coords[4] = (float) getX2(); 924 coords[5] = (float) getY2(); 925 result = SEG_CUBICTO; 926 break; 927 default: 928 throw new NoSuchElementException("cubic iterator out of bounds"); 929 } 930 if (at != null) 931 at.transform(coords, 0, coords, 0, 3); 932 return result; 933 } 934 935 public int currentSegment(double[] coords) 936 { 937 int result; 938 switch (current) 939 { 940 case 0: 941 coords[0] = getX1(); 942 coords[1] = getY1(); 943 result = SEG_MOVETO; 944 break; 945 case 1: 946 coords[0] = getCtrlX1(); 947 coords[1] = getCtrlY1(); 948 coords[2] = getCtrlX2(); 949 coords[3] = getCtrlY2(); 950 coords[4] = getX2(); 951 coords[5] = getY2(); 952 result = SEG_CUBICTO; 953 break; 954 default: 955 throw new NoSuchElementException("cubic iterator out of bounds"); 956 } 957 if (at != null) 958 at.transform(coords, 0, coords, 0, 3); 959 return result; 960 } 961 }; 962 } 963 964 getPathIterator(AffineTransform at, double flatness)965 public PathIterator getPathIterator(AffineTransform at, double flatness) 966 { 967 return new FlatteningPathIterator(getPathIterator(at), flatness); 968 } 969 970 971 /** 972 * Create a new curve with the same contents as this one. 973 * 974 * @return the clone. 975 */ clone()976 public Object clone() 977 { 978 try 979 { 980 return super.clone(); 981 } 982 catch (CloneNotSupportedException e) 983 { 984 throw (Error) new InternalError().initCause(e); // Impossible 985 } 986 } 987 988 989 /** 990 * A two-dimensional curve that is parameterized with a cubic 991 * function and stores coordinate values in double-precision 992 * floating-point format. 993 * 994 * @see CubicCurve2D.Float 995 * 996 * @author Eric Blake (ebb9@email.byu.edu) 997 * @author Sascha Brawer (brawer@dandelis.ch) 998 */ 999 public static class Double 1000 extends CubicCurve2D 1001 { 1002 /** 1003 * The <i>x</i> coordinate of the curve’s start point. 1004 */ 1005 public double x1; 1006 1007 1008 /** 1009 * The <i>y</i> coordinate of the curve’s start point. 1010 */ 1011 public double y1; 1012 1013 1014 /** 1015 * The <i>x</i> coordinate of the curve’s first control point. 1016 */ 1017 public double ctrlx1; 1018 1019 1020 /** 1021 * The <i>y</i> coordinate of the curve’s first control point. 1022 */ 1023 public double ctrly1; 1024 1025 1026 /** 1027 * The <i>x</i> coordinate of the curve’s second control point. 1028 */ 1029 public double ctrlx2; 1030 1031 1032 /** 1033 * The <i>y</i> coordinate of the curve’s second control point. 1034 */ 1035 public double ctrly2; 1036 1037 1038 /** 1039 * The <i>x</i> coordinate of the curve’s end point. 1040 */ 1041 public double x2; 1042 1043 1044 /** 1045 * The <i>y</i> coordinate of the curve’s end point. 1046 */ 1047 public double y2; 1048 1049 1050 /** 1051 * Constructs a new CubicCurve2D that stores its coordinate values 1052 * in double-precision floating-point format. All points are 1053 * initially at position (0, 0). 1054 */ Double()1055 public Double() 1056 { 1057 } 1058 1059 1060 /** 1061 * Constructs a new CubicCurve2D that stores its coordinate values 1062 * in double-precision floating-point format, specifying the 1063 * initial position of each point. 1064 * 1065 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 1066 * alt="A drawing of a CubicCurve2D" /> 1067 * 1068 * @param x1 the <i>x</i> coordinate of the curve’s start 1069 * point. 1070 * 1071 * @param y1 the <i>y</i> coordinate of the curve’s start 1072 * point. 1073 * 1074 * @param cx1 the <i>x</i> coordinate of the curve’s first 1075 * control point. 1076 * 1077 * @param cy1 the <i>y</i> coordinate of the curve’s first 1078 * control point. 1079 * 1080 * @param cx2 the <i>x</i> coordinate of the curve’s second 1081 * control point. 1082 * 1083 * @param cy2 the <i>y</i> coordinate of the curve’s second 1084 * control point. 1085 * 1086 * @param x2 the <i>x</i> coordinate of the curve’s end 1087 * point. 1088 * 1089 * @param y2 the <i>y</i> coordinate of the curve’s end 1090 * point. 1091 */ Double(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2)1092 public Double(double x1, double y1, double cx1, double cy1, 1093 double cx2, double cy2, double x2, double y2) 1094 { 1095 this.x1 = x1; 1096 this.y1 = y1; 1097 ctrlx1 = cx1; 1098 ctrly1 = cy1; 1099 ctrlx2 = cx2; 1100 ctrly2 = cy2; 1101 this.x2 = x2; 1102 this.y2 = y2; 1103 } 1104 1105 1106 /** 1107 * Returns the <i>x</i> coordinate of the curve’s start 1108 * point. 1109 */ getX1()1110 public double getX1() 1111 { 1112 return x1; 1113 } 1114 1115 1116 /** 1117 * Returns the <i>y</i> coordinate of the curve’s start 1118 * point. 1119 */ getY1()1120 public double getY1() 1121 { 1122 return y1; 1123 } 1124 1125 1126 /** 1127 * Returns the curve’s start point. 1128 */ getP1()1129 public Point2D getP1() 1130 { 1131 return new Point2D.Double(x1, y1); 1132 } 1133 1134 1135 /** 1136 * Returns the <i>x</i> coordinate of the curve’s first 1137 * control point. 1138 */ getCtrlX1()1139 public double getCtrlX1() 1140 { 1141 return ctrlx1; 1142 } 1143 1144 1145 /** 1146 * Returns the <i>y</i> coordinate of the curve’s first 1147 * control point. 1148 */ getCtrlY1()1149 public double getCtrlY1() 1150 { 1151 return ctrly1; 1152 } 1153 1154 1155 /** 1156 * Returns the curve’s first control point. 1157 */ getCtrlP1()1158 public Point2D getCtrlP1() 1159 { 1160 return new Point2D.Double(ctrlx1, ctrly1); 1161 } 1162 1163 1164 /** 1165 * Returns the <i>x</i> coordinate of the curve’s second 1166 * control point. 1167 */ getCtrlX2()1168 public double getCtrlX2() 1169 { 1170 return ctrlx2; 1171 } 1172 1173 1174 /** 1175 * Returns the <i>y</i> coordinate of the curve’s second 1176 * control point. 1177 */ getCtrlY2()1178 public double getCtrlY2() 1179 { 1180 return ctrly2; 1181 } 1182 1183 1184 /** 1185 * Returns the curve’s second control point. 1186 */ getCtrlP2()1187 public Point2D getCtrlP2() 1188 { 1189 return new Point2D.Double(ctrlx2, ctrly2); 1190 } 1191 1192 1193 /** 1194 * Returns the <i>x</i> coordinate of the curve’s end 1195 * point. 1196 */ getX2()1197 public double getX2() 1198 { 1199 return x2; 1200 } 1201 1202 1203 /** 1204 * Returns the <i>y</i> coordinate of the curve’s end 1205 * point. 1206 */ getY2()1207 public double getY2() 1208 { 1209 return y2; 1210 } 1211 1212 1213 /** 1214 * Returns the curve’s end point. 1215 */ getP2()1216 public Point2D getP2() 1217 { 1218 return new Point2D.Double(x2, y2); 1219 } 1220 1221 1222 /** 1223 * Changes the curve geometry, separately specifying each coordinate 1224 * value. 1225 * 1226 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 1227 * alt="A drawing of a CubicCurve2D" /> 1228 * 1229 * @param x1 the <i>x</i> coordinate of the curve’s new start 1230 * point. 1231 * 1232 * @param y1 the <i>y</i> coordinate of the curve’s new start 1233 * point. 1234 * 1235 * @param cx1 the <i>x</i> coordinate of the curve’s new 1236 * first control point. 1237 * 1238 * @param cy1 the <i>y</i> coordinate of the curve’s new 1239 * first control point. 1240 * 1241 * @param cx2 the <i>x</i> coordinate of the curve’s new 1242 * second control point. 1243 * 1244 * @param cy2 the <i>y</i> coordinate of the curve’s new 1245 * second control point. 1246 * 1247 * @param x2 the <i>x</i> coordinate of the curve’s new end 1248 * point. 1249 * 1250 * @param y2 the <i>y</i> coordinate of the curve’s new end 1251 * point. 1252 */ setCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2)1253 public void setCurve(double x1, double y1, double cx1, double cy1, 1254 double cx2, double cy2, double x2, double y2) 1255 { 1256 this.x1 = x1; 1257 this.y1 = y1; 1258 ctrlx1 = cx1; 1259 ctrly1 = cy1; 1260 ctrlx2 = cx2; 1261 ctrly2 = cy2; 1262 this.x2 = x2; 1263 this.y2 = y2; 1264 } 1265 1266 1267 /** 1268 * Determines the smallest rectangle that encloses the 1269 * curve’s start, end and control points. As the 1270 * illustration below shows, the invisible control points may cause 1271 * the bounds to be much larger than the area that is actually 1272 * covered by the curve. 1273 * 1274 * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180" 1275 * alt="An illustration of the bounds of a CubicCurve2D" /> 1276 */ getBounds2D()1277 public Rectangle2D getBounds2D() 1278 { 1279 double nx1 = Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2)); 1280 double ny1 = Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2)); 1281 double nx2 = Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2)); 1282 double ny2 = Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2)); 1283 return new Rectangle2D.Double(nx1, ny1, nx2 - nx1, ny2 - ny1); 1284 } 1285 } 1286 1287 1288 /** 1289 * A two-dimensional curve that is parameterized with a cubic 1290 * function and stores coordinate values in single-precision 1291 * floating-point format. 1292 * 1293 * @see CubicCurve2D.Float 1294 * 1295 * @author Eric Blake (ebb9@email.byu.edu) 1296 * @author Sascha Brawer (brawer@dandelis.ch) 1297 */ 1298 public static class Float 1299 extends CubicCurve2D 1300 { 1301 /** 1302 * The <i>x</i> coordinate of the curve’s start point. 1303 */ 1304 public float x1; 1305 1306 1307 /** 1308 * The <i>y</i> coordinate of the curve’s start point. 1309 */ 1310 public float y1; 1311 1312 1313 /** 1314 * The <i>x</i> coordinate of the curve’s first control point. 1315 */ 1316 public float ctrlx1; 1317 1318 1319 /** 1320 * The <i>y</i> coordinate of the curve’s first control point. 1321 */ 1322 public float ctrly1; 1323 1324 1325 /** 1326 * The <i>x</i> coordinate of the curve’s second control point. 1327 */ 1328 public float ctrlx2; 1329 1330 1331 /** 1332 * The <i>y</i> coordinate of the curve’s second control point. 1333 */ 1334 public float ctrly2; 1335 1336 1337 /** 1338 * The <i>x</i> coordinate of the curve’s end point. 1339 */ 1340 public float x2; 1341 1342 1343 /** 1344 * The <i>y</i> coordinate of the curve’s end point. 1345 */ 1346 public float y2; 1347 1348 1349 /** 1350 * Constructs a new CubicCurve2D that stores its coordinate values 1351 * in single-precision floating-point format. All points are 1352 * initially at position (0, 0). 1353 */ Float()1354 public Float() 1355 { 1356 } 1357 1358 1359 /** 1360 * Constructs a new CubicCurve2D that stores its coordinate values 1361 * in single-precision floating-point format, specifying the 1362 * initial position of each point. 1363 * 1364 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 1365 * alt="A drawing of a CubicCurve2D" /> 1366 * 1367 * @param x1 the <i>x</i> coordinate of the curve’s start 1368 * point. 1369 * 1370 * @param y1 the <i>y</i> coordinate of the curve’s start 1371 * point. 1372 * 1373 * @param cx1 the <i>x</i> coordinate of the curve’s first 1374 * control point. 1375 * 1376 * @param cy1 the <i>y</i> coordinate of the curve’s first 1377 * control point. 1378 * 1379 * @param cx2 the <i>x</i> coordinate of the curve’s second 1380 * control point. 1381 * 1382 * @param cy2 the <i>y</i> coordinate of the curve’s second 1383 * control point. 1384 * 1385 * @param x2 the <i>x</i> coordinate of the curve’s end 1386 * point. 1387 * 1388 * @param y2 the <i>y</i> coordinate of the curve’s end 1389 * point. 1390 */ Float(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2)1391 public Float(float x1, float y1, float cx1, float cy1, 1392 float cx2, float cy2, float x2, float y2) 1393 { 1394 this.x1 = x1; 1395 this.y1 = y1; 1396 ctrlx1 = cx1; 1397 ctrly1 = cy1; 1398 ctrlx2 = cx2; 1399 ctrly2 = cy2; 1400 this.x2 = x2; 1401 this.y2 = y2; 1402 } 1403 1404 1405 /** 1406 * Returns the <i>x</i> coordinate of the curve’s start 1407 * point. 1408 */ getX1()1409 public double getX1() 1410 { 1411 return x1; 1412 } 1413 1414 1415 /** 1416 * Returns the <i>y</i> coordinate of the curve’s start 1417 * point. 1418 */ getY1()1419 public double getY1() 1420 { 1421 return y1; 1422 } 1423 1424 1425 /** 1426 * Returns the curve’s start point. 1427 */ getP1()1428 public Point2D getP1() 1429 { 1430 return new Point2D.Float(x1, y1); 1431 } 1432 1433 1434 /** 1435 * Returns the <i>x</i> coordinate of the curve’s first 1436 * control point. 1437 */ getCtrlX1()1438 public double getCtrlX1() 1439 { 1440 return ctrlx1; 1441 } 1442 1443 1444 /** 1445 * Returns the <i>y</i> coordinate of the curve’s first 1446 * control point. 1447 */ getCtrlY1()1448 public double getCtrlY1() 1449 { 1450 return ctrly1; 1451 } 1452 1453 1454 /** 1455 * Returns the curve’s first control point. 1456 */ getCtrlP1()1457 public Point2D getCtrlP1() 1458 { 1459 return new Point2D.Float(ctrlx1, ctrly1); 1460 } 1461 1462 1463 /** 1464 * Returns the <i>s</i> coordinate of the curve’s second 1465 * control point. 1466 */ getCtrlX2()1467 public double getCtrlX2() 1468 { 1469 return ctrlx2; 1470 } 1471 1472 1473 /** 1474 * Returns the <i>y</i> coordinate of the curve’s second 1475 * control point. 1476 */ getCtrlY2()1477 public double getCtrlY2() 1478 { 1479 return ctrly2; 1480 } 1481 1482 1483 /** 1484 * Returns the curve’s second control point. 1485 */ getCtrlP2()1486 public Point2D getCtrlP2() 1487 { 1488 return new Point2D.Float(ctrlx2, ctrly2); 1489 } 1490 1491 1492 /** 1493 * Returns the <i>x</i> coordinate of the curve’s end 1494 * point. 1495 */ getX2()1496 public double getX2() 1497 { 1498 return x2; 1499 } 1500 1501 1502 /** 1503 * Returns the <i>y</i> coordinate of the curve’s end 1504 * point. 1505 */ getY2()1506 public double getY2() 1507 { 1508 return y2; 1509 } 1510 1511 1512 /** 1513 * Returns the curve’s end point. 1514 */ getP2()1515 public Point2D getP2() 1516 { 1517 return new Point2D.Float(x2, y2); 1518 } 1519 1520 1521 /** 1522 * Changes the curve geometry, separately specifying each coordinate 1523 * value as a double-precision floating-point number. 1524 * 1525 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 1526 * alt="A drawing of a CubicCurve2D" /> 1527 * 1528 * @param x1 the <i>x</i> coordinate of the curve’s new start 1529 * point. 1530 * 1531 * @param y1 the <i>y</i> coordinate of the curve’s new start 1532 * point. 1533 * 1534 * @param cx1 the <i>x</i> coordinate of the curve’s new 1535 * first control point. 1536 * 1537 * @param cy1 the <i>y</i> coordinate of the curve’s new 1538 * first control point. 1539 * 1540 * @param cx2 the <i>x</i> coordinate of the curve’s new 1541 * second control point. 1542 * 1543 * @param cy2 the <i>y</i> coordinate of the curve’s new 1544 * second control point. 1545 * 1546 * @param x2 the <i>x</i> coordinate of the curve’s new end 1547 * point. 1548 * 1549 * @param y2 the <i>y</i> coordinate of the curve’s new end 1550 * point. 1551 */ setCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2)1552 public void setCurve(double x1, double y1, double cx1, double cy1, 1553 double cx2, double cy2, double x2, double y2) 1554 { 1555 this.x1 = (float) x1; 1556 this.y1 = (float) y1; 1557 ctrlx1 = (float) cx1; 1558 ctrly1 = (float) cy1; 1559 ctrlx2 = (float) cx2; 1560 ctrly2 = (float) cy2; 1561 this.x2 = (float) x2; 1562 this.y2 = (float) y2; 1563 } 1564 1565 1566 /** 1567 * Changes the curve geometry, separately specifying each coordinate 1568 * value as a single-precision floating-point number. 1569 * 1570 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" 1571 * alt="A drawing of a CubicCurve2D" /> 1572 * 1573 * @param x1 the <i>x</i> coordinate of the curve’s new start 1574 * point. 1575 * 1576 * @param y1 the <i>y</i> coordinate of the curve’s new start 1577 * point. 1578 * 1579 * @param cx1 the <i>x</i> coordinate of the curve’s new 1580 * first control point. 1581 * 1582 * @param cy1 the <i>y</i> coordinate of the curve’s new 1583 * first control point. 1584 * 1585 * @param cx2 the <i>x</i> coordinate of the curve’s new 1586 * second control point. 1587 * 1588 * @param cy2 the <i>y</i> coordinate of the curve’s new 1589 * second control point. 1590 * 1591 * @param x2 the <i>x</i> coordinate of the curve’s new end 1592 * point. 1593 * 1594 * @param y2 the <i>y</i> coordinate of the curve’s new end 1595 * point. 1596 */ setCurve(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2)1597 public void setCurve(float x1, float y1, float cx1, float cy1, 1598 float cx2, float cy2, float x2, float y2) 1599 { 1600 this.x1 = x1; 1601 this.y1 = y1; 1602 ctrlx1 = cx1; 1603 ctrly1 = cy1; 1604 ctrlx2 = cx2; 1605 ctrly2 = cy2; 1606 this.x2 = x2; 1607 this.y2 = y2; 1608 } 1609 1610 1611 /** 1612 * Determines the smallest rectangle that encloses the 1613 * curve’s start, end and control points. As the 1614 * illustration below shows, the invisible control points may cause 1615 * the bounds to be much larger than the area that is actually 1616 * covered by the curve. 1617 * 1618 * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180" 1619 * alt="An illustration of the bounds of a CubicCurve2D" /> 1620 */ getBounds2D()1621 public Rectangle2D getBounds2D() 1622 { 1623 float nx1 = (float) Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2)); 1624 float ny1 = (float) Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2)); 1625 float nx2 = (float) Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2)); 1626 float ny2 = (float) Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2)); 1627 return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1); 1628 } 1629 } 1630 } 1631