1. /*
  2. * @(#)QuadCurve2D.java 1.29 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt.geom;
  8. import java.awt.Shape;
  9. import java.awt.Rectangle;
  10. /**
  11. * The <code>QuadCurve2D</code> class defines a quadratic parametric curve
  12. * segment in (x, y) coordinate space.
  13. * <p>
  14. * This class is only the abstract superclass for all objects that
  15. * store a 2D quadratic curve segment.
  16. * The actual storage representation of the coordinates is left to
  17. * the subclass.
  18. *
  19. * @version 1.29, 12/19/03
  20. * @author Jim Graham
  21. */
  22. public abstract class QuadCurve2D implements Shape, Cloneable {
  23. /**
  24. * A quadratic parametric curve segment specified with
  25. * <code>float</code> coordinates.
  26. */
  27. public static class Float extends QuadCurve2D {
  28. /**
  29. * The x coordinate of the start point of the quadratic curve
  30. * segment.
  31. */
  32. public float x1;
  33. /**
  34. * The y coordinate of the start point of the quadratic curve
  35. * segment.
  36. */
  37. public float y1;
  38. /**
  39. * The x coordinate of the control point of the quadratic curve
  40. * segment.
  41. */
  42. public float ctrlx;
  43. /**
  44. * The y coordinate of the control point of the quadratic curve
  45. * segment.
  46. */
  47. public float ctrly;
  48. /**
  49. * The x coordinate of the end point of the quadratic curve
  50. * segment.
  51. */
  52. public float x2;
  53. /**
  54. * The y coordinate of the end point of the quadratic curve
  55. * segment.
  56. */
  57. public float y2;
  58. /**
  59. * Constructs and initializes a <code>QuadCurve2D</code> with
  60. * coordinates (0, 0, 0, 0, 0, 0).
  61. */
  62. public Float() {
  63. }
  64. /**
  65. * Constructs and initializes a <code>QuadCurve2D</code> from the
  66. * specified coordinates.
  67. * @param x1, y1 the starting point coordinates
  68. * @param ctrlx, ctrly the coordinates of the control point
  69. * @param x2, y2 the ending point coordinates
  70. */
  71. public Float(float x1, float y1,
  72. float ctrlx, float ctrly,
  73. float x2, float y2) {
  74. setCurve(x1, y1, ctrlx, ctrly, x2, y2);
  75. }
  76. /**
  77. * Returns the x coordinate of the start point in
  78. * <code>double</code> precision.
  79. * @return the x coordinate of the starting point.
  80. */
  81. public double getX1() {
  82. return (double) x1;
  83. }
  84. /**
  85. * Returns the y coordinate of the start point in
  86. * <code>double</code> precision.
  87. * @return the y coordinate of the starting point.
  88. */
  89. public double getY1() {
  90. return (double) y1;
  91. }
  92. /**
  93. * Returns the start point.
  94. * @return a {@link Point2D} object that is the starting point
  95. * of this <code>QuadCurve2D</code>.
  96. */
  97. public Point2D getP1() {
  98. return new Point2D.Float(x1, y1);
  99. }
  100. /**
  101. * Returns the x coordinate of the control point in
  102. * <code>double</code> precision.
  103. * @return the x coordinate of the control point.
  104. */
  105. public double getCtrlX() {
  106. return (double) ctrlx;
  107. }
  108. /**
  109. * Returns the y coordinate of the control point in
  110. * <code>double</code> precision.
  111. * @return the y coordiante of the control point.
  112. */
  113. public double getCtrlY() {
  114. return (double) ctrly;
  115. }
  116. /**
  117. * Returns the control point.
  118. * @return a <code>Point2D</code> that is the control point of
  119. * this <code>QuadCurve2D</code>.
  120. */
  121. public Point2D getCtrlPt() {
  122. return new Point2D.Float(ctrlx, ctrly);
  123. }
  124. /**
  125. * Returns the x coordinate of the end point in
  126. * <code>double</code> precision.
  127. * @return the x coordinate of the end point.
  128. */
  129. public double getX2() {
  130. return (double) x2;
  131. }
  132. /**
  133. * Returns the y coordinate of the end point in
  134. * <code>double</code> precision.
  135. * @return the y coordiante of the end point.
  136. */
  137. public double getY2() {
  138. return (double) y2;
  139. }
  140. /**
  141. * Returns the end point.
  142. * @return a <code>Point2D</code> that is the end point of this
  143. * <code>QuadCurve2D</code>.
  144. */
  145. public Point2D getP2() {
  146. return new Point2D.Float(x2, y2);
  147. }
  148. /**
  149. * Sets the location of the endpoints and controlpoint of this
  150. * <code>QuadCurve2D</code> to the specified <code>double</code>
  151. * coordinates.
  152. * @param x1, y1 the coordinates of the starting point
  153. * @param ctrlx, ctrly the coordinates of the control point
  154. * @param x2, y2 the coordinates of the ending point
  155. */
  156. public void setCurve(double x1, double y1,
  157. double ctrlx, double ctrly,
  158. double x2, double y2) {
  159. this.x1 = (float) x1;
  160. this.y1 = (float) y1;
  161. this.ctrlx = (float) ctrlx;
  162. this.ctrly = (float) ctrly;
  163. this.x2 = (float) x2;
  164. this.y2 = (float) y2;
  165. }
  166. /**
  167. * Sets the location of the endpoints and controlpoint of this curve
  168. * to the specified <code>float</code> coordinates.
  169. * @param x1, y1 the coordinates of the starting point
  170. * @param ctrlx, ctrly the coordinates of the control point
  171. * @param x2, y2 the coordinates of the ending point
  172. */
  173. public void setCurve(float x1, float y1,
  174. float ctrlx, float ctrly,
  175. float x2, float y2) {
  176. this.x1 = x1;
  177. this.y1 = y1;
  178. this.ctrlx = ctrlx;
  179. this.ctrly = ctrly;
  180. this.x2 = x2;
  181. this.y2 = y2;
  182. }
  183. /**
  184. * Returns the bounding box of this <code>QuadCurve2D</code>.
  185. * @return a {@link Rectangle2D} that is the bounding box
  186. * of the shape of this <code>QuadCurve2D</code>.
  187. */
  188. public Rectangle2D getBounds2D() {
  189. float left = Math.min(Math.min(x1, x2), ctrlx);
  190. float top = Math.min(Math.min(y1, y2), ctrly);
  191. float right = Math.max(Math.max(x1, x2), ctrlx);
  192. float bottom = Math.max(Math.max(y1, y2), ctrly);
  193. return new Rectangle2D.Float(left, top,
  194. right - left, bottom - top);
  195. }
  196. }
  197. /**
  198. * A quadratic parametric curve segment specified with
  199. * <code>double</code> coordinates.
  200. */
  201. public static class Double extends QuadCurve2D {
  202. /**
  203. * The x coordinate of the start point of the quadratic curve
  204. * segment.
  205. */
  206. public double x1;
  207. /**
  208. * The x coordinate of the start point of the quadratic curve
  209. * segment.
  210. */
  211. public double y1;
  212. /**
  213. * The x coordinate of the control point of the quadratic curve
  214. * segment.
  215. */
  216. public double ctrlx;
  217. /**
  218. * The y coordinate of the control point of the quadratic curve
  219. * segment.
  220. */
  221. public double ctrly;
  222. /**
  223. * The x coordinate of the end point of the quadratic curve
  224. * segment.
  225. */
  226. public double x2;
  227. /**
  228. * The y coordinate of the end point of the quadratic curve
  229. * segment.
  230. */
  231. public double y2;
  232. /**
  233. * Constructs and initializes a <code>QuadCurve2D</code> with
  234. * coordinates (0, 0, 0, 0, 0, 0).
  235. */
  236. public Double() {
  237. }
  238. /**
  239. * Constructs and initializes a <code>QuadCurve2D</code> from the
  240. * specified coordinates.
  241. * @param x1, y1 the coordinates of the starting point
  242. * @param ctrlx, ctrly the coordinates of the control point
  243. * @param x2, y2 the coordinates of the ending point
  244. */
  245. public Double(double x1, double y1,
  246. double ctrlx, double ctrly,
  247. double x2, double y2) {
  248. setCurve(x1, y1, ctrlx, ctrly, x2, y2);
  249. }
  250. /**
  251. * Returns the x coordinate of the start point in
  252. * <code>double</code> precision.
  253. * @return the x coordinate of the starting point.
  254. */
  255. public double getX1() {
  256. return x1;
  257. }
  258. /**
  259. * Returns the y coordinate of the start point in
  260. * <code>double</code> precision.
  261. * @return the y coordiante of the starting point.
  262. */
  263. public double getY1() {
  264. return y1;
  265. }
  266. /**
  267. * Returns the start point.
  268. * @return a <code>Point2D</code> that is the starting point
  269. * of this <code>QuadCurve2D</code>.
  270. */
  271. public Point2D getP1() {
  272. return new Point2D.Double(x1, y1);
  273. }
  274. /**
  275. * Returns the x coordinate of the control point in
  276. * <code>double</code> precision.
  277. * @return the x coordinate of the control point.
  278. */
  279. public double getCtrlX() {
  280. return ctrlx;
  281. }
  282. /**
  283. * Returns the y coordinate of the control point in
  284. * <code>double</code> precision.
  285. * @return the y coordiante of the control point.
  286. */
  287. public double getCtrlY() {
  288. return ctrly;
  289. }
  290. /**
  291. * Returns the control point.
  292. * @return a <code>Point2D</code> object that is the control
  293. * point of this <code>QuadCurve2D</code>.
  294. */
  295. public Point2D getCtrlPt() {
  296. return new Point2D.Double(ctrlx, ctrly);
  297. }
  298. /**
  299. * Returns the x coordinate of the end point in
  300. * <code>double</code> precision.
  301. * @return the x coordiante of the end point.
  302. */
  303. public double getX2() {
  304. return x2;
  305. }
  306. /**
  307. * Returns the y coordinate of the end point in
  308. * <code>double</code> precision.
  309. * @return the y coordiante of the end point.
  310. */
  311. public double getY2() {
  312. return y2;
  313. }
  314. /**
  315. * Returns the end point.
  316. * @return a <code>Point2D</code> that is the end point
  317. * of this <code>QuadCurve2D</code>.
  318. */
  319. public Point2D getP2() {
  320. return new Point2D.Double(x2, y2);
  321. }
  322. /**
  323. * Sets the location of the endpoints and controlpoint of this curve
  324. * to the specified <code>double</code> coordinates.
  325. * @param x1, y1 the coordinates of the starting point
  326. * @param ctrlx, ctrly the coordinates of the control point
  327. * @param x2, y2 the coordinates of the ending point
  328. */
  329. public void setCurve(double x1, double y1,
  330. double ctrlx, double ctrly,
  331. double x2, double y2) {
  332. this.x1 = x1;
  333. this.y1 = y1;
  334. this.ctrlx = ctrlx;
  335. this.ctrly = ctrly;
  336. this.x2 = x2;
  337. this.y2 = y2;
  338. }
  339. /**
  340. * Returns the bounding box of this <code>QuadCurve2D</code>.
  341. * @return a <code>Rectangle2D</code> that is the bounding
  342. * box of the shape of this <code>QuadCurve2D</code>.
  343. */
  344. public Rectangle2D getBounds2D() {
  345. double left = Math.min(Math.min(x1, x2), ctrlx);
  346. double top = Math.min(Math.min(y1, y2), ctrly);
  347. double right = Math.max(Math.max(x1, x2), ctrlx);
  348. double bottom = Math.max(Math.max(y1, y2), ctrly);
  349. return new Rectangle2D.Double(left, top,
  350. right - left, bottom - top);
  351. }
  352. }
  353. /**
  354. * This is an abstract class that cannot be instantiated directly.
  355. * Type-specific implementation subclasses are available for
  356. * instantiation and provide a number of formats for storing
  357. * the information necessary to satisfy the various accessor
  358. * methods below.
  359. *
  360. * @see java.awt.geom.QuadCurve2D.Float
  361. * @see java.awt.geom.QuadCurve2D.Double
  362. */
  363. protected QuadCurve2D() {
  364. }
  365. /**
  366. * Returns the x coordinate of the start point in
  367. * <code>double</code> in precision.
  368. * @return the x coordinate of the start point.
  369. */
  370. public abstract double getX1();
  371. /**
  372. * Returns the y coordinate of the start point in
  373. * <code>double</code> precision.
  374. * @return the y coordinate of the start point.
  375. */
  376. public abstract double getY1();
  377. /**
  378. * Returns the start point.
  379. * @return a <code>Point2D</code> that is the start point of this
  380. * <code>QuadCurve2D</code>.
  381. */
  382. public abstract Point2D getP1();
  383. /**
  384. * Returns the x coordinate of the control point in
  385. * <code>double</code> precision.
  386. * @return x coordinate the control point
  387. */
  388. public abstract double getCtrlX();
  389. /**
  390. * Returns the y coordinate of the control point in
  391. * <code>double</code> precision.
  392. * @return the y coordinate of the control point.
  393. */
  394. public abstract double getCtrlY();
  395. /**
  396. * Returns the control point.
  397. * @return a <code>Point2D</code> that is the control point of this
  398. * <code>Point2D</code>.
  399. */
  400. public abstract Point2D getCtrlPt();
  401. /**
  402. * Returns the x coordinate of the end point in
  403. * <code>double</code> precision.
  404. * @return the x coordiante of the end point.
  405. */
  406. public abstract double getX2();
  407. /**
  408. * Returns the y coordinate of the end point in
  409. * <code>double</code> precision.
  410. * @return the y coordinate of the end point.
  411. */
  412. public abstract double getY2();
  413. /**
  414. * Returns the end point.
  415. * @return a <code>Point</code> object that is the end point
  416. * of this <code>Point2D</code>.
  417. */
  418. public abstract Point2D getP2();
  419. /**
  420. * Sets the location of the endpoints and controlpoint of this curve
  421. * to the specified <code>double</code> coordinates.
  422. * @param x1, y1 the coordinates of the starting point
  423. * @param ctrlx, ctrly the coordinates of the control point
  424. * @param x2, y2 the coordinates of the ending point
  425. */
  426. public abstract void setCurve(double x1, double y1,
  427. double ctrlx, double ctrly,
  428. double x2, double y2);
  429. /**
  430. * Sets the location of the endpoints and controlpoints of this
  431. * <code>QuadCurve2D</code> to the <code>double</code> coordinates at
  432. * the specified offset in the specified array.
  433. * @param coords the array containing coordinate values
  434. * @param offset the index into the array from which to start
  435. * getting the coordinate values and assigning them to this
  436. * <code>QuadCurve2D</code>
  437. */
  438. public void setCurve(double[] coords, int offset) {
  439. setCurve(coords[offset + 0], coords[offset + 1],
  440. coords[offset + 2], coords[offset + 3],
  441. coords[offset + 4], coords[offset + 5]);
  442. }
  443. /**
  444. * Sets the location of the endpoints and controlpoint of this
  445. * <code>QuadCurve2D</code> to the specified <code>Point2D</code>
  446. * coordinates.
  447. * @param p1 the starting point
  448. * @param cp the control point
  449. * @param p2 the ending point
  450. */
  451. public void setCurve(Point2D p1, Point2D cp, Point2D p2) {
  452. setCurve(p1.getX(), p1.getY(),
  453. cp.getX(), cp.getY(),
  454. p2.getX(), p2.getY());
  455. }
  456. /**
  457. * Sets the location of the endpoints and controlpoints of this
  458. * <code>QuadCurve2D</code> to the coordinates of the
  459. * <code>Point2D</code> objects at the specified offset in
  460. * the specified array.
  461. * @param pts an array containing <code>Point2D</code> that define
  462. * coordinate values
  463. * @param offset the index into <code>pts</code> at which to start
  464. * getting the coordinate values and assigning them to this
  465. * <code>QuadCurve2D</code>
  466. */
  467. public void setCurve(Point2D[] pts, int offset) {
  468. setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
  469. pts[offset + 1].getX(), pts[offset + 1].getY(),
  470. pts[offset + 2].getX(), pts[offset + 2].getY());
  471. }
  472. /**
  473. * Sets the location of the endpoints and controlpoint of this
  474. * <code>QuadCurve2D</code> to the same as those in the specified
  475. * <code>QuadCurve2D</code>.
  476. * @param c the specified <code>QuadCurve2D</code>
  477. */
  478. public void setCurve(QuadCurve2D c) {
  479. setCurve(c.getX1(), c.getY1(),
  480. c.getCtrlX(), c.getCtrlY(),
  481. c.getX2(), c.getY2());
  482. }
  483. /**
  484. * Returns the square of the flatness, or maximum distance of a
  485. * controlpoint from the line connecting the endpoints, of the
  486. * quadratic curve specified by the indicated controlpoints.
  487. * @param x1, y1 the coordinates of the starting point
  488. * @param ctrlx, ctrly the coordinates of the control point
  489. * @param x2, y2 the coordinates of the ending point
  490. * @return the square of the flatness of the quadratic curve
  491. * defined by the specified coordinates.
  492. */
  493. public static double getFlatnessSq(double x1, double y1,
  494. double ctrlx, double ctrly,
  495. double x2, double y2) {
  496. return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly);
  497. }
  498. /**
  499. * Returns the flatness, or maximum distance of a
  500. * controlpoint from the line connecting the endpoints, of the
  501. * quadratic curve specified by the indicated controlpoints.
  502. * @param x1, y1 the coordinates of the starting point
  503. * @param ctrlx, ctrly the coordinates of the control point
  504. * @param x2, y2 the coordinates of the ending point
  505. * @return the flatness of the quadratic curve defined by the
  506. * specified coordinates.
  507. */
  508. public static double getFlatness(double x1, double y1,
  509. double ctrlx, double ctrly,
  510. double x2, double y2) {
  511. return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly);
  512. }
  513. /**
  514. * Returns the square of the flatness, or maximum distance of a
  515. * controlpoint from the line connecting the endpoints, of the
  516. * quadratic curve specified by the controlpoints stored in the
  517. * indicated array at the indicated index.
  518. * @param coords an array containing coordinate values
  519. * @param offset the index into <code>coords</code> at which to
  520. * to start getting the values from the array and
  521. * assigning them to a quadratic curve
  522. * @return the flatness of the quadratic curve that is defined by the
  523. * values in the specified array at the specified index.
  524. */
  525. public static double getFlatnessSq(double coords[], int offset) {
  526. return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1],
  527. coords[offset + 4], coords[offset + 5],
  528. coords[offset + 2], coords[offset + 3]);
  529. }
  530. /**
  531. * Returns the flatness, or maximum distance of a
  532. * controlpoint from the line connecting the endpoints, of the
  533. * quadratic curve specified by the controlpoints stored in the
  534. * indicated array at the indicated index.
  535. * @param coords an array containing coordinate values
  536. * @param offset the index into <code>coords</code> at which to
  537. * start getting the coordinate values and assigning
  538. * them to a quadratic curve
  539. * @return the flatness of a quadratic curve defined by the
  540. * specified array at the specified offset.
  541. */
  542. public static double getFlatness(double coords[], int offset) {
  543. return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1],
  544. coords[offset + 4], coords[offset + 5],
  545. coords[offset + 2], coords[offset + 3]);
  546. }
  547. /**
  548. * Returns the square of the flatness, or maximum distance of a
  549. * controlpoint from the line connecting the endpoints, of this
  550. * <code>QuadCurve2D</code>.
  551. * @return the square of the flatness of this
  552. * <code>QuadCurve2D</code>.
  553. */
  554. public double getFlatnessSq() {
  555. return Line2D.ptSegDistSq(getX1(), getY1(),
  556. getX2(), getY2(),
  557. getCtrlX(), getCtrlY());
  558. }
  559. /**
  560. * Returns the flatness, or maximum distance of a
  561. * controlpoint from the line connecting the endpoints, of this
  562. * <code>QuadCurve2D</code>.
  563. * @return the flatness of this <code>QuadCurve2D</code>.
  564. */
  565. public double getFlatness() {
  566. return Line2D.ptSegDist(getX1(), getY1(),
  567. getX2(), getY2(),
  568. getCtrlX(), getCtrlY());
  569. }
  570. /**
  571. * Subdivides this <code>QuadCurve2D</code> and stores the resulting
  572. * two subdivided curves into the <code>left</code> and
  573. * <code>right</code> curve parameters.
  574. * Either or both of the <code>left</code> and <code>right</code>
  575. * objects can be the same as this <code>QuadCurve2D</code> or
  576. * <code>null</code>.
  577. * @param left the <code>QuadCurve2D</code> object for storing the
  578. * left or first half of the subdivided curve
  579. * @param right the <code>QuadCurve2D</code> object for storing the
  580. * right or second half of the subdivided curve
  581. */
  582. public void subdivide(QuadCurve2D left, QuadCurve2D right) {
  583. subdivide(this, left, right);
  584. }
  585. /**
  586. * Subdivides the quadratic curve specified by the <code>src</code>
  587. * parameter and stores the resulting two subdivided curves into the
  588. * <code>left</code> and <code>right</code> curve parameters.
  589. * Either or both of the <code>left</code> and <code>right</code>
  590. * objects can be the same as the <code>src</code> object or
  591. * <code>null</code>.
  592. * @param src the quadratic curve to be subdivided
  593. * @param left the <code>QuadCurve2D</code> object for storing the
  594. * left or first half of the subdivided curve
  595. * @param right the <code>QuadCurve2D</code> object for storing the
  596. * right or second half of the subdivided curve
  597. */
  598. public static void subdivide(QuadCurve2D src,
  599. QuadCurve2D left,
  600. QuadCurve2D right) {
  601. double x1 = src.getX1();
  602. double y1 = src.getY1();
  603. double ctrlx = src.getCtrlX();
  604. double ctrly = src.getCtrlY();
  605. double x2 = src.getX2();
  606. double y2 = src.getY2();
  607. double ctrlx1 = (x1 + ctrlx) / 2.0;
  608. double ctrly1 = (y1 + ctrly) / 2.0;
  609. double ctrlx2 = (x2 + ctrlx) / 2.0;
  610. double ctrly2 = (y2 + ctrly) / 2.0;
  611. ctrlx = (ctrlx1 + ctrlx2) / 2.0;
  612. ctrly = (ctrly1 + ctrly2) / 2.0;
  613. if (left != null) {
  614. left.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx, ctrly);
  615. }
  616. if (right != null) {
  617. right.setCurve(ctrlx, ctrly, ctrlx2, ctrly2, x2, y2);
  618. }
  619. }
  620. /**
  621. * Subdivides the quadratic curve specified by the coordinates
  622. * stored in the <code>src</code> array at indices
  623. * <code>srcoff</code> through <code>srcoff</code> + 5
  624. * and stores the resulting two subdivided curves into the two
  625. * result arrays at the corresponding indices.
  626. * Either or both of the <code>left</code> and <code>right</code>
  627. * arrays can be <code>null</code> or a reference to the same array
  628. * and offset as the <code>src</code> array.
  629. * Note that the last point in the first subdivided curve is the
  630. * same as the first point in the second subdivided curve. Thus,
  631. * it is possible to pass the same array for <code>left</code> and
  632. * <code>right</code> and to use offsets such that
  633. * <code>rightoff</code> equals <code>leftoff</code> + 4 in order
  634. * to avoid allocating extra storage for this common point.
  635. * @param src the array holding the coordinates for the source curve
  636. * @param srcoff the offset into the array of the beginning of the
  637. * the 6 source coordinates
  638. * @param left the array for storing the coordinates for the first
  639. * half of the subdivided curve
  640. * @param leftoff the offset into the array of the beginning of the
  641. * the 6 left coordinates
  642. * @param right the array for storing the coordinates for the second
  643. * half of the subdivided curve
  644. * @param rightoff the offset into the array of the beginning of the
  645. * the 6 right coordinates
  646. */
  647. public static void subdivide(double src[], int srcoff,
  648. double left[], int leftoff,
  649. double right[], int rightoff) {
  650. double x1 = src[srcoff + 0];
  651. double y1 = src[srcoff + 1];
  652. double ctrlx = src[srcoff + 2];
  653. double ctrly = src[srcoff + 3];
  654. double x2 = src[srcoff + 4];
  655. double y2 = src[srcoff + 5];
  656. if (left != null) {
  657. left[leftoff + 0] = x1;
  658. left[leftoff + 1] = y1;
  659. }
  660. if (right != null) {
  661. right[rightoff + 4] = x2;
  662. right[rightoff + 5] = y2;
  663. }
  664. x1 = (x1 + ctrlx) / 2.0;
  665. y1 = (y1 + ctrly) / 2.0;
  666. x2 = (x2 + ctrlx) / 2.0;
  667. y2 = (y2 + ctrly) / 2.0;
  668. ctrlx = (x1 + x2) / 2.0;
  669. ctrly = (y1 + y2) / 2.0;
  670. if (left != null) {
  671. left[leftoff + 2] = x1;
  672. left[leftoff + 3] = y1;
  673. left[leftoff + 4] = ctrlx;
  674. left[leftoff + 5] = ctrly;
  675. }
  676. if (right != null) {
  677. right[rightoff + 0] = ctrlx;
  678. right[rightoff + 1] = ctrly;
  679. right[rightoff + 2] = x2;
  680. right[rightoff + 3] = y2;
  681. }
  682. }
  683. /**
  684. * Solves the quadratic whose coefficients are in the <code>eqn</code>
  685. * array and places the non-complex roots back into the same array,
  686. * returning the number of roots. The quadratic solved is represented
  687. * by the equation:
  688. * <pre>
  689. * eqn = {C, B, A};
  690. * ax^2 + bx + c = 0
  691. * </pre>
  692. * A return value of <code>-1</code> is used to distinguish a constant
  693. * equation, which might be always 0 or never 0, from an equation that
  694. * has no zeroes.
  695. * @param eqn the array that contains the quadratic coefficients
  696. * @return the number of roots, or <code>-1</code> if the equation is
  697. * a constant
  698. */
  699. public static int solveQuadratic(double eqn[]) {
  700. return solveQuadratic(eqn, eqn);
  701. }
  702. /**
  703. * Solves the quadratic whose coefficients are in the <code>eqn</code>
  704. * array and places the non-complex roots into the <code>res</code>
  705. * array, returning the number of roots.
  706. * The quadratic solved is represented by the equation:
  707. * <pre>
  708. * eqn = {C, B, A};
  709. * ax^2 + bx + c = 0
  710. * </pre>
  711. * A return value of <code>-1</code> is used to distinguish a constant
  712. * equation, which might be always 0 or never 0, from an equation that
  713. * has no zeroes.
  714. * @param eqn the specified array of coefficients to use to solve
  715. * the quadratic equation
  716. * @param res the array that contains the non-complex roots
  717. * resulting from the solution of the quadratic equation
  718. * @return the number of roots, or <code>-1</code> if the equation is
  719. * a constant.
  720. */
  721. public static int solveQuadratic(double eqn[], double res[]) {
  722. double a = eqn[2];
  723. double b = eqn[1];
  724. double c = eqn[0];
  725. int roots = 0;
  726. if (a == 0.0) {
  727. // The quadratic parabola has degenerated to a line.
  728. if (b == 0.0) {
  729. // The line has degenerated to a constant.
  730. return -1;
  731. }
  732. res[roots++] = -c / b;
  733. } else {
  734. // From Numerical Recipes, 5.6, Quadratic and Cubic Equations
  735. double d = b * b - 4.0 * a * c;
  736. if (d < 0.0) {
  737. // If d < 0.0, then there are no roots
  738. return 0;
  739. }
  740. d = Math.sqrt(d);
  741. // For accuracy, calculate one root using:
  742. // (-b +/- d) / 2a
  743. // and the other using:
  744. // 2c / (-b +/- d)
  745. // Choose the sign of the +/- so that b+d gets larger in magnitude
  746. if (b < 0.0) {
  747. d = -d;
  748. }
  749. double q = (b + d) / -2.0;
  750. // We already tested a for being 0 above
  751. res[roots++] = q / a;
  752. if (q != 0.0) {
  753. res[roots++] = c / q;
  754. }
  755. }
  756. return roots;
  757. }
  758. /**
  759. * Tests if a specified coordinate is inside the boundary of the
  760. * shape of this <code>QuadCurve2D</code>.
  761. * @param x, y the specified coordinates
  762. * @return <code>true</code> if the specified coordinate is inside
  763. * the boundary of the shape of this
  764. * <code>QuadCurve2D</code> <code>false</code> otherwise.
  765. */
  766. public boolean contains(double x, double y) {
  767. double x1 = getX1();
  768. double y1 = getY1();
  769. double xc = getCtrlX();
  770. double yc = getCtrlY();
  771. double x2 = getX2();
  772. double y2 = getY2();
  773. /*
  774. * We have a convex shape bounded by quad curve Pc(t)
  775. * and ine Pl(t).
  776. *
  777. * P1 = (x1, y1) - start point of curve
  778. * P2 = (x2, y2) - end point of curve
  779. * Pc = (xc, yc) - control point
  780. *
  781. * Pq(t) = P1*(1 - t)^2 + 2*Pc*t*(1 - t) + P2*t^2 =
  782. * = (P1 - 2*Pc + P2)*t^2 + 2*(Pc - P1)*t + P1
  783. * Pl(t) = P1*(1 - t) + P2*t
  784. * t = [0:1]
  785. *
  786. * P = (x, y) - point of interest
  787. *
  788. * Let's look at second derivative of quad curve equation:
  789. *
  790. * Pq''(t) = 2 * (P1 - 2 * Pc + P2) = Pq''
  791. * It's constant vector.
  792. *
  793. * Let's draw a line through P to be parallel to this
  794. * vector and find the intersection of the quad curve
  795. * and the line.
  796. *
  797. * Pq(t) is point of intersection if system of equations
  798. * below has the solution.
  799. *
  800. * L(s) = P + Pq''*s == Pq(t)
  801. * Pq''*s + (P - Pq(t)) == 0
  802. *
  803. * | xq''*s + (x - xq(t)) == 0
  804. * | yq''*s + (y - yq(t)) == 0
  805. *
  806. * This system has the solution if rank of its matrix equals to 1.
  807. * That is, determinant of the matrix should be zero.
  808. *
  809. * (y - yq(t))*xq'' == (x - xq(t))*yq''
  810. *
  811. * Let's solve this equation with 't' variable.
  812. * Also let kx = x1 - 2*xc + x2
  813. * ky = y1 - 2*yc + y2
  814. *
  815. * t0q = (1/2)*((x - x1)*ky - (y - y1)*kx) /
  816. * ((xc - x1)*ky - (yc - y1)*kx)
  817. *
  818. * Let's do the same for our line Pl(t):
  819. *
  820. * t0l = ((x - x1)*ky - (y - y1)*kx) /
  821. * ((x2 - x1)*ky - (y2 - y1)*kx)
  822. *
  823. * It's easy to check that t0q == t0l. This fact means
  824. * we can compute t0 only one time.
  825. *
  826. * In case t0 < 0 or t0 > 1, we have an intersections outside
  827. * of shape bounds. So, P is definitely out of shape.
  828. *
  829. * In case t0 is inside [0:1], we should calculate Pq(t0)
  830. * and Pl(t0). We have three points for now, and all of them
  831. * lie on one line. So, we just need to detect, is our point
  832. * of interest between points of intersections or not.
  833. *
  834. * If the denominator in the t0q and t0l equations is
  835. * zero, then the points must be collinear and so the
  836. * curve is degenerate and encloses no area. Thus the
  837. * result is false.
  838. */
  839. double kx = x1 - 2 * xc + x2;
  840. double ky = y1 - 2 * yc + y2;
  841. double dx = x - x1;
  842. double dy = y - y1;
  843. double dxl = x2 - x1;
  844. double dyl = y2 - y1;
  845. double t0 = (dx * ky - dy * kx) / (dxl * ky - dyl * kx);
  846. if (t0 < 0 || t0 > 1 || t0 != t0) {
  847. return false;
  848. }
  849. double xb = kx * t0 * t0 + 2 * (xc - x1) * t0 + x1;
  850. double yb = ky * t0 * t0 + 2 * (yc - y1) * t0 + y1;
  851. double xl = dxl * t0 + x1;
  852. double yl = dyl * t0 + y1;
  853. return (x >= xb && x < xl) ||
  854. (x >= xl && x < xb) ||
  855. (y >= yb && y < yl) ||
  856. (y >= yl && y < yb);
  857. }
  858. /**
  859. * Tests if a specified <code>Point2D</code> is inside the boundary of
  860. * the shape of this <code>QuadCurve2D</code>.
  861. * @param p the specified <code>Point2D</code>
  862. * @return <code>true</code> if the specified <code>Point2D</code> is
  863. * inside the boundary of the shape of this
  864. * <code>QuadCurve2D</code>.
  865. */
  866. public boolean contains(Point2D p) {
  867. return contains(p.getX(), p.getY());
  868. }
  869. /*
  870. * Fill an array with the coefficients of the parametric equation
  871. * in t, ready for solving against val with solveQuadratic.
  872. * We currently have:
  873. * val = Py(t) = C1*(1-t)^2 + 2*CP*t*(1-t) + C2*t^2
  874. * = C1 - 2*C1*t + C1*t^2 + 2*CP*t - 2*CP*t^2 + C2*t^2
  875. * = C1 + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2
  876. * 0 = (C1 - val) + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2
  877. * 0 = C + Bt + At^2
  878. * C = C1 - val
  879. * B = 2*CP - 2*C1
  880. * A = C1 - 2*CP + C2
  881. */
  882. private static void fillEqn(double eqn[], double val,
  883. double c1, double cp, double c2) {
  884. eqn[0] = c1 - val;
  885. eqn[1] = cp + cp - c1 - c1;
  886. eqn[2] = c1 - cp - cp + c2;
  887. return;
  888. }
  889. /*
  890. * Evaluate the t values in the first num slots of the vals[] array
  891. * and place the evaluated values back into the same array. Only
  892. * evaluate t values that are within the range <0, 1>, including
  893. * the 0 and 1 ends of the range iff the include0 or include1
  894. * booleans are true. If an "inflection" equation is handed in,
  895. * then any points which represent a point of inflection for that
  896. * quadratic equation are also ignored.
  897. */
  898. private static int evalQuadratic(double vals[], int num,
  899. boolean include0,
  900. boolean include1,
  901. double inflect[],
  902. double c1, double ctrl, double c2) {
  903. int j = 0;
  904. for (int i = 0; i < num; i++) {
  905. double t = vals[i];
  906. if ((include0 ? t >= 0 : t > 0) &&
  907. (include1 ? t <= 1 : t < 1) &&
  908. (inflect == null ||
  909. inflect[1] + 2*inflect[2]*t != 0))
  910. {
  911. double u = 1 - t;
  912. vals[j++] = c1*u*u + 2*ctrl*t*u + c2*t*t;
  913. }
  914. }
  915. return j;
  916. }
  917. private static final int BELOW = -2;
  918. private static final int LOWEDGE = -1;
  919. private static final int INSIDE = 0;
  920. private static final int HIGHEDGE = 1;
  921. private static final int ABOVE = 2;
  922. /*
  923. * Determine where coord lies with respect to the range from
  924. * low to high. It is assumed that low <= high. The return
  925. * value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,
  926. * or ABOVE.
  927. */
  928. private static int getTag(double coord, double low, double high) {
  929. if (coord <= low) {
  930. return (coord < low ? BELOW : LOWEDGE);
  931. }
  932. if (coord >= high) {
  933. return (coord > high ? ABOVE : HIGHEDGE);
  934. }
  935. return INSIDE;
  936. }
  937. /*
  938. * Determine if the pttag represents a coordinate that is already
  939. * in its test range, or is on the border with either of the two
  940. * opttags representing another coordinate that is "towards the
  941. * inside" of that test range. In other words, are either of the
  942. * two "opt" points "drawing the pt inward"?
  943. */
  944. private static boolean inwards(int pttag, int opt1tag, int opt2tag) {
  945. switch (pttag) {
  946. case BELOW:
  947. case ABOVE:
  948. default:
  949. return false;
  950. case LOWEDGE:
  951. return (opt1tag >= INSIDE || opt2tag >= INSIDE);
  952. case INSIDE:
  953. return true;
  954. case HIGHEDGE:
  955. return (opt1tag <= INSIDE || opt2tag <= INSIDE);
  956. }
  957. }
  958. /**
  959. * Tests if the shape of this <code>QuadCurve2D</code> intersects the
  960. * interior of a specified set of rectangular coordinates.
  961. * @param x, y the coordinates of the upper-left corner of the
  962. * specified rectangular area
  963. * @param w the width of the specified rectangular area
  964. * @param h the height of the specified rectangular area
  965. * @return <code>true</code> if the shape of this
  966. * <code>QuadCurve2D</code> intersects the interior of the
  967. * specified set of rectangular coordinates;
  968. * <code>false</code> otherwise.
  969. */
  970. public boolean intersects(double x, double y, double w, double h) {
  971. // Trivially reject non-existant rectangles
  972. if (w < 0 || h < 0) {
  973. return false;
  974. }
  975. // Trivially accept if either endpoint is inside the rectangle
  976. // (not on its border since it may end there and not go inside)
  977. // Record where they lie with respect to the rectangle.
  978. // -1 => left, 0 => inside, 1 => right
  979. double x1 = getX1();
  980. double y1 = getY1();
  981. int x1tag = getTag(x1, x, x+w);
  982. int y1tag = getTag(y1, y, y+h);
  983. if (x1tag == INSIDE && y1tag == INSIDE) {
  984. return true;
  985. }
  986. double x2 = getX2();
  987. double y2 = getY2();
  988. int x2tag = getTag(x2, x, x+w);
  989. int y2tag = getTag(y2, y, y+h);
  990. if (x2tag == INSIDE && y2tag == INSIDE) {
  991. return true;
  992. }
  993. double ctrlx = getCtrlX();
  994. double ctrly = getCtrlY();
  995. int ctrlxtag = getTag(ctrlx, x, x+w);
  996. int ctrlytag = getTag(ctrly, y, y+h);
  997. // Trivially reject if all points are entirely to one side of
  998. // the rectangle.
  999. if (x1tag < INSIDE && x2tag < INSIDE && ctrlxtag < INSIDE) {
  1000. return false; // All points left
  1001. }
  1002. if (y1tag < INSIDE && y2tag < INSIDE && ctrlytag < INSIDE) {
  1003. return false; // All points above
  1004. }
  1005. if (x1tag > INSIDE && x2tag > INSIDE && ctrlxtag > INSIDE) {
  1006. return false; // All points right
  1007. }
  1008. if (y1tag > INSIDE && y2tag > INSIDE && ctrlytag > INSIDE) {
  1009. return false; // All points below
  1010. }
  1011. // Test for endpoints on the edge where either the segment
  1012. // or the curve is headed "inwards" from them
  1013. // Note: These tests are a superset of the fast endpoint tests
  1014. // above and thus repeat those tests, but take more time
  1015. // and cover more cases
  1016. if (inwards(x1tag, x2tag, ctrlxtag) &&
  1017. inwards(y1tag, y2tag, ctrlytag))
  1018. {
  1019. // First endpoint on border with either edge moving inside
  1020. return true;
  1021. }
  1022. if (inwards(x2tag, x1tag, ctrlxtag) &&
  1023. inwards(y2tag, y1tag, ctrlytag))
  1024. {
  1025. // Second endpoint on border with either edge moving inside
  1026. return true;
  1027. }
  1028. // Trivially accept if endpoints span directly across the rectangle
  1029. boolean xoverlap = (x1tag * x2tag <= 0);
  1030. boolean yoverlap = (y1tag * y2tag <= 0);
  1031. if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {
  1032. return true;
  1033. }
  1034. if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {
  1035. return true;
  1036. }
  1037. // We now know that both endpoints are outside the rectangle
  1038. // but the 3 points are not all on one side of the rectangle.
  1039. // Therefore the curve cannot be contained inside the rectangle,
  1040. // but the rectangle might be contained inside the curve, or
  1041. // the curve might intersect the boundary of the rectangle.
  1042. double[] eqn = new double[3];
  1043. double[] res = new double[3];
  1044. if (!yoverlap) {
  1045. // Both y coordinates for the closing segment are above or
  1046. // below the rectangle which means that we can only intersect
  1047. // if the curve crosses the top (or bottom) of the rectangle
  1048. // in more than one place and if those crossing locations
  1049. // span the horizontal range of the rectangle.
  1050. fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly, y2);
  1051. return (solveQuadratic(eqn, res) == 2 &&
  1052. evalQuadratic(res, 2, true, true, null,
  1053. x1, ctrlx, x2) == 2 &&
  1054. getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0);
  1055. }
  1056. // Y ranges overlap. Now we examine the X ranges
  1057. if (!xoverlap) {
  1058. // Both x coordinates for the closing segment are left of
  1059. // or right of the rectangle which means that we can only
  1060. // intersect if the curve crosses the left (or right) edge
  1061. // of the rectangle in more than one place and if those
  1062. // crossing locations span the vertical range of the rectangle.
  1063. fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx, x2);
  1064. return (solveQuadratic(eqn, res) == 2 &&
  1065. evalQuadratic(res, 2, true, true, null,
  1066. y1, ctrly, y2) == 2 &&
  1067. getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0);
  1068. }
  1069. // The X and Y ranges of the endpoints overlap the X and Y
  1070. // ranges of the rectangle, now find out how the endpoint
  1071. // line segment intersects the Y range of the rectangle
  1072. double dx = x2 - x1;
  1073. double dy = y2 - y1;
  1074. double k = y2 * x1 - x2 * y1;
  1075. int c1tag, c2tag;
  1076. if (y1tag == INSIDE) {
  1077. c1tag = x1tag;
  1078. } else {
  1079. c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w);
  1080. }
  1081. if (y2tag == INSIDE) {
  1082. c2tag = x2tag;
  1083. } else {
  1084. c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w);
  1085. }
  1086. // If the part of the line segment that intersects the Y range
  1087. // of the rectangle crosses it horizontally - trivially accept
  1088. if (c1tag * c2tag <= 0) {
  1089. return true;
  1090. }
  1091. // Now we know that both the X and Y ranges intersect and that
  1092. // the endpoint line segment does not directly cross the rectangle.
  1093. //
  1094. // We can almost treat this case like one of the cases above
  1095. // where both endpoints are to one side, except that we will
  1096. // only get one intersection of the curve with the vertical
  1097. // side of the rectangle. This is because the endpoint segment
  1098. // accounts for the other intersection.
  1099. //
  1100. // (Remember there is overlap in both the X and Y ranges which
  1101. // means that the segment must cross at least one vertical edge
  1102. // of the rectangle - in particular, the "near vertical side" -
  1103. // leaving only one intersection for the curve.)
  1104. //
  1105. // Now we calculate the y tags of the two intersections on the
  1106. // "near vertical side" of the rectangle. We will have one with
  1107. // the endpoint segment, and one with the curve. If those two
  1108. // vertical intersections overlap the Y range of the rectangle,
  1109. // we have an intersection. Otherwise, we don't.
  1110. // c1tag = vertical intersection class of the endpoint segment
  1111. //
  1112. // Choose the y tag of the endpoint that was not on the same
  1113. // side of the rectangle as the subsegment calculated above.
  1114. // Note that we can "steal" the existing Y tag of that endpoint
  1115. // since it will be provably the same as the vertical intersection.
  1116. c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);
  1117. // c2tag = vertical intersection class of the curve
  1118. //
  1119. // We have to calculate this one the straightforward way.
  1120. // Note that the c2tag can still tell us which vertical edge
  1121. // to test against.
  1122. fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx, x2);
  1123. int num = solveQuadratic(eqn, res);
  1124. // Note: We should be able to assert(num == 2); since the
  1125. // X range "crosses" (not touches) the vertical boundary,
  1126. // but we pass num to evalQuadratic for completeness.
  1127. evalQuadratic(res, num, true, true, null, y1, ctrly, y2);
  1128. // Note: We can assert(num evals == 1); since one of the
  1129. // 2 crossings will be out of the [0,1] range.
  1130. c2tag = getTag(res[0], y, y+h);
  1131. // Finally, we have an intersection if the two crossings
  1132. // overlap the Y range of the rectangle.
  1133. return (c1tag * c2tag <= 0);
  1134. }
  1135. /**
  1136. * Tests if the shape of this <code>QuadCurve2D</code> intersects the
  1137. * interior of a specified <code>Rectangle2D</code>.
  1138. * @param r the specified <code>Rectangle2D</code>
  1139. * @return <code>true</code> if the shape of this
  1140. * <code>QuadCurve2D</code> intersects the interior of
  1141. * the specified <code>Rectangle2D</code>
  1142. * <code>false</code> otherwise.
  1143. */
  1144. public boolean intersects(Rectangle2D r) {
  1145. return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  1146. }
  1147. /**
  1148. * Tests if the interior of the shape of this
  1149. * <code>QuadCurve2D</code> entirely contains the specified
  1150. * set of rectangular coordinates.
  1151. * @param x, y the coordinates of the upper-left corner of the
  1152. * specified rectangular area
  1153. * @param w the width of the specified rectangular area
  1154. * @param h the height of the specified rectangular area
  1155. * @return <code>true</code> if the interior of the shape of this
  1156. * <code>QuadCurve2D</code> entirely contains the specified
  1157. * rectangluar area; <code>false</code> otherwise.
  1158. */
  1159. public boolean contains(double x, double y, double w, double h) {
  1160. // Assertion: Quadratic curves closed by connecting their
  1161. // endpoints are always convex.
  1162. return (contains(x, y) &&
  1163. contains(x + w, y) &&
  1164. contains(x + w, y + h) &&
  1165. contains(x, y + h));
  1166. }
  1167. /**
  1168. * Tests if the interior of the shape of this
  1169. * <code>QuadCurve2D</code> entirely contains the specified
  1170. * <code>Rectangle2D</code>.
  1171. * @param r the specified <code>Rectangle2D</code>
  1172. * @return <code>true</code> if the interior of the shape of this
  1173. * <code>QuadCurve2D</code> entirely contains the specified
  1174. * <code>Rectangle2D</code> <code>false</code> otherwise.
  1175. */
  1176. public boolean contains(Rectangle2D r) {
  1177. return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  1178. }
  1179. /**
  1180. * Returns the bounding box of this <code>QuadCurve2D</code>.
  1181. * @return a {@link Rectangle} that is the bounding box of the shape
  1182. * of this <code>QuadCurve2D</code>.
  1183. */
  1184. public Rectangle getBounds() {
  1185. return getBounds2D().getBounds();
  1186. }
  1187. /**
  1188. * Returns an iteration object that defines the boundary of the
  1189. * shape of this <code>QuadCurve2D</code>.
  1190. * The iterator for this class is not multi-threaded safe,
  1191. * which means that this <code>QuadCurve2D</code> class does not
  1192. * guarantee that modifications to the geometry of this
  1193. * <code>QuadCurve2D</code> object do not affect any iterations of
  1194. * that geometry that are already in process.
  1195. * @param at an optional {@link AffineTransform} to apply to the
  1196. * shape boundary
  1197. * @return a {@link PathIterator} object that defines the boundary
  1198. * of the shape.
  1199. */
  1200. public PathIterator getPathIterator(AffineTransform at) {
  1201. return new QuadIterator(this, at);
  1202. }
  1203. /**
  1204. * Returns an iteration object that defines the boundary of the
  1205. * flattened shape of this <code>QuadCurve2D</code>.
  1206. * The iterator for this class is not multi-threaded safe,
  1207. * which means that this <code>QuadCurve2D</code> class does not
  1208. * guarantee that modifications to the geometry of this
  1209. * <code>QuadCurve2D</code> object do not affect any iterations of
  1210. * that geometry that are already in process.
  1211. * @param at an optional <code>AffineTransform</code> to apply
  1212. * to the boundary of the shape
  1213. * @param flatness the maximum distance that the control points for a
  1214. * subdivided curve can be with respect to a line connecting
  1215. * the endpoints of this curve before this curve is
  1216. * replaced by a straight line connecting the endpoints.
  1217. * @return a <code>PathIterator</code> object that defines the
  1218. * flattened boundary of the shape.
  1219. */
  1220. public PathIterator getPathIterator(AffineTransform at, double flatness) {
  1221. return new FlatteningPathIterator(getPathIterator(at), flatness);
  1222. }
  1223. /**
  1224. * Creates a new object of the same class and with the same contents
  1225. * as this object.
  1226. *
  1227. * @return a clone of this instance.
  1228. * @exception OutOfMemoryError if there is not enough memory.
  1229. * @see java.lang.Cloneable
  1230. * @since 1.2
  1231. */
  1232. public Object clone() {
  1233. try {
  1234. return super.clone();
  1235. } catch (CloneNotSupportedException e) {
  1236. // this shouldn't happen, since we are Cloneable
  1237. throw new InternalError();
  1238. }
  1239. }
  1240. }