1. /*
  2. * @(#)QuadCurve2D.java 1.18 01/11/29
  3. *
  4. * Copyright 2002 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 10 Feb 1997
  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, y1 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, y1 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, y1 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, y1 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, y1 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 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 equ 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 result array,
  705. * returning the number of roots. The quadratic solved is represented
  706. * 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. * @return the number of roots, or <code>-1</code> if the equation is
  715. * a constant.
  716. */
  717. static int solveQuadratic(double eqn[], double res[]) {
  718. double a = eqn[2];
  719. double b = eqn[1];
  720. double c = eqn[0];
  721. int roots = 0;
  722. if (a == 0.0) {
  723. // The quadratic parabola has degenerated to a line.
  724. if (b == 0.0) {
  725. // The line has degenerated to a constant.
  726. return -1;
  727. }
  728. res[roots++] = -c / b;
  729. } else {
  730. // From Numerical Recipes, 5.6, Quadratic and Cubic Equations
  731. double d = b * b - 4.0 * a * c;
  732. if (d < 0.0) {
  733. // If d < 0.0, then there are no roots
  734. return 0;
  735. }
  736. d = Math.sqrt(d);
  737. // For accuracy, calculate one root using:
  738. // (-b +/- d) / 2a
  739. // and the other using:
  740. // 2c / (-b +/- d)
  741. // Choose the sign of the +/- so that b+d gets larger in magnitude
  742. if (b < 0.0) {
  743. d = -d;
  744. }
  745. double q = (b + d) / -2.0;
  746. // We already tested a for being 0 above
  747. res[roots++] = q / a;
  748. if (q != 0.0) {
  749. res[roots++] = c / q;
  750. }
  751. }
  752. return roots;
  753. }
  754. /**
  755. * Tests if a specified coordinate is inside the boundary of the
  756. * shape of this <code>QuadCurve2D</code>.
  757. * @param x, y the specified coordinates
  758. * @return <code>true</code> if the specified coordinate is inside
  759. * the boundary of the shape of this
  760. * <code>QuadCurve2D</code> <code>false</code> otherwise.
  761. */
  762. public boolean contains(double x, double y) {
  763. // We count the "Y" crossings to determine if the point is
  764. // inside the curve bounded by its closing line.
  765. int crossings = 0;
  766. double x1 = getX1();
  767. double y1 = getY1();
  768. double x2 = getX2();
  769. double y2 = getY2();
  770. // First check for a crossing of the line connecting the endpoints
  771. double dy = y2 - y1;
  772. if ((dy > 0.0 && y >= y1 && y <= y2) ||
  773. (dy < 0.0 && y <= y1 && y >= y2))
  774. {
  775. if (x <= x1 + (y - y1) * (x2 - x1) / dy) {
  776. crossings++;
  777. }
  778. }
  779. // Solve the Y parametric equation for intersections with y
  780. double ctrlx = getCtrlX();
  781. double ctrly = getCtrlY();
  782. boolean include0 = ((y2 - y1) * (ctrly - y1) >= 0);
  783. boolean include1 = ((y1 - y2) * (ctrly - y2) >= 0);
  784. double eqn[] = new double[3];
  785. double res[] = new double[3];
  786. fillEqn(eqn, y, y1, ctrly, y2);
  787. int roots = solveQuadratic(eqn, res);
  788. roots = evalQuadratic(res, roots,
  789. include0, include1, eqn,
  790. x1, ctrlx, x2);
  791. while (--roots >= 0) {
  792. if (x < res[roots]) {
  793. crossings++;
  794. }
  795. }
  796. return ((crossings & 1) == 1);
  797. }
  798. /**
  799. * Tests if a specified <code>Point2D</code> is inside the boundary of
  800. * the shape of this <code>QuadCurve2D</code>.
  801. * @param p the specified <code>Point2D</code>
  802. * @return <code>true</code> if the specified <code>Point2D</code> is
  803. * inside the boundary of the shape of this
  804. * <code>QuadCurve2D</code>.
  805. */
  806. public boolean contains(Point2D p) {
  807. return contains(p.getX(), p.getY());
  808. }
  809. /*
  810. * Fill an array with the coefficients of the parametric equation
  811. * in t, ready for solving against val with solveQuadratic.
  812. * We currently have:
  813. * val = Py(t) = C1*(1-t)^2 + 2*CP*t*(1-t) + C2*t^2
  814. * = C1 - 2*C1*t + C1*t^2 + 2*CP*t - 2*CP*t^2 + C2*t^2
  815. * = C1 + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2
  816. * 0 = (C1 - val) + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2
  817. * 0 = C + Bt + At^2
  818. * C = C1 - val
  819. * B = 2*CP - 2*C1
  820. * A = C1 - 2*CP + C2
  821. */
  822. private static void fillEqn(double eqn[], double val,
  823. double c1, double cp, double c2) {
  824. eqn[0] = c1 - val;
  825. eqn[1] = cp + cp - c1 - c1;
  826. eqn[2] = c1 - cp - cp + c2;
  827. return;
  828. }
  829. /*
  830. * Evaluate the t values in the first num slots of the vals[] array
  831. * and place the evaluated values back into the same array. Only
  832. * evaluate t values that are within the range <0, 1>, including
  833. * the 0 and 1 ends of the range iff the include0 or include1
  834. * booleans are true. If an "inflection" equation is handed in,
  835. * then any points which represent a point of inflection for that
  836. * quadratic equation are also ignored.
  837. */
  838. private static int evalQuadratic(double vals[], int num,
  839. boolean include0,
  840. boolean include1,
  841. double inflect[],
  842. double c1, double ctrl, double c2) {
  843. int j = 0;
  844. for (int i = 0; i < num; i++) {
  845. double t = vals[i];
  846. if ((include0 ? t >= 0 : t > 0) &&
  847. (include1 ? t <= 1 : t < 1) &&
  848. (inflect == null ||
  849. inflect[1] + 2*inflect[2]*t != 0))
  850. {
  851. double u = 1 - t;
  852. vals[j++] = c1*u*u + 2*ctrl*t*u + c2*t*t;
  853. }
  854. }
  855. return j;
  856. }
  857. private static final int BELOW = -2;
  858. private static final int LOWEDGE = -1;
  859. private static final int INSIDE = 0;
  860. private static final int HIGHEDGE = 1;
  861. private static final int ABOVE = 2;
  862. /*
  863. * Determine where coord lies with respect to the range from
  864. * low to high. It is assumed that low <= high. The return
  865. * value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,
  866. * or ABOVE.
  867. */
  868. private static int getTag(double coord, double low, double high) {
  869. if (coord <= low) {
  870. return (coord < low ? BELOW : LOWEDGE);
  871. }
  872. if (coord >= high) {
  873. return (coord > high ? ABOVE : HIGHEDGE);
  874. }
  875. return INSIDE;
  876. }
  877. /*
  878. * Determine if the pttag represents a coordinate that is already
  879. * in its test range, or is on the border with either of the two
  880. * opttags representing another coordinate that is "towards the
  881. * inside" of that test range. In other words, are either of the
  882. * two "opt" points "drawing the pt inward"?
  883. */
  884. private static boolean inwards(int pttag, int opt1tag, int opt2tag) {
  885. switch (pttag) {
  886. case BELOW:
  887. case ABOVE:
  888. default:
  889. return false;
  890. case LOWEDGE:
  891. return (opt1tag >= INSIDE || opt2tag >= INSIDE);
  892. case INSIDE:
  893. return true;
  894. case HIGHEDGE:
  895. return (opt1tag <= INSIDE || opt2tag <= INSIDE);
  896. }
  897. }
  898. /**
  899. * Tests if the shape of this <code>QuadCurve2D</code> intersects the
  900. * interior of a specified set of rectangular coordinates.
  901. * @param x, y the coordinates of the upper-left corner of the
  902. * specified rectangular area
  903. * @param w the width of the specified rectangular area
  904. * @param h the height of the specified rectangular area
  905. * @return <code>true</code> if the shape of this
  906. * <code>QuadCurve2D</code> intersects the interior of the
  907. * specified set of rectangular coordinates;
  908. * <code>false</code> otherwise.
  909. */
  910. public boolean intersects(double x, double y, double w, double h) {
  911. // Trivially reject non-existant rectangles
  912. if (w < 0 || h < 0) {
  913. return false;
  914. }
  915. // Trivially accept if either endpoint is inside the rectangle
  916. // (not on its border since it may end there and not go inside)
  917. // Record where they lie with respect to the rectangle.
  918. // -1 => left, 0 => inside, 1 => right
  919. double x1 = getX1();
  920. double y1 = getY1();
  921. int x1tag = getTag(x1, x, x+w);
  922. int y1tag = getTag(y1, y, y+h);
  923. if (x1tag == INSIDE && y1tag == INSIDE) {
  924. return true;
  925. }
  926. double x2 = getX2();
  927. double y2 = getY2();
  928. int x2tag = getTag(x2, x, x+w);
  929. int y2tag = getTag(y2, y, y+h);
  930. if (x2tag == INSIDE && y2tag == INSIDE) {
  931. return true;
  932. }
  933. double ctrlx = getCtrlX();
  934. double ctrly = getCtrlY();
  935. int ctrlxtag = getTag(ctrlx, x, x+w);
  936. int ctrlytag = getTag(ctrly, y, y+h);
  937. // Trivially reject if all points are entirely to one side of
  938. // the rectangle.
  939. if (x1tag < INSIDE && x2tag < INSIDE && ctrlxtag < INSIDE) {
  940. return false; // All points left
  941. }
  942. if (y1tag < INSIDE && y2tag < INSIDE && ctrlytag < INSIDE) {
  943. return false; // All points above
  944. }
  945. if (x1tag > INSIDE && x2tag > INSIDE && ctrlxtag > INSIDE) {
  946. return false; // All points right
  947. }
  948. if (y1tag > INSIDE && y2tag > INSIDE && ctrlytag > INSIDE) {
  949. return false; // All points below
  950. }
  951. // Test for endpoints on the edge where either the segment
  952. // or the curve is headed "inwards" from them
  953. // Note: These tests are a superset of the fast endpoint tests
  954. // above and thus repeat those tests, but take more time
  955. // and cover more cases
  956. if (inwards(x1tag, x2tag, ctrlxtag) &&
  957. inwards(y1tag, y2tag, ctrlytag))
  958. {
  959. // First endpoint on border with either edge moving inside
  960. return true;
  961. }
  962. if (inwards(x2tag, x1tag, ctrlxtag) &&
  963. inwards(y2tag, y1tag, ctrlytag))
  964. {
  965. // Second endpoint on border with either edge moving inside
  966. return true;
  967. }
  968. // Trivially accept if endpoints span directly across the rectangle
  969. boolean xoverlap = (x1tag * x2tag <= 0);
  970. boolean yoverlap = (y1tag * y2tag <= 0);
  971. if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {
  972. return true;
  973. }
  974. if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {
  975. return true;
  976. }
  977. // We now know that both endpoints are outside the rectangle
  978. // but the 3 points are not all on one side of the rectangle.
  979. // Therefore the curve cannot be contained inside the rectangle,
  980. // but the rectangle might be contained inside the curve, or
  981. // the curve might intersect the boundary of the rectangle.
  982. double[] eqn = new double[3];
  983. double[] res = new double[3];
  984. if (!yoverlap) {
  985. // Both y coordinates for the closing segment are above or
  986. // below the rectangle which means that we can only intersect
  987. // if the curve crosses the top (or bottom) of the rectangle
  988. // in more than one place and if those crossing locations
  989. // span the horizontal range of the rectangle.
  990. fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly, y2);
  991. return (solveQuadratic(eqn, res) == 2 &&
  992. evalQuadratic(res, 2, true, true, null,
  993. x1, ctrlx, x2) == 2 &&
  994. getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0);
  995. }
  996. // Y ranges overlap. Now we examine the X ranges
  997. if (!xoverlap) {
  998. // Both x coordinates for the closing segment are left of
  999. // or right of the rectangle which means that we can only
  1000. // intersect if the curve crosses the left (or right) edge
  1001. // of the rectangle in more than one place and if those
  1002. // crossing locations span the vertical range of the rectangle.
  1003. fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx, x2);
  1004. return (solveQuadratic(eqn, res) == 2 &&
  1005. evalQuadratic(res, 2, true, true, null,
  1006. y1, ctrly, y2) == 2 &&
  1007. getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0);
  1008. }
  1009. // The X and Y ranges of the endpoints overlap the X and Y
  1010. // ranges of the rectangle, now find out how the endpoint
  1011. // line segment intersects the Y range of the rectangle
  1012. double dx = x2 - x1;
  1013. double dy = y2 - y1;
  1014. double k = y2 * x1 - x2 * y1;
  1015. int c1tag, c2tag;
  1016. if (y1tag == INSIDE) {
  1017. c1tag = x1tag;
  1018. } else {
  1019. c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w);
  1020. }
  1021. if (y2tag == INSIDE) {
  1022. c2tag = x2tag;
  1023. } else {
  1024. c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w);
  1025. }
  1026. // If the part of the line segment that intersects the Y range
  1027. // of the rectangle crosses it horizontally - trivially accept
  1028. if (c1tag * c2tag <= 0) {
  1029. return true;
  1030. }
  1031. // Now we know that both the X and Y ranges intersect and that
  1032. // the endpoint line segment does not directly cross the rectangle.
  1033. //
  1034. // We can almost treat this case like one of the cases above
  1035. // where both endpoints are to one side, except that we will
  1036. // only get one intersection of the curve with the vertical
  1037. // side of the rectangle. This is because the endpoint segment
  1038. // accounts for the other intersection.
  1039. //
  1040. // (Remember there is overlap in both the X and Y ranges which
  1041. // means that the segment must cross at least one vertical edge
  1042. // of the rectangle - in particular, the "near vertical side" -
  1043. // leaving only one intersection for the curve.)
  1044. //
  1045. // Now we calculate the y tags of the two intersections on the
  1046. // "near vertical side" of the rectangle. We will have one with
  1047. // the endpoint segment, and one with the curve. If those two
  1048. // vertical intersections overlap the Y range of the rectangle,
  1049. // we have an intersection. Otherwise, we don't.
  1050. // c1tag = vertical intersection class of the endpoint segment
  1051. //
  1052. // Choose the y tag of the endpoint that was not on the same
  1053. // side of the rectangle as the subsegment calculated above.
  1054. // Note that we can "steal" the existing Y tag of that endpoint
  1055. // since it will be provably the same as the vertical intersection.
  1056. c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);
  1057. // c2tag = vertical intersection class of the curve
  1058. //
  1059. // We have to calculate this one the straightforward way.
  1060. // Note that the c2tag can still tell us which vertical edge
  1061. // to test against.
  1062. fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx, x2);
  1063. int num = solveQuadratic(eqn, res);
  1064. // Note: We should be able to assert(num == 2); since the
  1065. // X range "crosses" (not touches) the vertical boundary,
  1066. // but we pass num to evalQuadratic for completeness.
  1067. evalQuadratic(res, num, true, true, null, y1, ctrly, y2);
  1068. // Note: We can assert(num evals == 1); since one of the
  1069. // 2 crossings will be out of the [0,1] range.
  1070. c2tag = getTag(res[0], y, y+h);
  1071. // Finally, we have an intersection if the two crossings
  1072. // overlap the Y range of the rectangle.
  1073. return (c1tag * c2tag <= 0);
  1074. }
  1075. /**
  1076. * Tests if the shape of this <code>QuadCurve2D</code> intersects the
  1077. * interior of a specified <code>Rectangle2D</code>.
  1078. * @param r the specified <code>Rectangle2D</code>
  1079. * @return <code>true</code> if the shape of this
  1080. * <code>QuadCurve2D</code> intersects the interior of
  1081. * the specified <code>Rectangle2D</code>
  1082. * <code>false</code> otherwise.
  1083. */
  1084. public boolean intersects(Rectangle2D r) {
  1085. return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  1086. }
  1087. /**
  1088. * Tests if the interior of the shape of this
  1089. * <code>QuadCurve2D</code> entirely contains the specified
  1090. * set of rectangular coordinates.
  1091. * @param x, y the coordinates of the upper-left corner of the
  1092. * specified rectangular area
  1093. * @param w the width of the specified rectangular area
  1094. * @param h the height of the specified rectangular area
  1095. * @return <code>true</code> if the interior of the shape of this
  1096. * <code>QuadCurve2D</code> entirely contains the specified
  1097. * rectangluar area; <code>false</code> otherwise.
  1098. */
  1099. public boolean contains(double x, double y, double w, double h) {
  1100. // Assertion: Quadratic curves closed by connecting their
  1101. // endpoints are always convex.
  1102. return (contains(x, y) &&
  1103. contains(x + w, y) &&
  1104. contains(x + w, y + h) &&
  1105. contains(x, y + h));
  1106. }
  1107. /**
  1108. * Tests if the interior of the shape of this
  1109. * <code>QuadCurve2D</code> entirely contains the specified
  1110. * <code>Rectangle2D</code>.
  1111. * @param r the specified <code>Rectangle2D</code>
  1112. * @return <code>true</code> if the interior of the shape of this
  1113. * <code>QuadCurve2D</code> entirely contains the specified
  1114. * <code>Rectangle2D</code> <code>false</code> otherwise.
  1115. */
  1116. public boolean contains(Rectangle2D r) {
  1117. return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  1118. }
  1119. /**
  1120. * Returns the bounding box of this <code>QuadCurve2D</code>.
  1121. * @return a {@link Rectangle} that is the bounding box of the shape
  1122. * of this <code>QuadCurve2D</code>.
  1123. */
  1124. public Rectangle getBounds() {
  1125. return getBounds2D().getBounds();
  1126. }
  1127. /**
  1128. * Returns an iteration object that defines the boundary of the
  1129. * shape of this <code>QuadCurve2D</code>.
  1130. * The iterator for this class is not multi-threaded safe,
  1131. * which means that this <code>QuadCurve2D</code> class does not
  1132. * guarantee that modifications to the geometry of this
  1133. * <code>QuadCurve2D</code> object do not affect any iterations of
  1134. * that geometry that are already in process.
  1135. * @param at an optional {@link AffineTransform} to apply to the
  1136. * shape boundary
  1137. * @return a {@link PathIterator} object that defines the boundary
  1138. * of the shape.
  1139. */
  1140. public PathIterator getPathIterator(AffineTransform at) {
  1141. return new QuadIterator(this, at);
  1142. }
  1143. /**
  1144. * Returns an iteration object that defines the boundary of the
  1145. * flattened shape of this <code>QuadCurve2D</code>.
  1146. * The iterator for this class is not multi-threaded safe,
  1147. * which means that this <code>QuadCurve2D</code> class does not
  1148. * guarantee that modifications to the geometry of this
  1149. * <code>QuadCurve2D</code> object do not affect any iterations of
  1150. * that geometry that are already in process.
  1151. * @param at an optional <code>AffineTransform</code> to apply
  1152. * to the boundary of the shape
  1153. * @param flatness the maximum distance that the control points for a
  1154. * subdivided curve can be with respect to a line connecting
  1155. * the endpoints of this curve before this curve is
  1156. * replaced by a straight line connecting the endpoints.
  1157. * @return a <code>PathIterator</code> object that defines the
  1158. * flattened boundary of the shape.
  1159. */
  1160. public PathIterator getPathIterator(AffineTransform at, double flatness) {
  1161. return new FlatteningPathIterator(getPathIterator(at), flatness);
  1162. }
  1163. /**
  1164. * Creates a new object of the same class and with the same contents
  1165. * as this object.
  1166. *
  1167. * @return a clone of this instance.
  1168. * @exception OutOfMemoryError if there is not enough memory.
  1169. * @see java.lang.Cloneable
  1170. * @since JDK1.2
  1171. */
  1172. public Object clone() {
  1173. try {
  1174. return super.clone();
  1175. } catch (CloneNotSupportedException e) {
  1176. // this shouldn't happen, since we are Cloneable
  1177. throw new InternalError();
  1178. }
  1179. }
  1180. }