1 |
/* Arc2D.java -- represents an arc in 2-D space |
/* Arc2D.java -- represents an arc in 2-D space |
2 |
Copyright (C) 2002, 2003 Free Software Foundation |
Copyright (C) 2002, 2003, 2004 Free Software Foundation |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
35 |
obligated to do so. If you do not wish to do so, delete this |
obligated to do so. If you do not wish to do so, delete this |
36 |
exception statement from your version. */ |
exception statement from your version. */ |
37 |
|
|
|
|
|
38 |
package java.awt.geom; |
package java.awt.geom; |
39 |
|
|
40 |
import java.util.NoSuchElementException; |
import java.util.NoSuchElementException; |
41 |
|
|
42 |
|
|
43 |
/** |
/** |
44 |
* This class represents all arcs (segments of an ellipse in 2-D space). The |
* This class represents all arcs (segments of an ellipse in 2-D space). The |
45 |
* arcs are defined by starting angle and extent (arc length) in degrees, as |
* arcs are defined by starting angle and extent (arc length) in degrees, as |
51 |
* first 360 degrees. Storage is up to the subclasses. |
* first 360 degrees. Storage is up to the subclasses. |
52 |
* |
* |
53 |
* @author Eric Blake (ebb9@email.byu.edu) |
* @author Eric Blake (ebb9@email.byu.edu) |
54 |
|
* @author Sven de Marothy (sven@physto.se) |
55 |
* @since 1.2 |
* @since 1.2 |
|
* @status updated to 1.4, but still missing functionality |
|
56 |
*/ |
*/ |
57 |
public abstract class Arc2D extends RectangularShape |
public abstract class Arc2D extends RectangularShape |
58 |
{ |
{ |
154 |
* extent sweeps counterclockwise (from the positive x-axis to the negative |
* extent sweeps counterclockwise (from the positive x-axis to the negative |
155 |
* y-axis). |
* y-axis). |
156 |
* |
* |
157 |
* @param x the new x coordinate of the lower left of the bounding box |
* @param x the new x coordinate of the upper left of the bounding box |
158 |
* @param y the new y coordinate of the lower left of the bounding box |
* @param y the new y coordinate of the upper left of the bounding box |
159 |
* @param w the new width of the bounding box |
* @param w the new width of the bounding box |
160 |
* @param h the new height of the bounding box |
* @param h the new height of the bounding box |
161 |
* @param start the start angle, in degrees |
* @param start the start angle, in degrees |
171 |
* extent sweeps counterclockwise (from the positive x-axis to the negative |
* extent sweeps counterclockwise (from the positive x-axis to the negative |
172 |
* y-axis). |
* y-axis). |
173 |
* |
* |
174 |
* @param p the lower left point of the bounding box |
* @param p the upper left point of the bounding box |
175 |
* @param d the dimensions of the bounding box |
* @param d the dimensions of the bounding box |
176 |
* @param start the start angle, in degrees |
* @param start the start angle, in degrees |
177 |
* @param extent the arc extent, in degrees |
* @param extent the arc extent, in degrees |
179 |
* @throws IllegalArgumentException if type is invalid |
* @throws IllegalArgumentException if type is invalid |
180 |
* @throws NullPointerException if p or d is null |
* @throws NullPointerException if p or d is null |
181 |
*/ |
*/ |
182 |
public void setArc(Point2D p, Dimension2D d, |
public void setArc(Point2D p, Dimension2D d, double start, double extent, |
183 |
double start, double extent, int type) |
int type) |
184 |
{ |
{ |
185 |
setArc(p.getX(), p.getY(), d.getWidth(), d.getHeight(), |
setArc(p.getX(), p.getY(), d.getWidth(), d.getHeight(), start, extent, type); |
|
start, extent, type); |
|
186 |
} |
} |
187 |
|
|
188 |
/** |
/** |
199 |
*/ |
*/ |
200 |
public void setArc(Rectangle2D r, double start, double extent, int type) |
public void setArc(Rectangle2D r, double start, double extent, int type) |
201 |
{ |
{ |
202 |
setArc(r.getX(), r.getY(), r.getWidth(), r.getHeight(), |
setArc(r.getX(), r.getY(), r.getWidth(), r.getHeight(), start, extent, type); |
|
start, extent, type); |
|
203 |
} |
} |
204 |
|
|
205 |
/** |
/** |
210 |
*/ |
*/ |
211 |
public void setArc(Arc2D a) |
public void setArc(Arc2D a) |
212 |
{ |
{ |
213 |
setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(), |
setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(), a.getAngleStart(), |
214 |
a.getAngleStart(), a.getAngleExtent(), a.getArcType()); |
a.getAngleExtent(), a.getArcType()); |
215 |
} |
} |
216 |
|
|
217 |
/** |
/** |
228 |
* @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
* @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
229 |
* @throws IllegalArgumentException if type is invalid |
* @throws IllegalArgumentException if type is invalid |
230 |
*/ |
*/ |
231 |
public void setArcByCenter(double x, double y, double r, |
public void setArcByCenter(double x, double y, double r, double start, |
232 |
double start, double extent, int type) |
double extent, int type) |
233 |
{ |
{ |
234 |
setArc(x - r, y - r, r + r, r + r, start, extent, type); |
setArc(x - r, y - r, r + r, r + r, start, extent, type); |
235 |
} |
} |
250 |
*/ |
*/ |
251 |
public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double r) |
public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double r) |
252 |
{ |
{ |
253 |
// XXX Implement. |
if ((p2.getX() - p1.getX()) * (p3.getY() - p1.getY()) |
254 |
throw new Error("not implemented"); |
- (p3.getX() - p1.getX()) * (p2.getY() - p1.getY()) > 0) |
255 |
|
{ |
256 |
|
Point2D p = p3; |
257 |
|
p3 = p1; |
258 |
|
p1 = p; |
259 |
|
} |
260 |
|
|
261 |
|
// normalized tangent vectors |
262 |
|
double dx1 = (p1.getX() - p2.getX()) / p1.distance(p2); |
263 |
|
double dy1 = (p1.getY() - p2.getY()) / p1.distance(p2); |
264 |
|
double dx2 = (p2.getX() - p3.getX()) / p3.distance(p2); |
265 |
|
double dy2 = (p2.getY() - p3.getY()) / p3.distance(p2); |
266 |
|
double theta1 = Math.atan2(dx1, dy1); |
267 |
|
double theta2 = Math.atan2(dx2, dy2); |
268 |
|
|
269 |
|
double dx = r * Math.cos(theta2) - r * Math.cos(theta1); |
270 |
|
double dy = -r * Math.sin(theta2) + r * Math.sin(theta1); |
271 |
|
|
272 |
|
if (theta1 < 0) |
273 |
|
theta1 += 2 * Math.PI; |
274 |
|
if (theta2 < 0) |
275 |
|
theta2 += 2 * Math.PI; |
276 |
|
if (theta2 < theta1) |
277 |
|
theta2 += 2 * Math.PI; |
278 |
|
|
279 |
|
// Vectors of the lines, not normalized, note we change |
280 |
|
// the direction of line 2. |
281 |
|
dx1 = p1.getX() - p2.getX(); |
282 |
|
dy1 = p1.getY() - p2.getY(); |
283 |
|
dx2 = p3.getX() - p2.getX(); |
284 |
|
dy2 = p3.getY() - p2.getY(); |
285 |
|
|
286 |
|
// Calculate the tangent point to the second line |
287 |
|
double t2 = -(dx1 * dy - dy1 * dx) / (dx2 * dy1 - dx1 * dy2); |
288 |
|
double x2 = t2 * (p3.getX() - p2.getX()) + p2.getX(); |
289 |
|
double y2 = t2 * (p3.getY() - p2.getY()) + p2.getY(); |
290 |
|
|
291 |
|
// calculate the center point |
292 |
|
double x = x2 - r * Math.cos(theta2); |
293 |
|
double y = y2 + r * Math.sin(theta2); |
294 |
|
|
295 |
|
setArc(x - r, y - r, 2 * r, 2 * r, Math.toDegrees(theta1), |
296 |
|
Math.toDegrees(theta2 - theta1), getArcType()); |
297 |
} |
} |
298 |
|
|
299 |
/** |
/** |
453 |
* @param h the height |
* @param h the height |
454 |
* @return the rectangle for use in getBounds2D |
* @return the rectangle for use in getBounds2D |
455 |
*/ |
*/ |
456 |
protected abstract Rectangle2D makeBounds(double x, double y, |
protected abstract Rectangle2D makeBounds(double x, double y, double w, |
457 |
double w, double h); |
double h); |
458 |
|
|
459 |
/** |
/** |
460 |
* Tests if the given angle, in degrees, is included in the arc. |
* Tests if the given angle, in degrees, is included in the arc. |
466 |
public boolean containsAngle(double a) |
public boolean containsAngle(double a) |
467 |
{ |
{ |
468 |
double start = getAngleStart(); |
double start = getAngleStart(); |
469 |
double end = start + getAngleExtent(); |
double extent = getAngleExtent(); |
470 |
|
double end = start + extent; |
471 |
|
|
472 |
|
if (extent >= 360 || extent <= -360) |
473 |
|
return true; |
474 |
|
|
475 |
|
if (extent < 0) |
476 |
|
{ |
477 |
|
end = start; |
478 |
|
start += extent; |
479 |
|
} |
480 |
|
|
481 |
start %= 360; |
start %= 360; |
482 |
if (start < 0) |
while (start < 0) |
483 |
start += 360; |
start += 360; |
484 |
|
|
485 |
end %= 360; |
end %= 360; |
486 |
if (end < 0) |
while (end < start) |
487 |
end += 360; |
end += 360; |
488 |
|
|
489 |
a %= 360; |
a %= 360; |
490 |
if (a < 0) |
while (a < start) |
491 |
a += 360; |
a += 360; |
492 |
|
|
493 |
return a >= start && a <= end; |
return a >= start && a <= end; |
497 |
* Determines if the arc contains the given point. If the bounding box |
* Determines if the arc contains the given point. If the bounding box |
498 |
* is empty, then this will return false. |
* is empty, then this will return false. |
499 |
* |
* |
500 |
|
* The area considered 'inside' an arc of type OPEN is the same as the |
501 |
|
* area inside an equivalent filled PIE-type arc. The area considered |
502 |
|
* 'inside' a CHORD-type arc is the same as the filled area. |
503 |
|
* |
504 |
* @param x the x coordinate to test |
* @param x the x coordinate to test |
505 |
* @param y the y coordinate to test |
* @param y the y coordinate to test |
506 |
* @return true if the point is inside the arc |
* @return true if the point is inside the arc |
509 |
{ |
{ |
510 |
double w = getWidth(); |
double w = getWidth(); |
511 |
double h = getHeight(); |
double h = getHeight(); |
512 |
if (w <= 0 || h <= 0) |
double extent = getAngleExtent(); |
513 |
|
if (w <= 0 || h <= 0 || extent == 0) |
514 |
|
return false; |
515 |
|
|
516 |
|
double mx = getX() + w / 2; |
517 |
|
double my = getY() + h / 2; |
518 |
|
double dx = (x - mx) * 2 / w; |
519 |
|
double dy = (y - my) * 2 / h; |
520 |
|
if ((dx * dx + dy * dy) >= 1.0) |
521 |
return false; |
return false; |
522 |
// XXX Finish implementing. |
|
523 |
throw new Error("not implemented"); |
double angle = Math.toDegrees(Math.atan2(-dy, dx)); |
524 |
|
if (getArcType() != CHORD) |
525 |
|
return containsAngle(angle); |
526 |
|
|
527 |
|
double a1 = Math.toRadians(getAngleStart()); |
528 |
|
double a2 = Math.toRadians(getAngleStart() + extent); |
529 |
|
double x1 = mx + getWidth() * Math.cos(a1) / 2; |
530 |
|
double y1 = my - getHeight() * Math.sin(a1) / 2; |
531 |
|
double x2 = mx + getWidth() * Math.cos(a2) / 2; |
532 |
|
double y2 = my - getHeight() * Math.sin(a2) / 2; |
533 |
|
double sgn = ((x2 - x1) * (my - y1) - (mx - x1) * (y2 - y1)) * ((x2 - x1) * (y |
534 |
|
- y1) - (x - x1) * (y2 - y1)); |
535 |
|
|
536 |
|
if (Math.abs(extent) > 180) |
537 |
|
{ |
538 |
|
if (containsAngle(angle)) |
539 |
|
return true; |
540 |
|
return sgn > 0; |
541 |
|
} |
542 |
|
else |
543 |
|
{ |
544 |
|
if (! containsAngle(angle)) |
545 |
|
return false; |
546 |
|
return sgn < 0; |
547 |
|
} |
548 |
} |
} |
549 |
|
|
550 |
/** |
/** |
551 |
* Tests if a given rectangle intersects the area of the arc. |
* Tests if a given rectangle intersects the area of the arc. |
552 |
* |
* |
553 |
|
* For a definition of the 'inside' area, see the contains() method. |
554 |
|
* @see #contains(double, double) |
555 |
|
* |
556 |
* @param x the x coordinate of the rectangle |
* @param x the x coordinate of the rectangle |
557 |
* @param y the y coordinate of the rectangle |
* @param y the y coordinate of the rectangle |
558 |
* @param w the width of the rectangle |
* @param w the width of the rectangle |
561 |
*/ |
*/ |
562 |
public boolean intersects(double x, double y, double w, double h) |
public boolean intersects(double x, double y, double w, double h) |
563 |
{ |
{ |
564 |
double mw = getWidth(); |
double extent = getAngleExtent(); |
565 |
double mh = getHeight(); |
if (extent == 0) |
|
if (mw <= 0 || mh <= 0 || w <= 0 || h <= 0) |
|
566 |
return false; |
return false; |
567 |
// XXX Finish implementing. |
|
568 |
throw new Error("not implemented"); |
if (contains(x, y) || contains(x, y + h) || contains(x + w, y) |
569 |
|
|| contains(x + w, y + h)) |
570 |
|
return true; |
571 |
|
|
572 |
|
double mx = getX() + getWidth() / 2; |
573 |
|
double my = getY() + getHeight() / 2; |
574 |
|
double x1 = mx |
575 |
|
+ getWidth() * Math.cos(Math.toRadians(getAngleStart())) / 2; |
576 |
|
double y1 = my |
577 |
|
- getHeight() * Math.sin(Math.toRadians(getAngleStart())) / 2; |
578 |
|
double x2 = mx |
579 |
|
+ getWidth() * Math.cos(Math.toRadians(getAngleStart() |
580 |
|
+ extent)) / 2; |
581 |
|
double y2 = my |
582 |
|
- getHeight() * Math.sin(Math.toRadians(getAngleStart() |
583 |
|
+ extent)) / 2; |
584 |
|
if (getArcType() != CHORD) |
585 |
|
{ |
586 |
|
// check intersections against the pie radii |
587 |
|
if (Line2D.linesIntersect(mx, my, x1, y1, x, y, x + w, y) |
588 |
|
|| Line2D.linesIntersect(mx, my, x1, y1, x + w, y, x + w, y + h) |
589 |
|
|| Line2D.linesIntersect(mx, my, x1, y1, x, y, x, y + h) |
590 |
|
|| Line2D.linesIntersect(mx, my, x1, y1, x, y + h, x + w, y + h)) |
591 |
|
return true; |
592 |
|
|
593 |
|
if (Line2D.linesIntersect(mx, my, x2, y2, x, y, x + w, y) |
594 |
|
|| Line2D.linesIntersect(mx, my, x2, y2, x + w, y, x + w, y + h) |
595 |
|
|| Line2D.linesIntersect(mx, my, x2, y2, x, y, x, y + h) |
596 |
|
|| Line2D.linesIntersect(mx, my, x2, y2, x, y + h, x + w, y + h)) |
597 |
|
return true; |
598 |
|
} |
599 |
|
else if (Line2D.linesIntersect(x1, y1, x2, y2, x, y, x + w, y) |
600 |
|
|| Line2D.linesIntersect(x1, y1, x2, y2, x + w, y, x + w, y + h) |
601 |
|
|| Line2D.linesIntersect(x1, y1, x2, y2, x, y, x, y + h) |
602 |
|
|| Line2D.linesIntersect(x1, y1, x2, y2, x, y + h, x + w, y + h)) |
603 |
|
return true; |
604 |
|
|
605 |
|
if ((new Rectangle2D.Double(x, y, w, h)).contains(x1, y1)) |
606 |
|
return true; |
607 |
|
|
608 |
|
return false; |
609 |
} |
} |
610 |
|
|
611 |
/** |
/** |
619 |
*/ |
*/ |
620 |
public boolean contains(double x, double y, double w, double h) |
public boolean contains(double x, double y, double w, double h) |
621 |
{ |
{ |
622 |
double mw = getWidth(); |
double extent = getAngleExtent(); |
623 |
double mh = getHeight(); |
if (extent == 0) |
624 |
if (mw <= 0 || mh <= 0 || w <= 0 || h <= 0) |
return false; |
625 |
|
|
626 |
|
if (! (contains(x, y) && contains(x, y + h) && contains(x + w, y) |
627 |
|
&& contains(x + w, y + h))) |
628 |
|
return false; |
629 |
|
|
630 |
|
double mx = getX() + getWidth() / 2; |
631 |
|
double my = getY() + getHeight() / 2; |
632 |
|
double x1 = mx |
633 |
|
+ getWidth() * Math.cos(Math.toRadians(getAngleStart())) / 2; |
634 |
|
double y1 = my |
635 |
|
- getHeight() * Math.sin(Math.toRadians(getAngleStart())) / 2; |
636 |
|
double x2 = mx |
637 |
|
+ getWidth() * Math.cos(Math.toRadians(getAngleStart() |
638 |
|
+ extent)) / 2; |
639 |
|
double y2 = my |
640 |
|
- getHeight() * Math.sin(Math.toRadians(getAngleStart() |
641 |
|
+ extent)) / 2; |
642 |
|
if (getArcType() != CHORD) |
643 |
|
{ |
644 |
|
// check intersections against the pie radii |
645 |
|
if (Line2D.linesIntersect(mx, my, x1, y1, x, y, x + w, y) |
646 |
|
|| Line2D.linesIntersect(mx, my, x1, y1, x + w, y, x + w, y + h) |
647 |
|
|| Line2D.linesIntersect(mx, my, x1, y1, x, y, x, y + h) |
648 |
|
|| Line2D.linesIntersect(mx, my, x1, y1, x, y + h, x + w, y + h)) |
649 |
|
return false; |
650 |
|
|
651 |
|
if (Line2D.linesIntersect(mx, my, x2, y2, x, y, x + w, y) |
652 |
|
|| Line2D.linesIntersect(mx, my, x2, y2, x + w, y, x + w, y + h) |
653 |
|
|| Line2D.linesIntersect(mx, my, x2, y2, x, y, x, y + h) |
654 |
|
|| Line2D.linesIntersect(mx, my, x2, y2, x, y + h, x + w, y + h)) |
655 |
|
return false; |
656 |
|
} |
657 |
|
else if (Line2D.linesIntersect(x1, y1, x2, y2, x, y, x + w, y) |
658 |
|
|| Line2D.linesIntersect(x1, y1, x2, y2, x + w, y, x + w, y + h) |
659 |
|
|| Line2D.linesIntersect(x1, y1, x2, y2, x, y, x, y + h) |
660 |
|
|| Line2D.linesIntersect(x1, y1, x2, y2, x, y + h, x + w, y + h)) |
661 |
return false; |
return false; |
662 |
// XXX Finish implementing. |
return true; |
|
throw new Error("not implemented"); |
|
663 |
} |
} |
664 |
|
|
665 |
/** |
/** |
730 |
* @param a the arc |
* @param a the arc |
731 |
* @param xform the transform |
* @param xform the transform |
732 |
*/ |
*/ |
733 |
ArcIterator(Arc2D a, AffineTransform xform) |
public ArcIterator(Arc2D a, AffineTransform xform) |
734 |
{ |
{ |
735 |
this.xform = xform; |
this.xform = xform; |
736 |
x = a.getX(); |
x = a.getX(); |
737 |
y = a.getY(); |
y = a.getY(); |
738 |
w = a.getWidth(); |
w = a.getWidth(); |
739 |
h = a.getHeight(); |
h = a.getHeight(); |
740 |
start = a.getAngleStart() * (Math.PI / 180); |
double start = a.getAngleStart() * (Math.PI / 180); |
741 |
extent = a.getAngleExtent() * (Math.PI / 180); |
double extent = a.getAngleExtent() * (Math.PI / 180); |
742 |
|
|
743 |
|
if (extent < 0) |
744 |
|
{ |
745 |
|
extent = -extent; |
746 |
|
start = 2 * Math.PI - extent + start; |
747 |
|
} |
748 |
|
this.start = start; |
749 |
|
this.extent = extent; |
750 |
|
|
751 |
type = a.type; |
type = a.type; |
|
double e = extent < 0 ? -extent : extent; |
|
752 |
if (w < 0 || h < 0) |
if (w < 0 || h < 0) |
753 |
limit = -1; |
limit = -1; |
754 |
else if (e == 0) |
else if (extent == 0) |
755 |
limit = type; |
limit = type; |
756 |
else if (e <= Math.PI / 2.0) |
else if (extent <= Math.PI / 2.0) |
757 |
limit = type + 1; |
limit = type + 1; |
758 |
else if (e <= Math.PI) |
else if (extent <= Math.PI) |
759 |
limit = type + 2; |
limit = type + 2; |
760 |
else if (e <= 3.0 * (Math.PI / 2.0)) |
else if (extent <= 3.0 * (Math.PI / 2.0)) |
761 |
limit = type + 3; |
limit = type + 3; |
762 |
else |
else |
763 |
limit = type + 4; |
limit = type + 4; |
764 |
} |
} |
765 |
|
|
766 |
/** |
/** |
769 |
* @param e the ellipse |
* @param e the ellipse |
770 |
* @param xform the transform |
* @param xform the transform |
771 |
*/ |
*/ |
772 |
ArcIterator(Ellipse2D e, AffineTransform xform) |
public ArcIterator(Ellipse2D e, AffineTransform xform) |
773 |
{ |
{ |
774 |
this.xform = xform; |
this.xform = xform; |
775 |
x = e.getX(); |
x = e.getX(); |
777 |
w = e.getWidth(); |
w = e.getWidth(); |
778 |
h = e.getHeight(); |
h = e.getHeight(); |
779 |
start = 0; |
start = 0; |
780 |
extent = -2 * Math.PI; |
extent = 2 * Math.PI; |
781 |
type = CHORD; |
type = CHORD; |
782 |
limit = (w < 0 || h < 0) ? -1 : 5; |
limit = (w < 0 || h < 0) ? -1 : 5; |
783 |
} |
} |
821 |
public int currentSegment(float[] coords) |
public int currentSegment(float[] coords) |
822 |
{ |
{ |
823 |
double[] double_coords = new double[6]; |
double[] double_coords = new double[6]; |
824 |
int code = currentSegment (double_coords); |
int code = currentSegment(double_coords); |
825 |
for (int i = 0; i < 6; ++i) |
for (int i = 0; i < 6; ++i) |
826 |
coords[i] = (float) double_coords[i]; |
coords[i] = (float) double_coords[i]; |
827 |
return code; |
return code; |
828 |
} |
} |
829 |
|
|
837 |
*/ |
*/ |
838 |
public int currentSegment(double[] coords) |
public int currentSegment(double[] coords) |
839 |
{ |
{ |
840 |
double rx = w/2; |
double rx = w / 2; |
841 |
double ry = h/2; |
double ry = h / 2; |
842 |
double xmid = x + rx; |
double xmid = x + rx; |
843 |
double ymid = y + ry; |
double ymid = y + ry; |
844 |
|
|
845 |
if (current > limit) |
if (current > limit) |
846 |
throw new NoSuchElementException("arc iterator out of bounds"); |
throw new NoSuchElementException("arc iterator out of bounds"); |
847 |
|
|
848 |
if (current == 0) |
if (current == 0) |
849 |
{ |
{ |
850 |
coords[0] = xmid + rx * Math.cos(start); |
coords[0] = xmid + rx * Math.cos(start); |
851 |
coords[1] = ymid - ry * Math.sin(start); |
coords[1] = ymid - ry * Math.sin(start); |
852 |
if (xform != null) |
if (xform != null) |
853 |
xform.transform(coords, 0, coords, 0, 1); |
xform.transform(coords, 0, coords, 0, 1); |
854 |
return SEG_MOVETO; |
return SEG_MOVETO; |
855 |
} |
} |
856 |
|
|
857 |
if (type != OPEN && current == limit) |
if (type != OPEN && current == limit) |
858 |
return SEG_CLOSE; |
return SEG_CLOSE; |
859 |
|
|
860 |
if ((current == limit - 1) && |
if ((current == limit - 1) && (type == PIE)) |
|
(type == PIE) || (type == CHORD)) |
|
861 |
{ |
{ |
862 |
if (type == PIE) |
coords[0] = xmid; |
863 |
{ |
coords[1] = ymid; |
864 |
coords[0] = xmid; |
if (xform != null) |
865 |
coords[1] = ymid; |
xform.transform(coords, 0, coords, 0, 1); |
866 |
} |
return SEG_LINETO; |
|
else if (type == CHORD) |
|
|
{ |
|
|
coords[0] = xmid + rx * Math.cos(start); |
|
|
coords[1] = ymid - ry * Math.sin(start); |
|
|
} |
|
|
if (xform != null) |
|
|
xform.transform(coords, 0, coords, 0, 1); |
|
|
return SEG_LINETO; |
|
867 |
} |
} |
868 |
|
|
869 |
// note that this produces a cubic approximation of the arc segment, |
// note that this produces a cubic approximation of the arc segment, |
870 |
// not a true ellipsoid. there's no ellipsoid path segment code, |
// not a true ellipsoid. there's no ellipsoid path segment code, |
871 |
// unfortunately. the cubic approximation looks about right, though. |
// unfortunately. the cubic approximation looks about right, though. |
|
|
|
872 |
double kappa = (Math.sqrt(2.0) - 1.0) * (4.0 / 3.0); |
double kappa = (Math.sqrt(2.0) - 1.0) * (4.0 / 3.0); |
873 |
double quad = (Math.PI / 2.0); |
double quad = (Math.PI / 2.0); |
874 |
|
|
878 |
|
|
879 |
double x0 = xmid + rx * Math.cos(curr_begin); |
double x0 = xmid + rx * Math.cos(curr_begin); |
880 |
double y0 = ymid - ry * Math.sin(curr_begin); |
double y0 = ymid - ry * Math.sin(curr_begin); |
881 |
|
|
882 |
double x1 = xmid + rx * Math.cos(curr_begin + curr_extent); |
double x1 = xmid + rx * Math.cos(curr_begin + curr_extent); |
883 |
double y1 = ymid - ry * Math.sin(curr_begin + curr_extent); |
double y1 = ymid - ry * Math.sin(curr_begin + curr_extent); |
884 |
|
|
885 |
AffineTransform trans = new AffineTransform (); |
AffineTransform trans = new AffineTransform(); |
886 |
double [] cvec = new double[2]; |
double[] cvec = new double[2]; |
887 |
double len = kappa * portion_of_a_quadrant; |
double len = kappa * portion_of_a_quadrant; |
888 |
double angle = curr_begin; |
double angle = curr_begin; |
889 |
|
|
890 |
// in a hypothetical "first quadrant" setting, our first control |
// in a hypothetical "first quadrant" setting, our first control |
891 |
// vector would be sticking up, from [1,0] to [1,kappa]. |
// vector would be sticking up, from [1,0] to [1,kappa]. |
894 |
// from what one would consider "normal" first quadrant rules, so we |
// from what one would consider "normal" first quadrant rules, so we |
895 |
// will *subtract* the y value of this control vector from our first |
// will *subtract* the y value of this control vector from our first |
896 |
// point. |
// point. |
|
|
|
897 |
cvec[0] = 0; |
cvec[0] = 0; |
898 |
cvec[1] = len; |
cvec[1] = len; |
899 |
trans.scale (rx, ry); |
trans.scale(rx, ry); |
900 |
trans.rotate (angle); |
trans.rotate(angle); |
901 |
trans.transform(cvec, 0, cvec, 0, 1); |
trans.transform(cvec, 0, cvec, 0, 1); |
902 |
coords[0] = x0 + cvec[0]; |
coords[0] = x0 + cvec[0]; |
903 |
coords[1] = y0 - cvec[1]; |
coords[1] = y0 - cvec[1]; |
904 |
|
|
905 |
// control vector #2 would, ideally, be sticking out and to the |
// control vector #2 would, ideally, be sticking out and to the |
906 |
// right, in a first quadrant arc segment. again, subtraction of y. |
// right, in a first quadrant arc segment. again, subtraction of y. |
|
|
|
907 |
cvec[0] = 0; |
cvec[0] = 0; |
908 |
cvec[1] = -len; |
cvec[1] = -len; |
909 |
trans.rotate (curr_extent); |
trans.rotate(curr_extent); |
910 |
trans.transform(cvec, 0, cvec, 0, 1); |
trans.transform(cvec, 0, cvec, 0, 1); |
911 |
coords[2] = x1 + cvec[0]; |
coords[2] = x1 + cvec[0]; |
912 |
coords[3] = y1 - cvec[1]; |
coords[3] = y1 - cvec[1]; |
913 |
|
|
914 |
// end point |
// end point |
915 |
coords[4] = x1; |
coords[4] = x1; |
916 |
coords[5] = y1; |
coords[5] = y1; |
917 |
|
|
918 |
if (xform != null) |
if (xform != null) |
919 |
xform.transform(coords, 0, coords, 0, 3); |
xform.transform(coords, 0, coords, 0, 3); |
920 |
|
|
921 |
return SEG_CUBICTO; |
return SEG_CUBICTO; |
922 |
} |
} |
979 |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
980 |
* @throws IllegalArgumentException if type is invalid |
* @throws IllegalArgumentException if type is invalid |
981 |
*/ |
*/ |
982 |
public Double(double x, double y, double w, double h, |
public Double(double x, double y, double w, double h, double start, |
983 |
double start, double extent, int type) |
double extent, int type) |
984 |
{ |
{ |
985 |
super(type); |
super(type); |
986 |
this.x = x; |
this.x = x; |
990 |
this.start = start; |
this.start = start; |
991 |
this.extent = extent; |
this.extent = extent; |
992 |
} |
} |
993 |
|
|
994 |
/** |
/** |
995 |
* Create a new arc with the given dimensions. |
* Create a new arc with the given dimensions. |
996 |
* |
* |
1094 |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
1095 |
* @throws IllegalArgumentException if type is invalid |
* @throws IllegalArgumentException if type is invalid |
1096 |
*/ |
*/ |
1097 |
public void setArc(double x, double y, double w, double h, |
public void setArc(double x, double y, double w, double h, double start, |
1098 |
double start, double extent, int type) |
double extent, int type) |
1099 |
{ |
{ |
1100 |
this.x = x; |
this.x = x; |
1101 |
this.y = y; |
this.y = y; |
1198 |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
1199 |
* @throws IllegalArgumentException if type is invalid |
* @throws IllegalArgumentException if type is invalid |
1200 |
*/ |
*/ |
1201 |
public Float(float x, float y, float w, float h, |
public Float(float x, float y, float w, float h, float start, |
1202 |
float start, float extent, int type) |
float extent, int type) |
1203 |
{ |
{ |
1204 |
super(type); |
super(type); |
1205 |
this.x = x; |
this.x = x; |
1209 |
this.start = start; |
this.start = start; |
1210 |
this.extent = extent; |
this.extent = extent; |
1211 |
} |
} |
1212 |
|
|
1213 |
/** |
/** |
1214 |
* Create a new arc with the given dimensions. |
* Create a new arc with the given dimensions. |
1215 |
* |
* |
1228 |
width = (float) r.getWidth(); |
width = (float) r.getWidth(); |
1229 |
height = (float) r.getHeight(); |
height = (float) r.getHeight(); |
1230 |
this.start = start; |
this.start = start; |
1231 |
this.extent = extent; |
this.extent = (float) extent; |
1232 |
} |
} |
1233 |
|
|
1234 |
/** |
/** |
1313 |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
* @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} |
1314 |
* @throws IllegalArgumentException if type is invalid |
* @throws IllegalArgumentException if type is invalid |
1315 |
*/ |
*/ |
1316 |
public void setArc(double x, double y, double w, double h, |
public void setArc(double x, double y, double w, double h, double start, |
1317 |
double start, double extent, int type) |
double extent, int type) |
1318 |
{ |
{ |
1319 |
this.x = (float) x; |
this.x = (float) x; |
1320 |
this.y = (float) y; |
this.y = (float) y; |