Arc2D.java 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124
  1. /* Arc2D.java -- represents an arc in 2-D space
  2. Copyright (C) 2002 Free Software Foundation
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15. 02111-1307 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.awt.geom;
  32. import java.util.NoSuchElementException;
  33. /**
  34. * This class represents all arcs (segments of an ellipse in 2-D space). The
  35. * arcs are defined by starting angle and extent (arc length) in degrees, as
  36. * opposed to radians (like the rest of Java), and can be open, chorded, or
  37. * wedge shaped. The angles are skewed according to the ellipse, so that 45
  38. * degrees always points to the upper right corner (positive x, negative y)
  39. * of the bounding rectangle. A positive extent draws a counterclockwise arc,
  40. * and while the angle can be any value, the path iterator only traverses the
  41. * first 360 degrees. Storage is up to the subclasses.
  42. *
  43. * @author Eric Blake <ebb9@email.byu.edu>
  44. * @since 1.2
  45. * @status updated to 1.4, but still missing functionality
  46. */
  47. public abstract class Arc2D extends RectangularShape
  48. {
  49. /**
  50. * An open arc, with no segment connecting the endpoints. This type of
  51. * arc still contains the same points as a chorded version.
  52. */
  53. public static final int OPEN = 0;
  54. /**
  55. * A closed arc with a single segment connecting the endpoints (a chord).
  56. */
  57. public static final int CHORD = 1;
  58. /**
  59. * A closed arc with two segments, one from each endpoint, meeting at the
  60. * center of the ellipse.
  61. */
  62. public static final int PIE = 2;
  63. /** The closure type of this arc. */
  64. private int type;
  65. /**
  66. * Create a new arc, with the specified closure type.
  67. *
  68. * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}.
  69. * @throws IllegalArgumentException if type is invalid
  70. */
  71. protected Arc2D(int type)
  72. {
  73. if (type < OPEN || type > PIE)
  74. throw new IllegalArgumentException();
  75. this.type = type;
  76. }
  77. /**
  78. * Get the starting angle of the arc in degrees.
  79. *
  80. * @return the starting angle
  81. * @see #setAngleStart(double)
  82. */
  83. public abstract double getAngleStart();
  84. /**
  85. * Get the extent angle of the arc in degrees.
  86. *
  87. * @return the extent angle
  88. * @see #setAngleExtent(double)
  89. */
  90. public abstract double getAngleExtent();
  91. /**
  92. * Return the closure type of the arc.
  93. *
  94. * @return the closure type
  95. * @see #OPEN
  96. * @see #CHORD
  97. * @see #PIE
  98. * @see #setArcType(int)
  99. */
  100. public int getArcType()
  101. {
  102. return type;
  103. }
  104. /**
  105. * Returns the starting point of the arc.
  106. *
  107. * @return the start point
  108. */
  109. public Point2D getStartPoint()
  110. {
  111. double angle = getAngleStart() * (-180 / Math.PI);
  112. double x = (Math.cos(angle) * getWidth() + getX()) / 2;
  113. double y = (Math.sin(angle) * getHeight() + getY()) / 2;
  114. return new Point2D.Double(x, y);
  115. }
  116. /**
  117. * Returns the ending point of the arc.
  118. *
  119. * @return the end point
  120. */
  121. public Point2D getEndPoint()
  122. {
  123. double angle = (getAngleStart() + getAngleExtent()) * (-180 / Math.PI);
  124. double x = (Math.cos(angle) * getWidth() + getX()) / 2;
  125. double y = (Math.sin(angle) * getHeight() + getY()) / 2;
  126. return new Point2D.Double(x, y);
  127. }
  128. /**
  129. * Set the parameters of the arc. The angles are in degrees, and a positive
  130. * extent sweeps counterclockwise (from the positive x-axis to the negative
  131. * y-axis).
  132. *
  133. * @param x the new x coordinate of the lower left of the bounding box
  134. * @param y the new y coordinate of the lower left of the bounding box
  135. * @param w the new width of the bounding box
  136. * @param h the new height of the bounding box
  137. * @param start the start angle, in degrees
  138. * @param extent the arc extent, in degrees
  139. * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  140. * @throws IllegalArgumentException if type is invalid
  141. */
  142. public abstract void setArc(double x, double y, double w, double h,
  143. double start, double extent, int type);
  144. /**
  145. * Set the parameters of the arc. The angles are in degrees, and a positive
  146. * extent sweeps counterclockwise (from the positive x-axis to the negative
  147. * y-axis).
  148. *
  149. * @param p the lower left point of the bounding box
  150. * @param d the dimensions of the bounding box
  151. * @param start the start angle, in degrees
  152. * @param extent the arc extent, in degrees
  153. * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  154. * @throws IllegalArgumentException if type is invalid
  155. * @throws NullPointerException if p or d is null
  156. */
  157. public void setArc(Point2D p, Dimension2D d,
  158. double start, double extent, int type)
  159. {
  160. setArc(p.getX(), p.getY(), d.getWidth(), d.getHeight(),
  161. start, extent, type);
  162. }
  163. /**
  164. * Set the parameters of the arc. The angles are in degrees, and a positive
  165. * extent sweeps counterclockwise (from the positive x-axis to the negative
  166. * y-axis).
  167. *
  168. * @param r the new bounding box
  169. * @param start the start angle, in degrees
  170. * @param extent the arc extent, in degrees
  171. * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  172. * @throws IllegalArgumentException if type is invalid
  173. * @throws NullPointerException if r is null
  174. */
  175. public void setArc(Rectangle2D r, double start, double extent, int type)
  176. {
  177. setArc(r.getX(), r.getY(), r.getWidth(), r.getHeight(),
  178. start, extent, type);
  179. }
  180. /**
  181. * Set the parameters of the arc from the given one.
  182. *
  183. * @param a the arc to copy
  184. * @throws NullPointerException if a is null
  185. */
  186. public void setArc(Arc2D a)
  187. {
  188. setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(),
  189. a.getAngleStart(), a.getAngleExtent(), a.getArcType());
  190. }
  191. /**
  192. * Set the parameters of the arc. The angles are in degrees, and a positive
  193. * extent sweeps counterclockwise (from the positive x-axis to the negative
  194. * y-axis). This controls the center point and radius, so the arc will be
  195. * circular.
  196. *
  197. * @param x the x coordinate of the center of the circle
  198. * @param y the y coordinate of the center of the circle
  199. * @param r the radius of the circle
  200. * @param start the start angle, in degrees
  201. * @param extent the arc extent, in degrees
  202. * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  203. * @throws IllegalArgumentException if type is invalid
  204. */
  205. public void setArcByCenter(double x, double y, double r,
  206. double start, double extent, int type)
  207. {
  208. setArc(x - r, y - r, r + r, r + r, start, extent, type);
  209. }
  210. /**
  211. * Sets the parameters of the arc by finding the tangents of two lines, and
  212. * using the specified radius. The arc will be circular, will begin on the
  213. * tangent point of the line extending from p1 to p2, and will end on the
  214. * tangent point of the line extending from p2 to p3.
  215. *
  216. * XXX What happens if the points are colinear, or the radius negative?
  217. *
  218. * @param p1 the first point
  219. * @param p2 the tangent line intersection point
  220. * @param p3 the third point
  221. * @param r the radius of the arc
  222. * @throws NullPointerException if any point is null
  223. */
  224. public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double r)
  225. {
  226. // XXX Implement.
  227. throw new Error("not implemented");
  228. }
  229. /**
  230. * Set the start, in degrees.
  231. *
  232. * @param start the new start angle
  233. * @see #getAngleStart()
  234. */
  235. public abstract void setAngleStart(double start);
  236. /**
  237. * Set the extent, in degrees.
  238. *
  239. * @param extent the new extent angle
  240. * @see #getAngleExtent()
  241. */
  242. public abstract void setAngleExtent(double extent);
  243. /**
  244. * Sets the starting angle to the angle of the given point relative to
  245. * the center of the arc. The extent remains constant; in other words,
  246. * this rotates the arc.
  247. *
  248. * @param p the new start point
  249. * @throws NullPointerException if p is null
  250. * @see #getStartPoint()
  251. * @see #getAngleStart()
  252. */
  253. public void setAngleStart(Point2D p)
  254. {
  255. double x = ((p.getX() * 2) - getX()) / getWidth();
  256. double y = ((p.getY() * 2) - getY()) / getHeight();
  257. setAngleStart(Math.atan2(y, x) * (-180 / Math.PI));
  258. }
  259. /**
  260. * Sets the starting and extent angles to those of the given points
  261. * relative to the center of the arc. The arc will be non-empty, and will
  262. * extend counterclockwise.
  263. *
  264. * @param x1 the first x coordinate
  265. * @param y1 the first y coordinate
  266. * @param x2 the second x coordinate
  267. * @param y2 the second y coordinate
  268. * @see #setAngleStart(Point2D)
  269. */
  270. public void setAngles(double x1, double y1, double x2, double y2)
  271. {
  272. // Normalize the points.
  273. double mx = getX();
  274. double my = getY();
  275. double mw = getWidth();
  276. double mh = getHeight();
  277. x1 = ((x1 * 2) - mx) / mw;
  278. y1 = ((y1 * 2) - my) / mh;
  279. x2 = ((x2 * 2) - mx) / mw;
  280. y2 = ((y2 * 2) - my) / mh;
  281. double start = Math.atan2(y1, x1) * (-180 / Math.PI);
  282. double extent = Math.atan2(y2, x2) * (-180 / Math.PI) - start;
  283. if (extent < 0)
  284. extent += 360;
  285. setAngleStart(start);
  286. setAngleExtent(extent);
  287. }
  288. /**
  289. * Sets the starting and extent angles to those of the given points
  290. * relative to the center of the arc. The arc will be non-empty, and will
  291. * extend counterclockwise.
  292. *
  293. * @param p1 the first point
  294. * @param p2 the second point
  295. * @throws NullPointerException if either point is null
  296. * @see #setAngleStart(Point2D)
  297. */
  298. public void setAngles(Point2D p1, Point2D p2)
  299. {
  300. setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY());
  301. }
  302. /**
  303. * Set the closure type of this arc.
  304. *
  305. * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  306. * @throws IllegalArgumentException if type is invalid
  307. * @see #getArcType()
  308. */
  309. public void setArcType(int type)
  310. {
  311. if (type < OPEN || type > PIE)
  312. throw new IllegalArgumentException();
  313. this.type = type;
  314. }
  315. /**
  316. * Sets the location and bounds of the ellipse of which this arc is a part.
  317. *
  318. * @param x the new x coordinate
  319. * @param y the new y coordinate
  320. * @param w the new width
  321. * @param h the new height
  322. * @see #getFrame()
  323. */
  324. public void setFrame(double x, double y, double w, double h)
  325. {
  326. setArc(x, y, w, h, getAngleStart(), getAngleExtent(), type);
  327. }
  328. /**
  329. * Gets the bounds of the arc. This is much tighter than
  330. * <code>getBounds</code>, as it takes into consideration the start and
  331. * end angles, and the center point of a pie wedge, rather than just the
  332. * overall ellipse.
  333. *
  334. * @return the bounds of the arc
  335. * @see #getBounds()
  336. */
  337. public Rectangle2D getBounds2D()
  338. {
  339. double extent = getAngleExtent();
  340. if (Math.abs(extent) >= 360)
  341. return makeBounds(getX(), getY(), getWidth(), getHeight());
  342. // XXX Finish implementing.
  343. throw new Error("not implemented");
  344. }
  345. /**
  346. * Construct a bounding box in a precision appropriate for the subclass.
  347. *
  348. * @param x the x coordinate
  349. * @param y the y coordinate
  350. * @param w the width
  351. * @param h the height
  352. * @return the rectangle for use in getBounds2D
  353. */
  354. protected abstract Rectangle2D makeBounds(double x, double y,
  355. double w, double h);
  356. /**
  357. * Tests if the given angle, in degrees, is included in the arc.
  358. *
  359. * XXX Does this normalize all angles to -180 - 180 first?
  360. *
  361. * @param a the angle to test
  362. * @return true if it is contained
  363. */
  364. public boolean containsAngle(double a)
  365. {
  366. // XXX Implement.
  367. throw new Error("not implemented");
  368. }
  369. /**
  370. * Determines if the arc contains the given point. If the bounding box
  371. * is empty, then this will return false.
  372. *
  373. * @param x the x coordinate to test
  374. * @param y the y coordinate to test
  375. * @return true if the point is inside the arc
  376. */
  377. public boolean contains(double x, double y)
  378. {
  379. double w = getWidth();
  380. double h = getHeight();
  381. if (w <= 0 || h <= 0)
  382. return false;
  383. // XXX Finish implementing.
  384. throw new Error("not implemented");
  385. }
  386. /**
  387. * Tests if a given rectangle intersects the area of the arc.
  388. *
  389. * @param x the x coordinate of the rectangle
  390. * @param y the y coordinate of the rectangle
  391. * @param w the width of the rectangle
  392. * @param h the height of the rectangle
  393. * @return true if the two shapes share common points
  394. */
  395. public boolean intersects(double x, double y, double w, double h)
  396. {
  397. double mw = getWidth();
  398. double mh = getHeight();
  399. if (mw <= 0 || mh <= 0 || w <= 0 || h <= 0)
  400. return false;
  401. // XXX Finish implementing.
  402. throw new Error("not implemented");
  403. }
  404. /**
  405. * Tests if a given rectangle is contained in the area of the arc.
  406. *
  407. * @param x the x coordinate of the rectangle
  408. * @param y the y coordinate of the rectangle
  409. * @param w the width of the rectangle
  410. * @param h the height of the rectangle
  411. * @return true if the arc contains the rectangle
  412. */
  413. public boolean contains(double x, double y, double w, double h)
  414. {
  415. double mw = getWidth();
  416. double mh = getHeight();
  417. if (mw <= 0 || mh <= 0 || w <= 0 || h <= 0)
  418. return false;
  419. // XXX Finish implementing.
  420. throw new Error("not implemented");
  421. }
  422. /**
  423. * Tests if a given rectangle is contained in the area of the arc.
  424. *
  425. * @param r the rectangle
  426. * @return true if the arc contains the rectangle
  427. */
  428. public boolean contains(Rectangle2D r)
  429. {
  430. return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  431. }
  432. /**
  433. * Returns an iterator over this arc, with an optional transformation.
  434. * This iterator is threadsafe, so future modifications to the arc do not
  435. * affect the iteration.
  436. *
  437. * @param at the transformation, or null
  438. * @return a path iterator
  439. */
  440. public PathIterator getPathIterator(AffineTransform at)
  441. {
  442. return new ArcIterator(this, at);
  443. }
  444. /**
  445. * This class is used to iterate over an arc. Since ellipses are a subclass
  446. * of arcs, this is used by Ellipse2D as well.
  447. *
  448. * @author Eric Blake <ebb9@email.byu.edu>
  449. */
  450. static final class ArcIterator implements PathIterator
  451. {
  452. /** The current iteration. */
  453. private int current;
  454. /** The last iteration. */
  455. private final int limit;
  456. /** The optional transformation. */
  457. private final AffineTransform xform;
  458. /** The x coordinate of the bounding box. */
  459. private final double x;
  460. /** The y coordinate of the bounding box. */
  461. private final double y;
  462. /** The width of the bounding box. */
  463. private final double w;
  464. /** The height of the bounding box. */
  465. private final double h;
  466. /** The start angle, in radians (not degrees). */
  467. private final double start;
  468. /** The extent angle, in radians (not degrees). */
  469. private final double extent;
  470. /** The arc closure type. */
  471. private final int type;
  472. /**
  473. * Construct a new iterator over an arc.
  474. *
  475. * @param a the arc
  476. * @param xform the transform
  477. */
  478. ArcIterator(Arc2D a, AffineTransform xform)
  479. {
  480. this.xform = xform;
  481. x = a.getX();
  482. y = a.getY();
  483. w = a.getWidth();
  484. h = a.getHeight();
  485. start = a.getAngleStart() * (Math.PI / 180);
  486. extent = a.getAngleExtent() * (Math.PI / 180);
  487. type = a.type;
  488. double e = extent < 0 ? -extent : extent;
  489. if (w < 0 || h < 0)
  490. limit = -1;
  491. else if (e == 0)
  492. limit = type;
  493. else if (e <= 90)
  494. limit = type + 1;
  495. else if (e <= 180)
  496. limit = type + 2;
  497. else if (e <= 270)
  498. limit = type + 3;
  499. else
  500. limit = type + 4;
  501. }
  502. /**
  503. * Construct a new iterator over an ellipse.
  504. *
  505. * @param e the ellipse
  506. * @param xform the transform
  507. */
  508. ArcIterator(Ellipse2D e, AffineTransform xform)
  509. {
  510. this.xform = xform;
  511. x = e.getX();
  512. y = e.getY();
  513. w = e.getWidth();
  514. h = e.getHeight();
  515. start = 0;
  516. extent = -2 * Math.PI;
  517. type = CHORD;
  518. limit = (w < 0 || h < 0) ? -1 : 5;
  519. }
  520. /**
  521. * Return the winding rule.
  522. *
  523. * @return {@link PathIterator#WIND_NON_ZERO}
  524. */
  525. public int getWindingRule()
  526. {
  527. return WIND_NON_ZERO;
  528. }
  529. /**
  530. * Test if the iteration is complete.
  531. *
  532. * @return true if more segments exist
  533. */
  534. public boolean isDone()
  535. {
  536. return current > limit;
  537. }
  538. /**
  539. * Advance the iterator.
  540. */
  541. public void next()
  542. {
  543. current++;
  544. }
  545. /**
  546. * Put the current segment into the array, and return the segment type.
  547. *
  548. * @param coords an array of 6 elements
  549. * @return the segment type
  550. * @throws NullPointerException if coords is null
  551. * @throws ArrayIndexOutOfBoundsException if coords is too small
  552. */
  553. public int currentSegment(float[] coords)
  554. {
  555. if (current > limit)
  556. throw new NoSuchElementException("arc iterator out of bounds");
  557. if (current == 0)
  558. {
  559. coords[0] = (float) (Math.cos(start) * w + x) / 2;
  560. coords[1] = (float) (Math.sin(start) * h + y) / 2;
  561. if (xform != null)
  562. xform.transform(coords, 0, coords, 0, 1);
  563. return SEG_MOVETO;
  564. }
  565. if (type != OPEN && current == limit)
  566. return SEG_CLOSE;
  567. if (type == PIE && current == limit - 1)
  568. {
  569. coords[0] = (float) (x + w / 2);
  570. coords[1] = (float) (y + h / 2);
  571. if (xform != null)
  572. xform.transform(coords, 0, coords, 0, 1);
  573. return SEG_LINETO;
  574. }
  575. // XXX Fill coords with 2 control points and next quarter point
  576. coords[0] = (float) 0;
  577. coords[1] = (float) 0;
  578. coords[2] = (float) 0;
  579. coords[3] = (float) 0;
  580. coords[4] = (float) 0;
  581. coords[5] = (float) 0;
  582. if (xform != null)
  583. xform.transform(coords, 0, coords, 0, 3);
  584. return SEG_CUBICTO;
  585. }
  586. /**
  587. * Put the current segment into the array, and return the segment type.
  588. *
  589. * @param coords an array of 6 elements
  590. * @return the segment type
  591. * @throws NullPointerException if coords is null
  592. * @throws ArrayIndexOutOfBoundsException if coords is too small
  593. */
  594. public int currentSegment(double[] coords)
  595. {
  596. if (current > limit)
  597. throw new NoSuchElementException("arc iterator out of bounds");
  598. if (current == 0)
  599. {
  600. coords[0] = (Math.cos(start) * w + x) / 2;
  601. coords[1] = (Math.sin(start) * h + y) / 2;
  602. if (xform != null)
  603. xform.transform(coords, 0, coords, 0, 1);
  604. return SEG_MOVETO;
  605. }
  606. if (type != OPEN && current == limit)
  607. return SEG_CLOSE;
  608. if (type == PIE && current == limit - 1)
  609. {
  610. coords[0] = (float) (x + w / 2);
  611. coords[1] = (float) (y + h / 2);
  612. if (xform != null)
  613. xform.transform(coords, 0, coords, 0, 1);
  614. return SEG_LINETO;
  615. }
  616. // XXX Fill coords with 2 control points and next quarter point
  617. coords[0] = 0;
  618. coords[1] = 0;
  619. coords[2] = 0;
  620. coords[3] = 0;
  621. coords[4] = 0;
  622. coords[5] = 0;
  623. if (xform != null)
  624. xform.transform(coords, 0, coords, 0, 3);
  625. return SEG_CUBICTO;
  626. }
  627. } // class ArcIterator
  628. /**
  629. * This class implements an arc in double precision.
  630. *
  631. * @author Eric Blake <ebb9@email.byu.edu
  632. * @since 1.2
  633. */
  634. public static class Double extends Arc2D
  635. {
  636. /** The x coordinate of the box bounding the ellipse of this arc. */
  637. public double x;
  638. /** The y coordinate of the box bounding the ellipse of this arc. */
  639. public double y;
  640. /** The width of the box bounding the ellipse of this arc. */
  641. public double width;
  642. /** The height of the box bounding the ellipse of this arc. */
  643. public double height;
  644. /** The start angle of this arc, in degrees. */
  645. public double start;
  646. /** The extent angle of this arc, in degrees. */
  647. public double extent;
  648. /**
  649. * Create a new, open arc at (0,0) with 0 extent.
  650. */
  651. public Double()
  652. {
  653. super(OPEN);
  654. }
  655. /**
  656. * Create a new arc of the given type at (0,0) with 0 extent.
  657. *
  658. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  659. * @throws IllegalArgumentException if type is invalid
  660. */
  661. public Double(int type)
  662. {
  663. super(type);
  664. }
  665. /**
  666. * Create a new arc with the given dimensions.
  667. *
  668. * @param x the x coordinate
  669. * @param y the y coordinate
  670. * @param w the width
  671. * @param h the height
  672. * @param start the start angle, in degrees
  673. * @param extent the extent, in degrees
  674. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  675. * @throws IllegalArgumentException if type is invalid
  676. */
  677. public Double(double x, double y, double w, double h,
  678. double start, double extent, int type)
  679. {
  680. super(type);
  681. this.x = x;
  682. this.y = y;
  683. width = w;
  684. height = h;
  685. this.start = start;
  686. this.extent = extent;
  687. }
  688. /**
  689. * Create a new arc with the given dimensions.
  690. *
  691. * @param r the bounding box
  692. * @param start the start angle, in degrees
  693. * @param extent the extent, in degrees
  694. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  695. * @throws IllegalArgumentException if type is invalid
  696. * @throws NullPointerException if r is null
  697. */
  698. public Double(Rectangle2D r, double start, double extent, int type)
  699. {
  700. super(type);
  701. x = r.getX();
  702. y = r.getY();
  703. width = r.getWidth();
  704. height = r.getHeight();
  705. this.start = start;
  706. this.extent = extent;
  707. }
  708. /**
  709. * Return the x coordinate of the bounding box.
  710. *
  711. * @return the value of x
  712. */
  713. public double getX()
  714. {
  715. return x;
  716. }
  717. /**
  718. * Return the y coordinate of the bounding box.
  719. *
  720. * @return the value of y
  721. */
  722. public double getY()
  723. {
  724. return y;
  725. }
  726. /**
  727. * Return the width of the bounding box.
  728. *
  729. * @return the value of width
  730. */
  731. public double getWidth()
  732. {
  733. return width;
  734. }
  735. /**
  736. * Return the height of the bounding box.
  737. *
  738. * @return the value of height
  739. */
  740. public double getHeight()
  741. {
  742. return height;
  743. }
  744. /**
  745. * Return the start angle of the arc, in degrees.
  746. *
  747. * @return the value of start
  748. */
  749. public double getAngleStart()
  750. {
  751. return start;
  752. }
  753. /**
  754. * Return the extent of the arc, in degrees.
  755. *
  756. * @return the value of extent
  757. */
  758. public double getAngleExtent()
  759. {
  760. return extent;
  761. }
  762. /**
  763. * Tests if the arc contains points.
  764. *
  765. * @return true if the arc has no interior
  766. */
  767. public boolean isEmpty()
  768. {
  769. return width <= 0 || height <= 0;
  770. }
  771. /**
  772. * Sets the arc to the given dimensions.
  773. *
  774. * @param x the x coordinate
  775. * @param y the y coordinate
  776. * @param w the width
  777. * @param h the height
  778. * @param start the start angle, in degrees
  779. * @param extent the extent, in degrees
  780. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  781. * @throws IllegalArgumentException if type is invalid
  782. */
  783. public void setArc(double x, double y, double w, double h,
  784. double start, double extent, int type)
  785. {
  786. this.x = x;
  787. this.y = y;
  788. width = w;
  789. height = h;
  790. this.start = start;
  791. this.extent = extent;
  792. setArcType(type);
  793. }
  794. /**
  795. * Sets the start angle of the arc.
  796. *
  797. * @param start the new start angle
  798. */
  799. public void setAngleStart(double start)
  800. {
  801. this.start = start;
  802. }
  803. /**
  804. * Sets the extent angle of the arc.
  805. *
  806. * @param start the new extent angle
  807. */
  808. public void setAngleExtent(double extent)
  809. {
  810. this.extent = extent;
  811. }
  812. /**
  813. * Creates a tight bounding box given dimensions that more precise than
  814. * the bounding box of the ellipse.
  815. *
  816. * @param x the x coordinate
  817. * @param y the y coordinate
  818. * @param w the width
  819. * @param h the height
  820. */
  821. protected Rectangle2D makeBounds(double x, double y, double w, double h)
  822. {
  823. return new Rectangle2D.Double(x, y, w, h);
  824. }
  825. } // class Double
  826. /**
  827. * This class implements an arc in float precision.
  828. *
  829. * @author Eric Blake <ebb9@email.byu.edu
  830. * @since 1.2
  831. */
  832. public static class Float extends Arc2D
  833. {
  834. /** The x coordinate of the box bounding the ellipse of this arc. */
  835. public float x;
  836. /** The y coordinate of the box bounding the ellipse of this arc. */
  837. public float y;
  838. /** The width of the box bounding the ellipse of this arc. */
  839. public float width;
  840. /** The height of the box bounding the ellipse of this arc. */
  841. public float height;
  842. /** The start angle of this arc, in degrees. */
  843. public float start;
  844. /** The extent angle of this arc, in degrees. */
  845. public float extent;
  846. /**
  847. * Create a new, open arc at (0,0) with 0 extent.
  848. */
  849. public Float()
  850. {
  851. super(OPEN);
  852. }
  853. /**
  854. * Create a new arc of the given type at (0,0) with 0 extent.
  855. *
  856. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  857. * @throws IllegalArgumentException if type is invalid
  858. */
  859. public Float(int type)
  860. {
  861. super(type);
  862. }
  863. /**
  864. * Create a new arc with the given dimensions.
  865. *
  866. * @param x the x coordinate
  867. * @param y the y coordinate
  868. * @param w the width
  869. * @param h the height
  870. * @param start the start angle, in degrees
  871. * @param extent the extent, in degrees
  872. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  873. * @throws IllegalArgumentException if type is invalid
  874. */
  875. public Float(float x, float y, float w, float h,
  876. float start, float extent, int type)
  877. {
  878. super(type);
  879. this.x = x;
  880. this.y = y;
  881. width = w;
  882. height = h;
  883. this.start = start;
  884. this.extent = extent;
  885. }
  886. /**
  887. * Create a new arc with the given dimensions.
  888. *
  889. * @param r the bounding box
  890. * @param start the start angle, in degrees
  891. * @param extent the extent, in degrees
  892. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  893. * @throws IllegalArgumentException if type is invalid
  894. * @throws NullPointerException if r is null
  895. */
  896. public Float(Rectangle2D r, float start, float extent, int type)
  897. {
  898. super(type);
  899. x = (float) r.getX();
  900. y = (float) r.getY();
  901. width = (float) r.getWidth();
  902. height = (float) r.getHeight();
  903. this.start = start;
  904. this.extent = extent;
  905. }
  906. /**
  907. * Return the x coordinate of the bounding box.
  908. *
  909. * @return the value of x
  910. */
  911. public double getX()
  912. {
  913. return x;
  914. }
  915. /**
  916. * Return the y coordinate of the bounding box.
  917. *
  918. * @return the value of y
  919. */
  920. public double getY()
  921. {
  922. return y;
  923. }
  924. /**
  925. * Return the width of the bounding box.
  926. *
  927. * @return the value of width
  928. */
  929. public double getWidth()
  930. {
  931. return width;
  932. }
  933. /**
  934. * Return the height of the bounding box.
  935. *
  936. * @return the value of height
  937. */
  938. public double getHeight()
  939. {
  940. return height;
  941. }
  942. /**
  943. * Return the start angle of the arc, in degrees.
  944. *
  945. * @return the value of start
  946. */
  947. public double getAngleStart()
  948. {
  949. return start;
  950. }
  951. /**
  952. * Return the extent of the arc, in degrees.
  953. *
  954. * @return the value of extent
  955. */
  956. public double getAngleExtent()
  957. {
  958. return extent;
  959. }
  960. /**
  961. * Tests if the arc contains points.
  962. *
  963. * @return true if the arc has no interior
  964. */
  965. public boolean isEmpty()
  966. {
  967. return width <= 0 || height <= 0;
  968. }
  969. /**
  970. * Sets the arc to the given dimensions.
  971. *
  972. * @param x the x coordinate
  973. * @param y the y coordinate
  974. * @param w the width
  975. * @param h the height
  976. * @param start the start angle, in degrees
  977. * @param extent the extent, in degrees
  978. * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE}
  979. * @throws IllegalArgumentException if type is invalid
  980. */
  981. public void setArc(double x, double y, double w, double h,
  982. double start, double extent, int type)
  983. {
  984. this.x = (float) x;
  985. this.y = (float) y;
  986. width = (float) w;
  987. height = (float) h;
  988. this.start = (float) start;
  989. this.extent = (float) extent;
  990. setArcType(type);
  991. }
  992. /**
  993. * Sets the start angle of the arc.
  994. *
  995. * @param start the new start angle
  996. */
  997. public void setAngleStart(double start)
  998. {
  999. this.start = (float) start;
  1000. }
  1001. /**
  1002. * Sets the extent angle of the arc.
  1003. *
  1004. * @param start the new extent angle
  1005. */
  1006. public void setAngleExtent(double extent)
  1007. {
  1008. this.extent = (float) extent;
  1009. }
  1010. /**
  1011. * Creates a tight bounding box given dimensions that more precise than
  1012. * the bounding box of the ellipse.
  1013. *
  1014. * @param x the x coordinate
  1015. * @param y the y coordinate
  1016. * @param w the width
  1017. * @param h the height
  1018. */
  1019. protected Rectangle2D makeBounds(double x, double y, double w, double h)
  1020. {
  1021. return new Rectangle2D.Float((float) x, (float) y, (float) w, (float) h);
  1022. }
  1023. } // class Float
  1024. } // class Arc2D