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