📄 arc2d.java
字号:
{ double start = getAngleStart(); double extent = getAngleExtent(); double end = start + extent; if (extent == 0) return false; if (extent >= 360 || extent <= -360) return true; if (extent < 0) { end = start; start += extent; } start %= 360; while (start < 0) start += 360; end %= 360; while (end < start) end += 360; a %= 360; while (a < start) a += 360; return a >= start && a < end; // starting angle included, ending angle not } /** * Determines if the arc contains the given point. If the bounding box * is empty, then this will return false. * * The area considered 'inside' an arc of type OPEN is the same as the * area inside an equivalent filled CHORD-type arc. The area considered * 'inside' a CHORD-type arc is the same as the filled area. * * @param x the x coordinate to test * @param y the y coordinate to test * @return true if the point is inside the arc */ public boolean contains(double x, double y) { double w = getWidth(); double h = getHeight(); double extent = getAngleExtent(); if (w <= 0 || h <= 0 || extent == 0) return false; double mx = getX() + w / 2; double my = getY() + h / 2; double dx = (x - mx) * 2 / w; double dy = (y - my) * 2 / h; if ((dx * dx + dy * dy) >= 1.0) return false; double angle = Math.toDegrees(Math.atan2(-dy, dx)); if (getArcType() == PIE) return containsAngle(angle); double a1 = Math.toRadians(getAngleStart()); double a2 = Math.toRadians(getAngleStart() + extent); double x1 = mx + getWidth() * Math.cos(a1) / 2; double y1 = my - getHeight() * Math.sin(a1) / 2; double x2 = mx + getWidth() * Math.cos(a2) / 2; double y2 = my - getHeight() * Math.sin(a2) / 2; double sgn = ((x2 - x1) * (my - y1) - (mx - x1) * (y2 - y1)) * ((x2 - x1) * (y - y1) - (x - x1) * (y2 - y1)); if (Math.abs(extent) > 180) { if (containsAngle(angle)) return true; return sgn > 0; } else { if (! containsAngle(angle)) return false; return sgn < 0; } } /** * Tests if a given rectangle intersects the area of the arc. * * For a definition of the 'inside' area, see the contains() method. * @see #contains(double, double) * * @param x the x coordinate of the rectangle * @param y the y coordinate of the rectangle * @param w the width of the rectangle * @param h the height of the rectangle * @return true if the two shapes share common points */ public boolean intersects(double x, double y, double w, double h) { double extent = getAngleExtent(); if (extent == 0) return false; if (contains(x, y) || contains(x, y + h) || contains(x + w, y) || contains(x + w, y + h)) return true; Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); double a = getWidth() / 2.0; double b = getHeight() / 2.0; double mx = getX() + a; double my = getY() + b; double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); if (getArcType() != CHORD) { // check intersections against the pie radii if (rect.intersectsLine(mx, my, x1, y1)) return true; if (rect.intersectsLine(mx, my, x2, y2)) return true; } else// check the chord if (rect.intersectsLine(x1, y1, x2, y2)) return true; // Check the Arc segment against the four edges double dx; // Check the Arc segment against the four edges double dy; dy = y - my; dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); if (! java.lang.Double.isNaN(dx)) { if (mx + dx >= x && mx + dx <= x + w && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) return true; if (mx - dx >= x && mx - dx <= x + w && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) return true; } dy = (y + h) - my; dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); if (! java.lang.Double.isNaN(dx)) { if (mx + dx >= x && mx + dx <= x + w && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) return true; if (mx - dx >= x && mx - dx <= x + w && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) return true; } dx = x - mx; dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); if (! java.lang.Double.isNaN(dy)) { if (my + dy >= y && my + dy <= y + h && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) return true; if (my - dy >= y && my - dy <= y + h && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) return true; } dx = (x + w) - mx; dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); if (! java.lang.Double.isNaN(dy)) { if (my + dy >= y && my + dy <= y + h && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) return true; if (my - dy >= y && my - dy <= y + h && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) return true; } // Check whether the arc is contained within the box if (rect.contains(mx, my)) return true; return false; } /** * Tests if a given rectangle is contained in the area of the arc. * * @param x the x coordinate of the rectangle * @param y the y coordinate of the rectangle * @param w the width of the rectangle * @param h the height of the rectangle * @return true if the arc contains the rectangle */ public boolean contains(double x, double y, double w, double h) { double extent = getAngleExtent(); if (extent == 0) return false; if (! (contains(x, y) && contains(x, y + h) && contains(x + w, y) && contains(x + w, y + h))) return false; Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); double a = getWidth() / 2.0; double b = getHeight() / 2.0; double mx = getX() + a; double my = getY() + b; double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); if (getArcType() != CHORD) { // check intersections against the pie radii if (rect.intersectsLine(mx, my, x1, y1)) return false; if (rect.intersectsLine(mx, my, x2, y2)) return false; } else if (rect.intersectsLine(x1, y1, x2, y2)) return false; return true; } /** * Tests if a given rectangle is contained in the area of the arc. * * @param r the rectangle * @return true if the arc contains the rectangle */ public boolean contains(Rectangle2D r) { return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } /** * Returns an iterator over this arc, with an optional transformation. * This iterator is threadsafe, so future modifications to the arc do not * affect the iteration. * * @param at the transformation, or null * @return a path iterator */ public PathIterator getPathIterator(AffineTransform at) { return new ArcIterator(this, at); } /** * This class is used to iterate over an arc. Since ellipses are a subclass * of arcs, this is used by Ellipse2D as well. * * @author Eric Blake (ebb9@email.byu.edu) */ static final class ArcIterator implements PathIterator { /** The current iteration. */ private int current; /** The last iteration. */ private final int limit; /** The optional transformation. */ private final AffineTransform xform; /** The x coordinate of the bounding box. */ private final double x; /** The y coordinate of the bounding box. */ private final double y; /** The width of the bounding box. */ private final double w; /** The height of the bounding box. */ private final double h; /** The start angle, in radians (not degrees). */ private final double start; /** The extent angle, in radians (not degrees). */ private final double extent; /** The arc closure type. */ private final int type; /** * Construct a new iterator over an arc. * * @param a the arc * @param xform the transform */ public ArcIterator(Arc2D a, AffineTransform xform) { this.xform = xform; x = a.getX(); y = a.getY(); w = a.getWidth(); h = a.getHeight(); double start = a.getAngleStart() * (Math.PI / 180); double extent = a.getAngleExtent() * (Math.PI / 180); if (extent < 0) { extent = -extent; start = 2 * Math.PI - extent + start; } this.start = start; this.extent = extent; type = a.type; if (w < 0 || h < 0) limit = -1; else if (extent == 0) limit = type; else if (extent <= Math.PI / 2.0) limit = type + 1; else if (extent <= Math.PI) limit = type + 2; else if (extent <= 3.0 * (Math.PI / 2.0)) limit = type + 3; else limit = type + 4; } /** * Construct a new iterator over an ellipse. * * @param e the ellipse * @param xform the transform */ public ArcIterator(Ellipse2D e, AffineTransform xform) { this.xform = xform; x = e.getX(); y = e.getY(); w = e.getWidth(); h = e.getHeight(); start = 0; extent = 2 * Math.PI; type = CHORD; limit = (w < 0 || h < 0) ? -1 : 5; } /** * Return the winding rule. * * @return {@link PathIterator#WIND_NON_ZERO} */ public int getWindingRule() { return WIND_NON_ZERO; } /** * Test if the iteration is complete. * * @return true if more segments exist */ public boolean isDone() { return current > limit; } /** * Advance the iterator. */ public void next() { current++; } /** * Put the current segment into the array, and return the segment type. * * @param coords an array of 6 elements * @return the segment type * @throws NullPointerException if coords is null * @throws ArrayIndexOutOfBoundsException if coords is too small */ public int currentSegment(float[] coords) { double[] double_coords = new double[6]; int code = currentSegment(double_coords); for (int i = 0; i < 6; ++i) coords[i] = (float) double_coords[i]; return code; } /** * Put the current segment into the array, and return the segment type. * * @param coords an array of 6 elements * @return the segment type * @throws NullPointerException if coords is null * @throws ArrayIndexOutOfBoundsException if coords is too small */ public int currentSegment(double[] coords) { double rx = w / 2; double ry = h / 2; double xmid = x + rx; double ymid = y + ry; if (current > limit) throw new NoSuchElementException("arc iterator out of bounds"); if (current == 0) { 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_MOVETO; } if (type != OPEN && current == limit) return SEG_CLOSE; if ((current == limit - 1) && (type == PIE)) { coords[0] = xmid; coords[1] = ymid; if (xform != null) xform.transform(coords, 0, coords, 0, 1); return SEG_LINETO; } // note that this produces a cubic approximation of the arc segment, // not a true ellipsoid. there's no ellipsoid path segment code, // unfortunately. the cubic approximation looks about right, though. double kappa = (Math.sqrt(2.0) - 1.0) * (4.0 / 3.0); double quad = (Math.PI / 2.0); double curr_begin = start + (current - 1) * quad; double curr_extent = Math.min((start + extent) - curr_begin, quad); double portion_of_a_quadrant = curr_extent / quad; double x0 = xmid + rx * Math.cos(curr_begin); double y0 = ymid - ry * Math.sin(curr_begin); double x1 = xmid + rx * Math.cos(curr_begin + curr_extent); double y1 = ymid - ry * Math.sin(curr_begin + curr_extent); AffineTransform trans = new AffineTransform(); double[] cvec = new double[2]; double len = kappa * portion_of_a_quadrant; double angle = curr_begin; // in a hypothetical "first quadrant" setting, our first control // vector would be sticking up, from [1,0] to [1,kappa]. // // let us recall however that in java2d, y coords are upside down // from what one would consider "normal" first quadrant rules, so we // will *subtract* the y value of this control vector from our first // point. cvec[0] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -