feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of an arc
* through the PathIterator interface.
*
* @author Jim Graham
*/
class ArcIterator implements PathIterator {
double x, y, w, h, angStRad, increment, cv;
AffineTransform affine;
int index;
int arcSegs;
int lineSegs;
ArcIterator(Arc2D a, AffineTransform at) {
this.w = a.getWidth() / 2;
this.h = a.getHeight() / 2;
this.x = a.getX() + w;
this.y = a.getY() + h;
this.angStRad = -Math.toRadians(a.getAngleStart());
this.affine = at;
double ext = -a.getAngleExtent();
if (ext >= 360.0 || ext <= -360) {
arcSegs = 4;
this.increment = Math.PI / 2;
// btan(Math.PI / 2);
this.cv = 0.5522847498307933;
if (ext < 0) {
increment = -increment;
cv = -cv;
}
} else {
arcSegs = (int) Math.ceil(Math.abs(ext) / 90.0);
this.increment = Math.toRadians(ext / arcSegs);
this.cv = btan(increment);
if (cv == 0) {
arcSegs = 0;
}
}
switch (a.getArcType()) {
case Arc2D.OPEN:
lineSegs = 0;
break;
case Arc2D.CHORD:
lineSegs = 1;
break;
case Arc2D.PIE:
lineSegs = 2;
break;
}
if (w < 0 || h < 0) {
arcSegs = lineSegs = -1;
}
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return index > arcSegs + lineSegs;
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
/*
* btan computes the length (k) of the control segments at
* the beginning and end of a cubic bezier that approximates
* a segment of an arc with extent less than or equal to
* 90 degrees. This length (k) will be used to generate the
* 2 bezier control points for such a segment.
*
* Assumptions:
* a) arc is centered on 0,0 with radius of 1.0
* b) arc extent is less than 90 degrees
* c) control points should preserve tangent
* d) control segments should have equal length
*
* Initial data:
* start angle: ang1
* end angle: ang2 = ang1 + extent
* start point: P1 = (x1, y1) = (cos(ang1), sin(ang1))
* end point: P4 = (x4, y4) = (cos(ang2), sin(ang2))
*
* Control points:
* P2 = (x2, y2)
* | x2 = x1 - k * sin(ang1) = cos(ang1) - k * sin(ang1)
* | y2 = y1 + k * cos(ang1) = sin(ang1) + k * cos(ang1)
*
* P3 = (x3, y3)
* | x3 = x4 + k * sin(ang2) = cos(ang2) + k * sin(ang2)
* | y3 = y4 - k * cos(ang2) = sin(ang2) - k * cos(ang2)
*
* The formula for this length (k) can be found using the
* following derivations:
*
* Midpoints:
* a) bezier (t = 1/2)
* bPm = P1 * (1-t)^3 +
* 3 * P2 * t * (1-t)^2 +
* 3 * P3 * t^2 * (1-t) +
* P4 * t^3 =
* = (P1 + 3P2 + 3P3 + P4)/8
*
* b) arc
* aPm = (cos((ang1 + ang2)/2), sin((ang1 + ang2)/2))
*
* Let angb = (ang2 - ang1)/2; angb is half of the angle
* between ang1 and ang2.
*
* Solve the equation bPm == aPm
*
* a) For xm coord:
* x1 + 3*x2 + 3*x3 + x4 = 8*cos((ang1 + ang2)/2)
*
* cos(ang1) + 3*cos(ang1) - 3*k*sin(ang1) +
* 3*cos(ang2) + 3*k*sin(ang2) + cos(ang2) =
* = 8*cos((ang1 + ang2)/2)
*
* 4*cos(ang1) + 4*cos(ang2) + 3*k*(sin(ang2) - sin(ang1)) =
* = 8*cos((ang1 + ang2)/2)
*
* 8*cos((ang1 + ang2)/2)*cos((ang2 - ang1)/2) +
* 6*k*sin((ang2 - ang1)/2)*cos((ang1 + ang2)/2) =
* = 8*cos((ang1 + ang2)/2)
*
* 4*cos(angb) + 3*k*sin(angb) = 4
*
* k = 4 / 3 * (1 - cos(angb)) / sin(angb)
*
* b) For ym coord we derive the same formula.
*
* Since this formula can generate "NaN" values for small
* angles, we will derive a safer form that does not involve
* dividing by very small values:
* (1 - cos(angb)) / sin(angb) =
* = (1 - cos(angb))*(1 + cos(angb)) / sin(angb)*(1 + cos(angb)) =
* = (1 - cos(angb)^2) / sin(angb)*(1 + cos(angb)) =
* = sin(angb)^2 / sin(angb)*(1 + cos(angb)) =
* = sin(angb) / (1 + cos(angb))
*
*/
private static double btan(double increment) {
increment /= 2.0;
return 4.0 / 3.0 * Math.sin(increment) / (1.0 + Math.cos(increment));
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("arc iterator out of bounds");
}
double angle = angStRad;
if (index == 0) {
coords[0] = (float) (x + Math.cos(angle) * w);
coords[1] = (float) (y + Math.sin(angle) * h);
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return SEG_MOVETO;
}
if (index > arcSegs) {
if (index == arcSegs + lineSegs) {
return SEG_CLOSE;
}
coords[0] = (float) x;
coords[1] = (float) y;
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return SEG_LINETO;
}
angle += increment * (index - 1);
double relx = Math.cos(angle);
double rely = Math.sin(angle);
coords[0] = (float) (x + (relx - cv * rely) * w);
coords[1] = (float) (y + (rely + cv * relx) * h);
angle += increment;
relx = Math.cos(angle);
rely = Math.sin(angle);
coords[2] = (float) (x + (relx + cv * rely) * w);
coords[3] = (float) (y + (rely - cv * relx) * h);
coords[4] = (float) (x + relx * w);
coords[5] = (float) (y + rely * h);
if (affine != null) {
affine.transform(coords, 0, coords, 0, 3);
}
return SEG_CUBICTO;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("arc iterator out of bounds");
}
double angle = angStRad;
if (index == 0) {
coords[0] = x + Math.cos(angle) * w;
coords[1] = y + Math.sin(angle) * h;
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return SEG_MOVETO;
}
if (index > arcSegs) {
if (index == arcSegs + lineSegs) {
return SEG_CLOSE;
}
coords[0] = x;
coords[1] = y;
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return SEG_LINETO;
}
angle += increment * (index - 1);
double relx = Math.cos(angle);
double rely = Math.sin(angle);
coords[0] = x + (relx - cv * rely) * w;
coords[1] = y + (rely + cv * relx) * h;
angle += increment;
relx = Math.cos(angle);
rely = Math.sin(angle);
coords[2] = x + (relx + cv * rely) * w;
coords[3] = y + (rely - cv * relx) * h;
coords[4] = x + relx * w;
coords[5] = y + rely * h;
if (affine != null) {
affine.transform(coords, 0, coords, 0, 3);
}
return SEG_CUBICTO;
}
}

View File

@@ -0,0 +1,744 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.awt.Shape;
import java.awt.Rectangle;
import java.util.Vector;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import sun.awt.geom.Curve;
import sun.awt.geom.Crossings;
import sun.awt.geom.AreaOp;
/**
* An <code>Area</code> object stores and manipulates a
* resolution-independent description of an enclosed area of
* 2-dimensional space.
* <code>Area</code> objects can be transformed and can perform
* various Constructive Area Geometry (CAG) operations when combined
* with other <code>Area</code> objects.
* The CAG operations include area
* {@link #add addition}, {@link #subtract subtraction},
* {@link #intersect intersection}, and {@link #exclusiveOr exclusive or}.
* See the linked method documentation for examples of the various
* operations.
* <p>
* The <code>Area</code> class implements the <code>Shape</code>
* interface and provides full support for all of its hit-testing
* and path iteration facilities, but an <code>Area</code> is more
* specific than a generalized path in a number of ways:
* <ul>
* <li>Only closed paths and sub-paths are stored.
* <code>Area</code> objects constructed from unclosed paths
* are implicitly closed during construction as if those paths
* had been filled by the <code>Graphics2D.fill</code> method.
* <li>The interiors of the individual stored sub-paths are all
* non-empty and non-overlapping. Paths are decomposed during
* construction into separate component non-overlapping parts,
* empty pieces of the path are discarded, and then these
* non-empty and non-overlapping properties are maintained
* through all subsequent CAG operations. Outlines of different
* component sub-paths may touch each other, as long as they
* do not cross so that their enclosed areas overlap.
* <li>The geometry of the path describing the outline of the
* <code>Area</code> resembles the path from which it was
* constructed only in that it describes the same enclosed
* 2-dimensional area, but may use entirely different types
* and ordering of the path segments to do so.
* </ul>
* Interesting issues which are not always obvious when using
* the <code>Area</code> include:
* <ul>
* <li>Creating an <code>Area</code> from an unclosed (open)
* <code>Shape</code> results in a closed outline in the
* <code>Area</code> object.
* <li>Creating an <code>Area</code> from a <code>Shape</code>
* which encloses no area (even when "closed") produces an
* empty <code>Area</code>. A common example of this issue
* is that producing an <code>Area</code> from a line will
* be empty since the line encloses no area. An empty
* <code>Area</code> will iterate no geometry in its
* <code>PathIterator</code> objects.
* <li>A self-intersecting <code>Shape</code> may be split into
* two (or more) sub-paths each enclosing one of the
* non-intersecting portions of the original path.
* <li>An <code>Area</code> may take more path segments to
* describe the same geometry even when the original
* outline is simple and obvious. The analysis that the
* <code>Area</code> class must perform on the path may
* not reflect the same concepts of "simple and obvious"
* as a human being perceives.
* </ul>
*
* @since 1.2
*/
public class Area implements Shape, Cloneable {
private static Vector EmptyCurves = new Vector();
private Vector curves;
/**
* Default constructor which creates an empty area.
* @since 1.2
*/
public Area() {
curves = EmptyCurves;
}
/**
* The <code>Area</code> class creates an area geometry from the
* specified {@link Shape} object. The geometry is explicitly
* closed, if the <code>Shape</code> is not already closed. The
* fill rule (even-odd or winding) specified by the geometry of the
* <code>Shape</code> is used to determine the resulting enclosed area.
* @param s the <code>Shape</code> from which the area is constructed
* @throws NullPointerException if <code>s</code> is null
* @since 1.2
*/
public Area(Shape s) {
if (s instanceof Area) {
curves = ((Area) s).curves;
} else {
curves = pathToCurves(s.getPathIterator(null));
}
}
private static Vector pathToCurves(PathIterator pi) {
Vector curves = new Vector();
int windingRule = pi.getWindingRule();
// coords array is big enough for holding:
// coordinates returned from currentSegment (6)
// OR
// two subdivided quadratic curves (2+4+4=10)
// AND
// 0-1 horizontal splitting parameters
// OR
// 2 parametric equation derivative coefficients
// OR
// three subdivided cubic curves (2+6+6+6=20)
// AND
// 0-2 horizontal splitting parameters
// OR
// 3 parametric equation derivative coefficients
double coords[] = new double[23];
double movx = 0, movy = 0;
double curx = 0, cury = 0;
double newx, newy;
while (!pi.isDone()) {
switch (pi.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
Curve.insertLine(curves, curx, cury, movx, movy);
curx = movx = coords[0];
cury = movy = coords[1];
Curve.insertMove(curves, movx, movy);
break;
case PathIterator.SEG_LINETO:
newx = coords[0];
newy = coords[1];
Curve.insertLine(curves, curx, cury, newx, newy);
curx = newx;
cury = newy;
break;
case PathIterator.SEG_QUADTO:
newx = coords[2];
newy = coords[3];
Curve.insertQuad(curves, curx, cury, coords);
curx = newx;
cury = newy;
break;
case PathIterator.SEG_CUBICTO:
newx = coords[4];
newy = coords[5];
Curve.insertCubic(curves, curx, cury, coords);
curx = newx;
cury = newy;
break;
case PathIterator.SEG_CLOSE:
Curve.insertLine(curves, curx, cury, movx, movy);
curx = movx;
cury = movy;
break;
}
pi.next();
}
Curve.insertLine(curves, curx, cury, movx, movy);
AreaOp operator;
if (windingRule == PathIterator.WIND_EVEN_ODD) {
operator = new AreaOp.EOWindOp();
} else {
operator = new AreaOp.NZWindOp();
}
return operator.calculate(curves, EmptyCurves);
}
/**
* Adds the shape of the specified <code>Area</code> to the
* shape of this <code>Area</code>.
* The resulting shape of this <code>Area</code> will include
* the union of both shapes, or all areas that were contained
* in either this or the specified <code>Area</code>.
* <pre>
* // Example:
* Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
* Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
* a1.add(a2);
*
* a1(before) + a2 = a1(after)
*
* ################ ################ ################
* ############## ############## ################
* ############ ############ ################
* ########## ########## ################
* ######## ######## ################
* ###### ###### ###### ######
* #### #### #### ####
* ## ## ## ##
* </pre>
* @param rhs the <code>Area</code> to be added to the
* current shape
* @throws NullPointerException if <code>rhs</code> is null
* @since 1.2
*/
public void add(Area rhs) {
curves = new AreaOp.AddOp().calculate(this.curves, rhs.curves);
invalidateBounds();
}
/**
* Subtracts the shape of the specified <code>Area</code> from the
* shape of this <code>Area</code>.
* The resulting shape of this <code>Area</code> will include
* areas that were contained only in this <code>Area</code>
* and not in the specified <code>Area</code>.
* <pre>
* // Example:
* Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
* Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
* a1.subtract(a2);
*
* a1(before) - a2 = a1(after)
*
* ################ ################
* ############## ############## ##
* ############ ############ ####
* ########## ########## ######
* ######## ######## ########
* ###### ###### ######
* #### #### ####
* ## ## ##
* </pre>
* @param rhs the <code>Area</code> to be subtracted from the
* current shape
* @throws NullPointerException if <code>rhs</code> is null
* @since 1.2
*/
public void subtract(Area rhs) {
curves = new AreaOp.SubOp().calculate(this.curves, rhs.curves);
invalidateBounds();
}
/**
* Sets the shape of this <code>Area</code> to the intersection of
* its current shape and the shape of the specified <code>Area</code>.
* The resulting shape of this <code>Area</code> will include
* only areas that were contained in both this <code>Area</code>
* and also in the specified <code>Area</code>.
* <pre>
* // Example:
* Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
* Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
* a1.intersect(a2);
*
* a1(before) intersect a2 = a1(after)
*
* ################ ################ ################
* ############## ############## ############
* ############ ############ ########
* ########## ########## ####
* ######## ########
* ###### ######
* #### ####
* ## ##
* </pre>
* @param rhs the <code>Area</code> to be intersected with this
* <code>Area</code>
* @throws NullPointerException if <code>rhs</code> is null
* @since 1.2
*/
public void intersect(Area rhs) {
curves = new AreaOp.IntOp().calculate(this.curves, rhs.curves);
invalidateBounds();
}
/**
* Sets the shape of this <code>Area</code> to be the combined area
* of its current shape and the shape of the specified <code>Area</code>,
* minus their intersection.
* The resulting shape of this <code>Area</code> will include
* only areas that were contained in either this <code>Area</code>
* or in the specified <code>Area</code>, but not in both.
* <pre>
* // Example:
* Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
* Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
* a1.exclusiveOr(a2);
*
* a1(before) xor a2 = a1(after)
*
* ################ ################
* ############## ############## ## ##
* ############ ############ #### ####
* ########## ########## ###### ######
* ######## ######## ################
* ###### ###### ###### ######
* #### #### #### ####
* ## ## ## ##
* </pre>
* @param rhs the <code>Area</code> to be exclusive ORed with this
* <code>Area</code>.
* @throws NullPointerException if <code>rhs</code> is null
* @since 1.2
*/
public void exclusiveOr(Area rhs) {
curves = new AreaOp.XorOp().calculate(this.curves, rhs.curves);
invalidateBounds();
}
/**
* Removes all of the geometry from this <code>Area</code> and
* restores it to an empty area.
* @since 1.2
*/
public void reset() {
curves = new Vector();
invalidateBounds();
}
/**
* Tests whether this <code>Area</code> object encloses any area.
* @return <code>true</code> if this <code>Area</code> object
* represents an empty area; <code>false</code> otherwise.
* @since 1.2
*/
public boolean isEmpty() {
return (curves.size() == 0);
}
/**
* Tests whether this <code>Area</code> consists entirely of
* straight edged polygonal geometry.
* @return <code>true</code> if the geometry of this
* <code>Area</code> consists entirely of line segments;
* <code>false</code> otherwise.
* @since 1.2
*/
public boolean isPolygonal() {
Enumeration enum_ = curves.elements();
while (enum_.hasMoreElements()) {
if (((Curve) enum_.nextElement()).getOrder() > 1) {
return false;
}
}
return true;
}
/**
* Tests whether this <code>Area</code> is rectangular in shape.
* @return <code>true</code> if the geometry of this
* <code>Area</code> is rectangular in shape; <code>false</code>
* otherwise.
* @since 1.2
*/
public boolean isRectangular() {
int size = curves.size();
if (size == 0) {
return true;
}
if (size > 3) {
return false;
}
Curve c1 = (Curve) curves.get(1);
Curve c2 = (Curve) curves.get(2);
if (c1.getOrder() != 1 || c2.getOrder() != 1) {
return false;
}
if (c1.getXTop() != c1.getXBot() || c2.getXTop() != c2.getXBot()) {
return false;
}
if (c1.getYTop() != c2.getYTop() || c1.getYBot() != c2.getYBot()) {
// One might be able to prove that this is impossible...
return false;
}
return true;
}
/**
* Tests whether this <code>Area</code> is comprised of a single
* closed subpath. This method returns <code>true</code> if the
* path contains 0 or 1 subpaths, or <code>false</code> if the path
* contains more than 1 subpath. The subpaths are counted by the
* number of {@link PathIterator#SEG_MOVETO SEG_MOVETO} segments
* that appear in the path.
* @return <code>true</code> if the <code>Area</code> is comprised
* of a single basic geometry; <code>false</code> otherwise.
* @since 1.2
*/
public boolean isSingular() {
if (curves.size() < 3) {
return true;
}
Enumeration enum_ = curves.elements();
enum_.nextElement(); // First Order0 "moveto"
while (enum_.hasMoreElements()) {
if (((Curve) enum_.nextElement()).getOrder() == 0) {
return false;
}
}
return true;
}
private Rectangle2D cachedBounds;
private void invalidateBounds() {
cachedBounds = null;
}
private Rectangle2D getCachedBounds() {
if (cachedBounds != null) {
return cachedBounds;
}
Rectangle2D r = new Rectangle2D.Double();
if (curves.size() > 0) {
Curve c = (Curve) curves.get(0);
// First point is always an order 0 curve (moveto)
r.setRect(c.getX0(), c.getY0(), 0, 0);
for (int i = 1; i < curves.size(); i++) {
((Curve) curves.get(i)).enlarge(r);
}
}
return (cachedBounds = r);
}
/**
* Returns a high precision bounding {@link Rectangle2D} that
* completely encloses this <code>Area</code>.
* <p>
* The Area class will attempt to return the tightest bounding
* box possible for the Shape. The bounding box will not be
* padded to include the control points of curves in the outline
* of the Shape, but should tightly fit the actual geometry of
* the outline itself.
* @return the bounding <code>Rectangle2D</code> for the
* <code>Area</code>.
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return getCachedBounds().getBounds2D();
}
/**
* Returns a bounding {@link Rectangle} that completely encloses
* this <code>Area</code>.
* <p>
* The Area class will attempt to return the tightest bounding
* box possible for the Shape. The bounding box will not be
* padded to include the control points of curves in the outline
* of the Shape, but should tightly fit the actual geometry of
* the outline itself. Since the returned object represents
* the bounding box with integers, the bounding box can only be
* as tight as the nearest integer coordinates that encompass
* the geometry of the Shape.
* @return the bounding <code>Rectangle</code> for the
* <code>Area</code>.
* @since 1.2
*/
public Rectangle getBounds() {
return getCachedBounds().getBounds();
}
/**
* Returns an exact copy of this <code>Area</code> object.
* @return Created clone object
* @since 1.2
*/
public Object clone() {
return new Area(this);
}
/**
* Tests whether the geometries of the two <code>Area</code> objects
* are equal.
* This method will return false if the argument is null.
* @param other the <code>Area</code> to be compared to this
* <code>Area</code>
* @return <code>true</code> if the two geometries are equal;
* <code>false</code> otherwise.
* @since 1.2
*/
public boolean equals(Area other) {
// REMIND: A *much* simpler operation should be possible...
// Should be able to do a curve-wise comparison since all Areas
// should evaluate their curves in the same top-down order.
if (other == this) {
return true;
}
if (other == null) {
return false;
}
Vector c = new AreaOp.XorOp().calculate(this.curves, other.curves);
return c.isEmpty();
}
/**
* Transforms the geometry of this <code>Area</code> using the specified
* {@link AffineTransform}. The geometry is transformed in place, which
* permanently changes the enclosed area defined by this object.
* @param t the transformation used to transform the area
* @throws NullPointerException if <code>t</code> is null
* @since 1.2
*/
public void transform(AffineTransform t) {
if (t == null) {
throw new NullPointerException("transform must not be null");
}
// REMIND: A simpler operation can be performed for some types
// of transform.
curves = pathToCurves(getPathIterator(t));
invalidateBounds();
}
/**
* Creates a new <code>Area</code> object that contains the same
* geometry as this <code>Area</code> transformed by the specified
* <code>AffineTransform</code>. This <code>Area</code> object
* is unchanged.
* @param t the specified <code>AffineTransform</code> used to transform
* the new <code>Area</code>
* @throws NullPointerException if <code>t</code> is null
* @return a new <code>Area</code> object representing the transformed
* geometry.
* @since 1.2
*/
public Area createTransformedArea(AffineTransform t) {
Area a = new Area(this);
a.transform(t);
return a;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y) {
if (!getCachedBounds().contains(x, y)) {
return false;
}
Enumeration enum_ = curves.elements();
int crossings = 0;
while (enum_.hasMoreElements()) {
Curve c = (Curve) enum_.nextElement();
crossings += c.crossingsFor(x, y);
}
return ((crossings & 1) == 1);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(Point2D p) {
return contains(p.getX(), p.getY());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y, double w, double h) {
if (w < 0 || h < 0) {
return false;
}
if (!getCachedBounds().contains(x, y, w, h)) {
return false;
}
Crossings c = Crossings.findCrossings(curves, x, y, x+w, y+h);
return (c != null && c.covers(y, y+h));
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(Rectangle2D r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean intersects(double x, double y, double w, double h) {
if (w < 0 || h < 0) {
return false;
}
if (!getCachedBounds().intersects(x, y, w, h)) {
return false;
}
Crossings c = Crossings.findCrossings(curves, x, y, x+w, y+h);
return (c == null || !c.isEmpty());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean intersects(Rectangle2D r) {
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* Creates a {@link PathIterator} for the outline of this
* <code>Area</code> object. This <code>Area</code> object is unchanged.
* @param at an optional <code>AffineTransform</code> to be applied to
* the coordinates as they are returned in the iteration, or
* <code>null</code> if untransformed coordinates are desired
* @return the <code>PathIterator</code> object that returns the
* geometry of the outline of this <code>Area</code>, one
* segment at a time.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at) {
return new AreaIterator(curves, at);
}
/**
* Creates a <code>PathIterator</code> for the flattened outline of
* this <code>Area</code> object. Only uncurved path segments
* represented by the SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point
* types are returned by the iterator. This <code>Area</code>
* object is unchanged.
* @param at an optional <code>AffineTransform</code> to be
* applied to the coordinates as they are returned in the
* iteration, or <code>null</code> if untransformed coordinates
* are desired
* @param flatness the maximum amount that the control points
* for a given curve can vary from colinear before a subdivided
* curve is replaced by a straight line connecting the end points
* @return the <code>PathIterator</code> object that returns the
* geometry of the outline of this <code>Area</code>, one segment
* at a time.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return new FlatteningPathIterator(getPathIterator(at), flatness);
}
}
class AreaIterator implements PathIterator {
private AffineTransform transform;
private Vector curves;
private int index;
private Curve prevcurve;
private Curve thiscurve;
public AreaIterator(Vector curves, AffineTransform at) {
this.curves = curves;
this.transform = at;
if (curves.size() >= 1) {
thiscurve = (Curve) curves.get(0);
}
}
public int getWindingRule() {
// REMIND: Which is better, EVEN_ODD or NON_ZERO?
// The paths calculated could be classified either way.
//return WIND_EVEN_ODD;
return WIND_NON_ZERO;
}
public boolean isDone() {
return (prevcurve == null && thiscurve == null);
}
public void next() {
if (prevcurve != null) {
prevcurve = null;
} else {
prevcurve = thiscurve;
index++;
if (index < curves.size()) {
thiscurve = (Curve) curves.get(index);
if (thiscurve.getOrder() != 0 &&
prevcurve.getX1() == thiscurve.getX0() &&
prevcurve.getY1() == thiscurve.getY0())
{
prevcurve = null;
}
} else {
thiscurve = null;
}
}
}
public int currentSegment(float coords[]) {
double dcoords[] = new double[6];
int segtype = currentSegment(dcoords);
int numpoints = (segtype == SEG_CLOSE ? 0
: (segtype == SEG_QUADTO ? 2
: (segtype == SEG_CUBICTO ? 3
: 1)));
for (int i = 0; i < numpoints * 2; i++) {
coords[i] = (float) dcoords[i];
}
return segtype;
}
public int currentSegment(double coords[]) {
int segtype;
int numpoints;
if (prevcurve != null) {
// Need to finish off junction between curves
if (thiscurve == null || thiscurve.getOrder() == 0) {
return SEG_CLOSE;
}
coords[0] = thiscurve.getX0();
coords[1] = thiscurve.getY0();
segtype = SEG_LINETO;
numpoints = 1;
} else if (thiscurve == null) {
throw new NoSuchElementException("area iterator out of bounds");
} else {
segtype = thiscurve.getSegment(coords);
numpoints = thiscurve.getOrder();
if (numpoints == 0) {
numpoints = 1;
}
}
if (transform != null) {
transform.transform(coords, 0, coords, 0, numpoints);
}
return segtype;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of a cubic curve
* segment through the PathIterator interface.
*
* @author Jim Graham
*/
class CubicIterator implements PathIterator {
CubicCurve2D cubic;
AffineTransform affine;
int index;
CubicIterator(CubicCurve2D q, AffineTransform at) {
this.cubic = q;
this.affine = at;
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return (index > 1);
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("cubic iterator iterator out of bounds");
}
int type;
if (index == 0) {
coords[0] = (float) cubic.getX1();
coords[1] = (float) cubic.getY1();
type = SEG_MOVETO;
} else {
coords[0] = (float) cubic.getCtrlX1();
coords[1] = (float) cubic.getCtrlY1();
coords[2] = (float) cubic.getCtrlX2();
coords[3] = (float) cubic.getCtrlY2();
coords[4] = (float) cubic.getX2();
coords[5] = (float) cubic.getY2();
type = SEG_CUBICTO;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 3);
}
return type;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("cubic iterator iterator out of bounds");
}
int type;
if (index == 0) {
coords[0] = cubic.getX1();
coords[1] = cubic.getY1();
type = SEG_MOVETO;
} else {
coords[0] = cubic.getCtrlX1();
coords[1] = cubic.getCtrlY1();
coords[2] = cubic.getCtrlX2();
coords[3] = cubic.getCtrlY2();
coords[4] = cubic.getX2();
coords[5] = cubic.getY2();
type = SEG_CUBICTO;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 3);
}
return type;
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
/**
* The <code>Dimension2D</code> class is to encapsulate a width
* and a height dimension.
* <p>
* This class is only the abstract superclass for all objects that
* store a 2D dimension.
* The actual storage representation of the sizes is left to
* the subclass.
*
* @author Jim Graham
* @since 1.2
*/
public abstract class Dimension2D implements Cloneable {
/**
* This is an abstract class that cannot be instantiated directly.
* Type-specific implementation subclasses are available for
* instantiation and provide a number of formats for storing
* the information necessary to satisfy the various accessor
* methods below.
*
* @see java.awt.Dimension
* @since 1.2
*/
protected Dimension2D() {
}
/**
* Returns the width of this <code>Dimension</code> in double
* precision.
* @return the width of this <code>Dimension</code>.
* @since 1.2
*/
public abstract double getWidth();
/**
* Returns the height of this <code>Dimension</code> in double
* precision.
* @return the height of this <code>Dimension</code>.
* @since 1.2
*/
public abstract double getHeight();
/**
* Sets the size of this <code>Dimension</code> object to the
* specified width and height.
* This method is included for completeness, to parallel the
* {@link java.awt.Component#getSize getSize} method of
* {@link java.awt.Component}.
* @param width the new width for the <code>Dimension</code>
* object
* @param height the new height for the <code>Dimension</code>
* object
* @since 1.2
*/
public abstract void setSize(double width, double height);
/**
* Sets the size of this <code>Dimension2D</code> object to
* match the specified size.
* This method is included for completeness, to parallel the
* <code>getSize</code> method of <code>Component</code>.
* @param d the new size for the <code>Dimension2D</code>
* object
* @since 1.2
*/
public void setSize(Dimension2D d) {
setSize(d.getWidth(), d.getHeight());
}
/**
* Creates a new object of the same class as this object.
*
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
* @since 1.2
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
}

View File

@@ -0,0 +1,464 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.io.Serializable;
/**
* The <code>Ellipse2D</code> class describes an ellipse that is defined
* by a framing rectangle.
* <p>
* This class is only the abstract superclass for all objects which
* store a 2D ellipse.
* The actual storage representation of the coordinates is left to
* the subclass.
*
* @author Jim Graham
* @since 1.2
*/
public abstract class Ellipse2D extends RectangularShape {
/**
* The <code>Float</code> class defines an ellipse specified
* in <code>float</code> precision.
* @since 1.2
*/
public static class Float extends Ellipse2D implements Serializable {
/**
* The X coordinate of the upper-left corner of the
* framing rectangle of this {@code Ellipse2D}.
* @since 1.2
* @serial
*/
public float x;
/**
* The Y coordinate of the upper-left corner of the
* framing rectangle of this {@code Ellipse2D}.
* @since 1.2
* @serial
*/
public float y;
/**
* The overall width of this <code>Ellipse2D</code>.
* @since 1.2
* @serial
*/
public float width;
/**
* The overall height of this <code>Ellipse2D</code>.
* @since 1.2
* @serial
*/
public float height;
/**
* Constructs a new <code>Ellipse2D</code>, initialized to
* location (0,&nbsp;0) and size (0,&nbsp;0).
* @since 1.2
*/
public Float() {
}
/**
* Constructs and initializes an <code>Ellipse2D</code> from the
* specified coordinates.
*
* @param x the X coordinate of the upper-left corner
* of the framing rectangle
* @param y the Y coordinate of the upper-left corner
* of the framing rectangle
* @param w the width of the framing rectangle
* @param h the height of the framing rectangle
* @since 1.2
*/
public Float(float x, float y, float w, float h) {
setFrame(x, y, w, h);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return (double) x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return (double) y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getWidth() {
return (double) width;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getHeight() {
return (double) height;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean isEmpty() {
return (width <= 0.0 || height <= 0.0);
}
/**
* Sets the location and size of the framing rectangle of this
* <code>Shape</code> to the specified rectangular values.
*
* @param x the X coordinate of the upper-left corner of the
* specified rectangular shape
* @param y the Y coordinate of the upper-left corner of the
* specified rectangular shape
* @param w the width of the specified rectangular shape
* @param h the height of the specified rectangular shape
* @since 1.2
*/
public void setFrame(float x, float y, float w, float h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setFrame(double x, double y, double w, double h) {
this.x = (float) x;
this.y = (float) y;
this.width = (float) w;
this.height = (float) h;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return new Rectangle2D.Float(x, y, width, height);
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = -6633761252372475977L;
}
/**
* The <code>Double</code> class defines an ellipse specified
* in <code>double</code> precision.
* @since 1.2
*/
public static class Double extends Ellipse2D implements Serializable {
/**
* The X coordinate of the upper-left corner of the
* framing rectangle of this {@code Ellipse2D}.
* @since 1.2
* @serial
*/
public double x;
/**
* The Y coordinate of the upper-left corner of the
* framing rectangle of this {@code Ellipse2D}.
* @since 1.2
* @serial
*/
public double y;
/**
* The overall width of this <code>Ellipse2D</code>.
* @since 1.2
* @serial
*/
public double width;
/**
* The overall height of the <code>Ellipse2D</code>.
* @since 1.2
* @serial
*/
public double height;
/**
* Constructs a new <code>Ellipse2D</code>, initialized to
* location (0,&nbsp;0) and size (0,&nbsp;0).
* @since 1.2
*/
public Double() {
}
/**
* Constructs and initializes an <code>Ellipse2D</code> from the
* specified coordinates.
*
* @param x the X coordinate of the upper-left corner
* of the framing rectangle
* @param y the Y coordinate of the upper-left corner
* of the framing rectangle
* @param w the width of the framing rectangle
* @param h the height of the framing rectangle
* @since 1.2
*/
public Double(double x, double y, double w, double h) {
setFrame(x, y, w, h);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getWidth() {
return width;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getHeight() {
return height;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean isEmpty() {
return (width <= 0.0 || height <= 0.0);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setFrame(double x, double y, double w, double h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return new Rectangle2D.Double(x, y, width, height);
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = 5555464816372320683L;
}
/**
* This is an abstract class that cannot be instantiated directly.
* Type-specific implementation subclasses are available for
* instantiation and provide a number of formats for storing
* the information necessary to satisfy the various accessor
* methods below.
*
* @see java.awt.geom.Ellipse2D.Float
* @see java.awt.geom.Ellipse2D.Double
* @since 1.2
*/
protected Ellipse2D() {
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y) {
// Normalize the coordinates compared to the ellipse
// having a center at 0,0 and a radius of 0.5.
double ellw = getWidth();
if (ellw <= 0.0) {
return false;
}
double normx = (x - getX()) / ellw - 0.5;
double ellh = getHeight();
if (ellh <= 0.0) {
return false;
}
double normy = (y - getY()) / ellh - 0.5;
return (normx * normx + normy * normy) < 0.25;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean intersects(double x, double y, double w, double h) {
if (w <= 0.0 || h <= 0.0) {
return false;
}
// Normalize the rectangular coordinates compared to the ellipse
// having a center at 0,0 and a radius of 0.5.
double ellw = getWidth();
if (ellw <= 0.0) {
return false;
}
double normx0 = (x - getX()) / ellw - 0.5;
double normx1 = normx0 + w / ellw;
double ellh = getHeight();
if (ellh <= 0.0) {
return false;
}
double normy0 = (y - getY()) / ellh - 0.5;
double normy1 = normy0 + h / ellh;
// find nearest x (left edge, right edge, 0.0)
// find nearest y (top edge, bottom edge, 0.0)
// if nearest x,y is inside circle of radius 0.5, then intersects
double nearx, neary;
if (normx0 > 0.0) {
// center to left of X extents
nearx = normx0;
} else if (normx1 < 0.0) {
// center to right of X extents
nearx = normx1;
} else {
nearx = 0.0;
}
if (normy0 > 0.0) {
// center above Y extents
neary = normy0;
} else if (normy1 < 0.0) {
// center below Y extents
neary = normy1;
} else {
neary = 0.0;
}
return (nearx * nearx + neary * neary) < 0.25;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y, double w, double h) {
return (contains(x, y) &&
contains(x + w, y) &&
contains(x, y + h) &&
contains(x + w, y + h));
}
/**
* Returns an iteration object that defines the boundary of this
* <code>Ellipse2D</code>.
* The iterator for this class is multi-threaded safe, which means
* that this <code>Ellipse2D</code> class guarantees that
* modifications to the geometry of this <code>Ellipse2D</code>
* object do not affect any iterations of that geometry that
* are already in process.
* @param at an optional <code>AffineTransform</code> to be applied to
* the coordinates as they are returned in the iteration, or
* <code>null</code> if untransformed coordinates are desired
* @return the <code>PathIterator</code> object that returns the
* geometry of the outline of this <code>Ellipse2D</code>,
* one segment at a time.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at) {
return new EllipseIterator(this, at);
}
/**
* Returns the hashcode for this <code>Ellipse2D</code>.
* @return the hashcode for this <code>Ellipse2D</code>.
* @since 1.6
*/
public int hashCode() {
long bits = java.lang.Double.doubleToLongBits(getX());
bits += java.lang.Double.doubleToLongBits(getY()) * 37;
bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
return (((int) bits) ^ ((int) (bits >> 32)));
}
/**
* Determines whether or not the specified <code>Object</code> is
* equal to this <code>Ellipse2D</code>. The specified
* <code>Object</code> is equal to this <code>Ellipse2D</code>
* if it is an instance of <code>Ellipse2D</code> and if its
* location and size are the same as this <code>Ellipse2D</code>.
* @param obj an <code>Object</code> to be compared with this
* <code>Ellipse2D</code>.
* @return <code>true</code> if <code>obj</code> is an instance
* of <code>Ellipse2D</code> and has the same values;
* <code>false</code> otherwise.
* @since 1.6
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Ellipse2D) {
Ellipse2D e2d = (Ellipse2D) obj;
return ((getX() == e2d.getX()) &&
(getY() == e2d.getY()) &&
(getWidth() == e2d.getWidth()) &&
(getHeight() == e2d.getHeight()));
}
return false;
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of an ellipse
* through the PathIterator interface.
*
* @author Jim Graham
*/
class EllipseIterator implements PathIterator {
double x, y, w, h;
AffineTransform affine;
int index;
EllipseIterator(Ellipse2D e, AffineTransform at) {
this.x = e.getX();
this.y = e.getY();
this.w = e.getWidth();
this.h = e.getHeight();
this.affine = at;
if (w < 0 || h < 0) {
index = 6;
}
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return index > 5;
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
// ArcIterator.btan(Math.PI/2)
public static final double CtrlVal = 0.5522847498307933;
/*
* ctrlpts contains the control points for a set of 4 cubic
* bezier curves that approximate a circle of radius 0.5
* centered at 0.5, 0.5
*/
private static final double pcv = 0.5 + CtrlVal * 0.5;
private static final double ncv = 0.5 - CtrlVal * 0.5;
private static double ctrlpts[][] = {
{ 1.0, pcv, pcv, 1.0, 0.5, 1.0 },
{ ncv, 1.0, 0.0, pcv, 0.0, 0.5 },
{ 0.0, ncv, ncv, 0.0, 0.5, 0.0 },
{ pcv, 0.0, 1.0, ncv, 1.0, 0.5 }
};
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("ellipse iterator out of bounds");
}
if (index == 5) {
return SEG_CLOSE;
}
if (index == 0) {
double ctrls[] = ctrlpts[3];
coords[0] = (float) (x + ctrls[4] * w);
coords[1] = (float) (y + ctrls[5] * h);
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return SEG_MOVETO;
}
double ctrls[] = ctrlpts[index - 1];
coords[0] = (float) (x + ctrls[0] * w);
coords[1] = (float) (y + ctrls[1] * h);
coords[2] = (float) (x + ctrls[2] * w);
coords[3] = (float) (y + ctrls[3] * h);
coords[4] = (float) (x + ctrls[4] * w);
coords[5] = (float) (y + ctrls[5] * h);
if (affine != null) {
affine.transform(coords, 0, coords, 0, 3);
}
return SEG_CUBICTO;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("ellipse iterator out of bounds");
}
if (index == 5) {
return SEG_CLOSE;
}
if (index == 0) {
double ctrls[] = ctrlpts[3];
coords[0] = x + ctrls[4] * w;
coords[1] = y + ctrls[5] * h;
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return SEG_MOVETO;
}
double ctrls[] = ctrlpts[index - 1];
coords[0] = x + ctrls[0] * w;
coords[1] = y + ctrls[1] * h;
coords[2] = x + ctrls[2] * w;
coords[3] = y + ctrls[3] * h;
coords[4] = x + ctrls[4] * w;
coords[5] = y + ctrls[5] * h;
if (affine != null) {
affine.transform(coords, 0, coords, 0, 3);
}
return SEG_CUBICTO;
}
}

View File

@@ -0,0 +1,395 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* The <code>FlatteningPathIterator</code> class returns a flattened view of
* another {@link PathIterator} object. Other {@link java.awt.Shape Shape}
* classes can use this class to provide flattening behavior for their paths
* without having to perform the interpolation calculations themselves.
*
* @author Jim Graham
*/
public class FlatteningPathIterator implements PathIterator {
static final int GROW_SIZE = 24; // Multiple of cubic & quad curve size
PathIterator src; // The source iterator
double squareflat; // Square of the flatness parameter
// for testing against squared lengths
int limit; // Maximum number of recursion levels
double hold[] = new double[14]; // The cache of interpolated coords
// Note that this must be long enough
// to store a full cubic segment and
// a relative cubic segment to avoid
// aliasing when copying the coords
// of a curve to the end of the array.
// This is also serendipitously equal
// to the size of a full quad segment
// and 2 relative quad segments.
double curx, cury; // The ending x,y of the last segment
double movx, movy; // The x,y of the last move segment
int holdType; // The type of the curve being held
// for interpolation
int holdEnd; // The index of the last curve segment
// being held for interpolation
int holdIndex; // The index of the curve segment
// that was last interpolated. This
// is the curve segment ready to be
// returned in the next call to
// currentSegment().
int levels[]; // The recursion level at which
// each curve being held in storage
// was generated.
int levelIndex; // The index of the entry in the
// levels array of the curve segment
// at the holdIndex
boolean done; // True when iteration is done
/**
* Constructs a new <code>FlatteningPathIterator</code> object that
* flattens a path as it iterates over it. The iterator does not
* subdivide any curve read from the source iterator to more than
* 10 levels of subdivision which yields a maximum of 1024 line
* segments per curve.
* @param src the original unflattened path being iterated over
* @param flatness the maximum allowable distance between the
* control points and the flattened curve
*/
public FlatteningPathIterator(PathIterator src, double flatness) {
this(src, flatness, 10);
}
/**
* Constructs a new <code>FlatteningPathIterator</code> object
* that flattens a path as it iterates over it.
* The <code>limit</code> parameter allows you to control the
* maximum number of recursive subdivisions that the iterator
* can make before it assumes that the curve is flat enough
* without measuring against the <code>flatness</code> parameter.
* The flattened iteration therefore never generates more than
* a maximum of <code>(2^limit)</code> line segments per curve.
* @param src the original unflattened path being iterated over
* @param flatness the maximum allowable distance between the
* control points and the flattened curve
* @param limit the maximum number of recursive subdivisions
* allowed for any curved segment
* @exception IllegalArgumentException if
* <code>flatness</code> or <code>limit</code>
* is less than zero
*/
public FlatteningPathIterator(PathIterator src, double flatness,
int limit) {
if (flatness < 0.0) {
throw new IllegalArgumentException("flatness must be >= 0");
}
if (limit < 0) {
throw new IllegalArgumentException("limit must be >= 0");
}
this.src = src;
this.squareflat = flatness * flatness;
this.limit = limit;
this.levels = new int[limit + 1];
// prime the first path segment
next(false);
}
/**
* Returns the flatness of this iterator.
* @return the flatness of this <code>FlatteningPathIterator</code>.
*/
public double getFlatness() {
return Math.sqrt(squareflat);
}
/**
* Returns the recursion limit of this iterator.
* @return the recursion limit of this
* <code>FlatteningPathIterator</code>.
*/
public int getRecursionLimit() {
return limit;
}
/**
* Returns the winding rule for determining the interior of the
* path.
* @return the winding rule of the original unflattened path being
* iterated over.
* @see PathIterator#WIND_EVEN_ODD
* @see PathIterator#WIND_NON_ZERO
*/
public int getWindingRule() {
return src.getWindingRule();
}
/**
* Tests if the iteration is complete.
* @return <code>true</code> if all the segments have
* been read; <code>false</code> otherwise.
*/
public boolean isDone() {
return done;
}
/*
* Ensures that the hold array can hold up to (want) more values.
* It is currently holding (hold.length - holdIndex) values.
*/
void ensureHoldCapacity(int want) {
if (holdIndex - want < 0) {
int have = hold.length - holdIndex;
int newsize = hold.length + GROW_SIZE;
double newhold[] = new double[newsize];
System.arraycopy(hold, holdIndex,
newhold, holdIndex + GROW_SIZE,
have);
hold = newhold;
holdIndex += GROW_SIZE;
holdEnd += GROW_SIZE;
}
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
next(true);
}
private void next(boolean doNext) {
int level;
if (holdIndex >= holdEnd) {
if (doNext) {
src.next();
}
if (src.isDone()) {
done = true;
return;
}
holdType = src.currentSegment(hold);
levelIndex = 0;
levels[0] = 0;
}
switch (holdType) {
case SEG_MOVETO:
case SEG_LINETO:
curx = hold[0];
cury = hold[1];
if (holdType == SEG_MOVETO) {
movx = curx;
movy = cury;
}
holdIndex = 0;
holdEnd = 0;
break;
case SEG_CLOSE:
curx = movx;
cury = movy;
holdIndex = 0;
holdEnd = 0;
break;
case SEG_QUADTO:
if (holdIndex >= holdEnd) {
// Move the coordinates to the end of the array.
holdIndex = hold.length - 6;
holdEnd = hold.length - 2;
hold[holdIndex + 0] = curx;
hold[holdIndex + 1] = cury;
hold[holdIndex + 2] = hold[0];
hold[holdIndex + 3] = hold[1];
hold[holdIndex + 4] = curx = hold[2];
hold[holdIndex + 5] = cury = hold[3];
}
level = levels[levelIndex];
while (level < limit) {
if (QuadCurve2D.getFlatnessSq(hold, holdIndex) < squareflat) {
break;
}
ensureHoldCapacity(4);
QuadCurve2D.subdivide(hold, holdIndex,
hold, holdIndex - 4,
hold, holdIndex);
holdIndex -= 4;
// Now that we have subdivided, we have constructed
// two curves of one depth lower than the original
// curve. One of those curves is in the place of
// the former curve and one of them is in the next
// set of held coordinate slots. We now set both
// curves level values to the next higher level.
level++;
levels[levelIndex] = level;
levelIndex++;
levels[levelIndex] = level;
}
// This curve segment is flat enough, or it is too deep
// in recursion levels to try to flatten any more. The
// two coordinates at holdIndex+4 and holdIndex+5 now
// contain the endpoint of the curve which can be the
// endpoint of an approximating line segment.
holdIndex += 4;
levelIndex--;
break;
case SEG_CUBICTO:
if (holdIndex >= holdEnd) {
// Move the coordinates to the end of the array.
holdIndex = hold.length - 8;
holdEnd = hold.length - 2;
hold[holdIndex + 0] = curx;
hold[holdIndex + 1] = cury;
hold[holdIndex + 2] = hold[0];
hold[holdIndex + 3] = hold[1];
hold[holdIndex + 4] = hold[2];
hold[holdIndex + 5] = hold[3];
hold[holdIndex + 6] = curx = hold[4];
hold[holdIndex + 7] = cury = hold[5];
}
level = levels[levelIndex];
while (level < limit) {
if (CubicCurve2D.getFlatnessSq(hold, holdIndex) < squareflat) {
break;
}
ensureHoldCapacity(6);
CubicCurve2D.subdivide(hold, holdIndex,
hold, holdIndex - 6,
hold, holdIndex);
holdIndex -= 6;
// Now that we have subdivided, we have constructed
// two curves of one depth lower than the original
// curve. One of those curves is in the place of
// the former curve and one of them is in the next
// set of held coordinate slots. We now set both
// curves level values to the next higher level.
level++;
levels[levelIndex] = level;
levelIndex++;
levels[levelIndex] = level;
}
// This curve segment is flat enough, or it is too deep
// in recursion levels to try to flatten any more. The
// two coordinates at holdIndex+6 and holdIndex+7 now
// contain the endpoint of the curve which can be the
// endpoint of an approximating line segment.
holdIndex += 6;
levelIndex--;
break;
}
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
* A float array of length 6 must be passed in and can be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types return one point,
* and SEG_CLOSE does not return any points.
* @param coords an array that holds the data returned from
* this method
* @return the path segment type of the current path segment.
* @exception NoSuchElementException if there
* are no more elements in the flattening path to be
* returned.
* @see PathIterator#SEG_MOVETO
* @see PathIterator#SEG_LINETO
* @see PathIterator#SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("flattening iterator out of bounds");
}
int type = holdType;
if (type != SEG_CLOSE) {
coords[0] = (float) hold[holdIndex + 0];
coords[1] = (float) hold[holdIndex + 1];
if (type != SEG_MOVETO) {
type = SEG_LINETO;
}
}
return type;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
* A double array of length 6 must be passed in and can be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types return one point,
* and SEG_CLOSE does not return any points.
* @param coords an array that holds the data returned from
* this method
* @return the path segment type of the current path segment.
* @exception NoSuchElementException if there
* are no more elements in the flattening path to be
* returned.
* @see PathIterator#SEG_MOVETO
* @see PathIterator#SEG_LINETO
* @see PathIterator#SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("flattening iterator out of bounds");
}
int type = holdType;
if (type != SEG_CLOSE) {
coords[0] = hold[holdIndex + 0];
coords[1] = hold[holdIndex + 1];
if (type != SEG_MOVETO) {
type = SEG_LINETO;
}
}
return type;
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.awt.Shape;
/**
* The {@code GeneralPath} class represents a geometric path
* constructed from straight lines, and quadratic and cubic
* (B&eacute;zier) curves. It can contain multiple subpaths.
* <p>
* {@code GeneralPath} is a legacy final class which exactly
* implements the behavior of its superclass {@link Path2D.Float}.
* Together with {@link Path2D.Double}, the {@link Path2D} classes
* provide full implementations of a general geometric path that
* support all of the functionality of the {@link Shape} and
* {@link PathIterator} interfaces with the ability to explicitly
* select different levels of internal coordinate precision.
* <p>
* Use {@code Path2D.Float} (or this legacy {@code GeneralPath}
* subclass) when dealing with data that can be represented
* and used with floating point precision. Use {@code Path2D.Double}
* for data that requires the accuracy or range of double precision.
*
* @author Jim Graham
* @since 1.2
*/
public final class GeneralPath extends Path2D.Float {
/**
* Constructs a new empty single precision {@code GeneralPath} object
* with a default winding rule of {@link #WIND_NON_ZERO}.
*
* @since 1.2
*/
public GeneralPath() {
super(WIND_NON_ZERO, INIT_SIZE);
}
/**
* Constructs a new <code>GeneralPath</code> object with the specified
* winding rule to control operations that require the interior of the
* path to be defined.
*
* @param rule the winding rule
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
* @since 1.2
*/
public GeneralPath(int rule) {
super(rule, INIT_SIZE);
}
/**
* Constructs a new <code>GeneralPath</code> object with the specified
* winding rule and the specified initial capacity to store path
* coordinates.
* This number is an initial guess as to how many path segments
* will be added to the path, but the storage is expanded as
* needed to store whatever path segments are added.
*
* @param rule the winding rule
* @param initialCapacity the estimate for the number of path segments
* in the path
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
* @since 1.2
*/
public GeneralPath(int rule, int initialCapacity) {
super(rule, initialCapacity);
}
/**
* Constructs a new <code>GeneralPath</code> object from an arbitrary
* {@link Shape} object.
* All of the initial geometry and the winding rule for this path are
* taken from the specified <code>Shape</code> object.
*
* @param s the specified <code>Shape</code> object
* @since 1.2
*/
public GeneralPath(Shape s) {
super(s, null);
}
GeneralPath(int windingRule,
byte[] pointTypes,
int numTypes,
float[] pointCoords,
int numCoords)
{
// used to construct from native
this.windingRule = windingRule;
this.pointTypes = pointTypes;
this.numTypes = numTypes;
this.floatCoords = pointCoords;
this.numCoords = numCoords;
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = -8327096662768731142L;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
/**
* The <code>IllegalPathStateException</code> represents an
* exception that is thrown if an operation is performed on a path
* that is in an illegal state with respect to the particular
* operation being performed, such as appending a path segment
* to a {@link GeneralPath} without an initial moveto.
*
*/
public class IllegalPathStateException extends RuntimeException {
/**
* Constructs an <code>IllegalPathStateException</code> with no
* detail message.
*
* @since 1.2
*/
public IllegalPathStateException() {
}
/**
* Constructs an <code>IllegalPathStateException</code> with the
* specified detail message.
* @param s the detail message
* @since 1.2
*/
public IllegalPathStateException(String s) {
super (s);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of a line segment
* through the PathIterator interface.
*
* @author Jim Graham
*/
class LineIterator implements PathIterator {
Line2D line;
AffineTransform affine;
int index;
LineIterator(Line2D l, AffineTransform at) {
this.line = l;
this.affine = at;
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return (index > 1);
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("line iterator out of bounds");
}
int type;
if (index == 0) {
coords[0] = (float) line.getX1();
coords[1] = (float) line.getY1();
type = SEG_MOVETO;
} else {
coords[0] = (float) line.getX2();
coords[1] = (float) line.getY2();
type = SEG_LINETO;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return type;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("line iterator out of bounds");
}
int type;
if (index == 0) {
coords[0] = line.getX1();
coords[1] = line.getY1();
type = SEG_MOVETO;
} else {
coords[0] = line.getX2();
coords[1] = line.getY2();
type = SEG_LINETO;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return type;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
/**
* The <code>NoninvertibleTransformException</code> class represents
* an exception that is thrown if an operation is performed requiring
* the inverse of an {@link AffineTransform} object but the
* <code>AffineTransform</code> is in a non-invertible state.
*/
public class NoninvertibleTransformException extends java.lang.Exception {
/**
* Constructs an instance of
* <code>NoninvertibleTransformException</code>
* with the specified detail message.
* @param s the detail message
* @since 1.2
*/
public NoninvertibleTransformException(String s) {
super (s);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.lang.annotation.Native;
/**
* The <code>PathIterator</code> interface provides the mechanism
* for objects that implement the {@link java.awt.Shape Shape}
* interface to return the geometry of their boundary by allowing
* a caller to retrieve the path of that boundary a segment at a
* time. This interface allows these objects to retrieve the path of
* their boundary a segment at a time by using 1st through 3rd order
* B&eacute;zier curves, which are lines and quadratic or cubic
* B&eacute;zier splines.
* <p>
* Multiple subpaths can be expressed by using a "MOVETO" segment to
* create a discontinuity in the geometry to move from the end of
* one subpath to the beginning of the next.
* <p>
* Each subpath can be closed manually by ending the last segment in
* the subpath on the same coordinate as the beginning "MOVETO" segment
* for that subpath or by using a "CLOSE" segment to append a line
* segment from the last point back to the first.
* Be aware that manually closing an outline as opposed to using a
* "CLOSE" segment to close the path might result in different line
* style decorations being used at the end points of the subpath.
* For example, the {@link java.awt.BasicStroke BasicStroke} object
* uses a line "JOIN" decoration to connect the first and last points
* if a "CLOSE" segment is encountered, whereas simply ending the path
* on the same coordinate as the beginning coordinate results in line
* "CAP" decorations being used at the ends.
*
* @see java.awt.Shape
* @see java.awt.BasicStroke
*
* @author Jim Graham
*/
public interface PathIterator {
/**
* The winding rule constant for specifying an even-odd rule
* for determining the interior of a path.
* The even-odd rule specifies that a point lies inside the
* path if a ray drawn in any direction from that point to
* infinity is crossed by path segments an odd number of times.
*/
@Native public static final int WIND_EVEN_ODD = 0;
/**
* The winding rule constant for specifying a non-zero rule
* for determining the interior of a path.
* The non-zero rule specifies that a point lies inside the
* path if a ray drawn in any direction from that point to
* infinity is crossed by path segments a different number
* of times in the counter-clockwise direction than the
* clockwise direction.
*/
@Native public static final int WIND_NON_ZERO = 1;
/**
* The segment type constant for a point that specifies the
* starting location for a new subpath.
*/
@Native public static final int SEG_MOVETO = 0;
/**
* The segment type constant for a point that specifies the
* end point of a line to be drawn from the most recently
* specified point.
*/
@Native public static final int SEG_LINETO = 1;
/**
* The segment type constant for the pair of points that specify
* a quadratic parametric curve to be drawn from the most recently
* specified point.
* The curve is interpolated by solving the parametric control
* equation in the range <code>(t=[0..1])</code> using
* the most recently specified (current) point (CP),
* the first control point (P1),
* and the final interpolated control point (P2).
* The parametric control equation for this curve is:
* <pre>
* P(t) = B(2,0)*CP + B(2,1)*P1 + B(2,2)*P2
* 0 &lt;= t &lt;= 1
*
* B(n,m) = mth coefficient of nth degree Bernstein polynomial
* = C(n,m) * t^(m) * (1 - t)^(n-m)
* C(n,m) = Combinations of n things, taken m at a time
* = n! / (m! * (n-m)!)
* </pre>
*/
@Native public static final int SEG_QUADTO = 2;
/**
* The segment type constant for the set of 3 points that specify
* a cubic parametric curve to be drawn from the most recently
* specified point.
* The curve is interpolated by solving the parametric control
* equation in the range <code>(t=[0..1])</code> using
* the most recently specified (current) point (CP),
* the first control point (P1),
* the second control point (P2),
* and the final interpolated control point (P3).
* The parametric control equation for this curve is:
* <pre>
* P(t) = B(3,0)*CP + B(3,1)*P1 + B(3,2)*P2 + B(3,3)*P3
* 0 &lt;= t &lt;= 1
*
* B(n,m) = mth coefficient of nth degree Bernstein polynomial
* = C(n,m) * t^(m) * (1 - t)^(n-m)
* C(n,m) = Combinations of n things, taken m at a time
* = n! / (m! * (n-m)!)
* </pre>
* This form of curve is commonly known as a B&eacute;zier curve.
*/
@Native public static final int SEG_CUBICTO = 3;
/**
* The segment type constant that specifies that
* the preceding subpath should be closed by appending a line segment
* back to the point corresponding to the most recent SEG_MOVETO.
*/
@Native public static final int SEG_CLOSE = 4;
/**
* Returns the winding rule for determining the interior of the
* path.
* @return the winding rule.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule();
/**
* Tests if the iteration is complete.
* @return <code>true</code> if all the segments have
* been read; <code>false</code> otherwise.
*/
public boolean isDone();
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next();
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path-segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and can be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types returns one point,
* SEG_QUADTO returns two points,
* SEG_CUBICTO returns 3 points
* and SEG_CLOSE does not return any points.
* @param coords an array that holds the data returned from
* this method
* @return the path-segment type of the current path segment.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords);
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path-segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and can be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types returns one point,
* SEG_QUADTO returns two points,
* SEG_CUBICTO returns 3 points
* and SEG_CLOSE does not return any points.
* @param coords an array that holds the data returned from
* this method
* @return the path-segment type of the current path segment.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords);
}

View File

@@ -0,0 +1,428 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.io.Serializable;
/**
* The <code>Point2D</code> class defines a point representing a location
* in {@code (x,y)} coordinate space.
* <p>
* This class is only the abstract superclass for all objects that
* store a 2D coordinate.
* The actual storage representation of the coordinates is left to
* the subclass.
*
* @author Jim Graham
* @since 1.2
*/
public abstract class Point2D implements Cloneable {
/**
* The <code>Float</code> class defines a point specified in float
* precision.
* @since 1.2
*/
public static class Float extends Point2D implements Serializable {
/**
* The X coordinate of this <code>Point2D</code>.
* @since 1.2
* @serial
*/
public float x;
/**
* The Y coordinate of this <code>Point2D</code>.
* @since 1.2
* @serial
*/
public float y;
/**
* Constructs and initializes a <code>Point2D</code> with
* coordinates (0,&nbsp;0).
* @since 1.2
*/
public Float() {
}
/**
* Constructs and initializes a <code>Point2D</code> with
* the specified coordinates.
*
* @param x the X coordinate of the newly
* constructed <code>Point2D</code>
* @param y the Y coordinate of the newly
* constructed <code>Point2D</code>
* @since 1.2
*/
public Float(float x, float y) {
this.x = x;
this.y = y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return (double) x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return (double) y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setLocation(double x, double y) {
this.x = (float) x;
this.y = (float) y;
}
/**
* Sets the location of this <code>Point2D</code> to the
* specified <code>float</code> coordinates.
*
* @param x the new X coordinate of this {@code Point2D}
* @param y the new Y coordinate of this {@code Point2D}
* @since 1.2
*/
public void setLocation(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Returns a <code>String</code> that represents the value
* of this <code>Point2D</code>.
* @return a string representation of this <code>Point2D</code>.
* @since 1.2
*/
public String toString() {
return "Point2D.Float["+x+", "+y+"]";
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = -2870572449815403710L;
}
/**
* The <code>Double</code> class defines a point specified in
* <code>double</code> precision.
* @since 1.2
*/
public static class Double extends Point2D implements Serializable {
/**
* The X coordinate of this <code>Point2D</code>.
* @since 1.2
* @serial
*/
public double x;
/**
* The Y coordinate of this <code>Point2D</code>.
* @since 1.2
* @serial
*/
public double y;
/**
* Constructs and initializes a <code>Point2D</code> with
* coordinates (0,&nbsp;0).
* @since 1.2
*/
public Double() {
}
/**
* Constructs and initializes a <code>Point2D</code> with the
* specified coordinates.
*
* @param x the X coordinate of the newly
* constructed <code>Point2D</code>
* @param y the Y coordinate of the newly
* constructed <code>Point2D</code>
* @since 1.2
*/
public Double(double x, double y) {
this.x = x;
this.y = y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setLocation(double x, double y) {
this.x = x;
this.y = y;
}
/**
* Returns a <code>String</code> that represents the value
* of this <code>Point2D</code>.
* @return a string representation of this <code>Point2D</code>.
* @since 1.2
*/
public String toString() {
return "Point2D.Double["+x+", "+y+"]";
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = 6150783262733311327L;
}
/**
* This is an abstract class that cannot be instantiated directly.
* Type-specific implementation subclasses are available for
* instantiation and provide a number of formats for storing
* the information necessary to satisfy the various accessor
* methods below.
*
* @see java.awt.geom.Point2D.Float
* @see java.awt.geom.Point2D.Double
* @see java.awt.Point
* @since 1.2
*/
protected Point2D() {
}
/**
* Returns the X coordinate of this <code>Point2D</code> in
* <code>double</code> precision.
* @return the X coordinate of this <code>Point2D</code>.
* @since 1.2
*/
public abstract double getX();
/**
* Returns the Y coordinate of this <code>Point2D</code> in
* <code>double</code> precision.
* @return the Y coordinate of this <code>Point2D</code>.
* @since 1.2
*/
public abstract double getY();
/**
* Sets the location of this <code>Point2D</code> to the
* specified <code>double</code> coordinates.
*
* @param x the new X coordinate of this {@code Point2D}
* @param y the new Y coordinate of this {@code Point2D}
* @since 1.2
*/
public abstract void setLocation(double x, double y);
/**
* Sets the location of this <code>Point2D</code> to the same
* coordinates as the specified <code>Point2D</code> object.
* @param p the specified <code>Point2D</code> to which to set
* this <code>Point2D</code>
* @since 1.2
*/
public void setLocation(Point2D p) {
setLocation(p.getX(), p.getY());
}
/**
* Returns the square of the distance between two points.
*
* @param x1 the X coordinate of the first specified point
* @param y1 the Y coordinate of the first specified point
* @param x2 the X coordinate of the second specified point
* @param y2 the Y coordinate of the second specified point
* @return the square of the distance between the two
* sets of specified coordinates.
* @since 1.2
*/
public static double distanceSq(double x1, double y1,
double x2, double y2)
{
x1 -= x2;
y1 -= y2;
return (x1 * x1 + y1 * y1);
}
/**
* Returns the distance between two points.
*
* @param x1 the X coordinate of the first specified point
* @param y1 the Y coordinate of the first specified point
* @param x2 the X coordinate of the second specified point
* @param y2 the Y coordinate of the second specified point
* @return the distance between the two sets of specified
* coordinates.
* @since 1.2
*/
public static double distance(double x1, double y1,
double x2, double y2)
{
x1 -= x2;
y1 -= y2;
return Math.sqrt(x1 * x1 + y1 * y1);
}
/**
* Returns the square of the distance from this
* <code>Point2D</code> to a specified point.
*
* @param px the X coordinate of the specified point to be measured
* against this <code>Point2D</code>
* @param py the Y coordinate of the specified point to be measured
* against this <code>Point2D</code>
* @return the square of the distance between this
* <code>Point2D</code> and the specified point.
* @since 1.2
*/
public double distanceSq(double px, double py) {
px -= getX();
py -= getY();
return (px * px + py * py);
}
/**
* Returns the square of the distance from this
* <code>Point2D</code> to a specified <code>Point2D</code>.
*
* @param pt the specified point to be measured
* against this <code>Point2D</code>
* @return the square of the distance between this
* <code>Point2D</code> to a specified <code>Point2D</code>.
* @since 1.2
*/
public double distanceSq(Point2D pt) {
double px = pt.getX() - this.getX();
double py = pt.getY() - this.getY();
return (px * px + py * py);
}
/**
* Returns the distance from this <code>Point2D</code> to
* a specified point.
*
* @param px the X coordinate of the specified point to be measured
* against this <code>Point2D</code>
* @param py the Y coordinate of the specified point to be measured
* against this <code>Point2D</code>
* @return the distance between this <code>Point2D</code>
* and a specified point.
* @since 1.2
*/
public double distance(double px, double py) {
px -= getX();
py -= getY();
return Math.sqrt(px * px + py * py);
}
/**
* Returns the distance from this <code>Point2D</code> to a
* specified <code>Point2D</code>.
*
* @param pt the specified point to be measured
* against this <code>Point2D</code>
* @return the distance between this <code>Point2D</code> and
* the specified <code>Point2D</code>.
* @since 1.2
*/
public double distance(Point2D pt) {
double px = pt.getX() - this.getX();
double py = pt.getY() - this.getY();
return Math.sqrt(px * px + py * py);
}
/**
* Creates a new object of the same class and with the
* same contents as this object.
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
* @since 1.2
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
/**
* Returns the hashcode for this <code>Point2D</code>.
* @return a hash code for this <code>Point2D</code>.
*/
public int hashCode() {
long bits = java.lang.Double.doubleToLongBits(getX());
bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
return (((int) bits) ^ ((int) (bits >> 32)));
}
/**
* Determines whether or not two points are equal. Two instances of
* <code>Point2D</code> are equal if the values of their
* <code>x</code> and <code>y</code> member fields, representing
* their position in the coordinate space, are the same.
* @param obj an object to be compared with this <code>Point2D</code>
* @return <code>true</code> if the object to be compared is
* an instance of <code>Point2D</code> and has
* the same values; <code>false</code> otherwise.
* @since 1.2
*/
public boolean equals(Object obj) {
if (obj instanceof Point2D) {
Point2D p2d = (Point2D) obj;
return (getX() == p2d.getX()) && (getY() == p2d.getY());
}
return super.equals(obj);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of a quadratic curve
* segment through the PathIterator interface.
*
* @author Jim Graham
*/
class QuadIterator implements PathIterator {
QuadCurve2D quad;
AffineTransform affine;
int index;
QuadIterator(QuadCurve2D q, AffineTransform at) {
this.quad = q;
this.affine = at;
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return (index > 1);
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("quad iterator iterator out of bounds");
}
int type;
if (index == 0) {
coords[0] = (float) quad.getX1();
coords[1] = (float) quad.getY1();
type = SEG_MOVETO;
} else {
coords[0] = (float) quad.getCtrlX();
coords[1] = (float) quad.getCtrlY();
coords[2] = (float) quad.getX2();
coords[3] = (float) quad.getY2();
type = SEG_QUADTO;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 2);
}
return type;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("quad iterator iterator out of bounds");
}
int type;
if (index == 0) {
coords[0] = quad.getX1();
coords[1] = quad.getY1();
type = SEG_MOVETO;
} else {
coords[0] = quad.getCtrlX();
coords[1] = quad.getCtrlY();
coords[2] = quad.getX2();
coords[3] = quad.getY2();
type = SEG_QUADTO;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, index == 0 ? 1 : 2);
}
return type;
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of a rectangle
* through the PathIterator interface.
*
* @author Jim Graham
*/
class RectIterator implements PathIterator {
double x, y, w, h;
AffineTransform affine;
int index;
RectIterator(Rectangle2D r, AffineTransform at) {
this.x = r.getX();
this.y = r.getY();
this.w = r.getWidth();
this.h = r.getHeight();
this.affine = at;
if (w < 0 || h < 0) {
index = 6;
}
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return index > 5;
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("rect iterator out of bounds");
}
if (index == 5) {
return SEG_CLOSE;
}
coords[0] = (float) x;
coords[1] = (float) y;
if (index == 1 || index == 2) {
coords[0] += (float) w;
}
if (index == 2 || index == 3) {
coords[1] += (float) h;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return (index == 0 ? SEG_MOVETO : SEG_LINETO);
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("rect iterator out of bounds");
}
if (index == 5) {
return SEG_CLOSE;
}
coords[0] = x;
coords[1] = y;
if (index == 1 || index == 2) {
coords[0] += w;
}
if (index == 2 || index == 3) {
coords[1] += h;
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return (index == 0 ? SEG_MOVETO : SEG_LINETO);
}
}

View File

@@ -0,0 +1,930 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.io.Serializable;
/**
* The <code>Rectangle2D</code> class describes a rectangle
* defined by a location {@code (x,y)} and dimension
* {@code (w x h)}.
* <p>
* This class is only the abstract superclass for all objects that
* store a 2D rectangle.
* The actual storage representation of the coordinates is left to
* the subclass.
*
* @author Jim Graham
* @since 1.2
*/
public abstract class Rectangle2D extends RectangularShape {
/**
* The bitmask that indicates that a point lies to the left of
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_LEFT = 1;
/**
* The bitmask that indicates that a point lies above
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_TOP = 2;
/**
* The bitmask that indicates that a point lies to the right of
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_RIGHT = 4;
/**
* The bitmask that indicates that a point lies below
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_BOTTOM = 8;
/**
* The <code>Float</code> class defines a rectangle specified in float
* coordinates.
* @since 1.2
*/
public static class Float extends Rectangle2D implements Serializable {
/**
* The X coordinate of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public float x;
/**
* The Y coordinate of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public float y;
/**
* The width of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public float width;
/**
* The height of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public float height;
/**
* Constructs a new <code>Rectangle2D</code>, initialized to
* location (0.0,&nbsp;0.0) and size (0.0,&nbsp;0.0).
* @since 1.2
*/
public Float() {
}
/**
* Constructs and initializes a <code>Rectangle2D</code>
* from the specified <code>float</code> coordinates.
*
* @param x the X coordinate of the upper-left corner
* of the newly constructed <code>Rectangle2D</code>
* @param y the Y coordinate of the upper-left corner
* of the newly constructed <code>Rectangle2D</code>
* @param w the width of the newly constructed
* <code>Rectangle2D</code>
* @param h the height of the newly constructed
* <code>Rectangle2D</code>
* @since 1.2
*/
public Float(float x, float y, float w, float h) {
setRect(x, y, w, h);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return (double) x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return (double) y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getWidth() {
return (double) width;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getHeight() {
return (double) height;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean isEmpty() {
return (width <= 0.0f) || (height <= 0.0f);
}
/**
* Sets the location and size of this <code>Rectangle2D</code>
* to the specified <code>float</code> values.
*
* @param x the X coordinate of the upper-left corner
* of this <code>Rectangle2D</code>
* @param y the Y coordinate of the upper-left corner
* of this <code>Rectangle2D</code>
* @param w the width of this <code>Rectangle2D</code>
* @param h the height of this <code>Rectangle2D</code>
* @since 1.2
*/
public void setRect(float x, float y, float w, float h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRect(double x, double y, double w, double h) {
this.x = (float) x;
this.y = (float) y;
this.width = (float) w;
this.height = (float) h;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRect(Rectangle2D r) {
this.x = (float) r.getX();
this.y = (float) r.getY();
this.width = (float) r.getWidth();
this.height = (float) r.getHeight();
}
/**
* {@inheritDoc}
* @since 1.2
*/
public int outcode(double x, double y) {
/*
* Note on casts to double below. If the arithmetic of
* x+w or y+h is done in float, then some bits may be
* lost if the binary exponents of x/y and w/h are not
* similar. By converting to double before the addition
* we force the addition to be carried out in double to
* avoid rounding error in the comparison.
*
* See bug 4320890 for problems that this inaccuracy causes.
*/
int out = 0;
if (this.width <= 0) {
out |= OUT_LEFT | OUT_RIGHT;
} else if (x < this.x) {
out |= OUT_LEFT;
} else if (x > this.x + (double) this.width) {
out |= OUT_RIGHT;
}
if (this.height <= 0) {
out |= OUT_TOP | OUT_BOTTOM;
} else if (y < this.y) {
out |= OUT_TOP;
} else if (y > this.y + (double) this.height) {
out |= OUT_BOTTOM;
}
return out;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return new Float(x, y, width, height);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D createIntersection(Rectangle2D r) {
Rectangle2D dest;
if (r instanceof Float) {
dest = new Rectangle2D.Float();
} else {
dest = new Rectangle2D.Double();
}
Rectangle2D.intersect(this, r, dest);
return dest;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D createUnion(Rectangle2D r) {
Rectangle2D dest;
if (r instanceof Float) {
dest = new Rectangle2D.Float();
} else {
dest = new Rectangle2D.Double();
}
Rectangle2D.union(this, r, dest);
return dest;
}
/**
* Returns the <code>String</code> representation of this
* <code>Rectangle2D</code>.
* @return a <code>String</code> representing this
* <code>Rectangle2D</code>.
* @since 1.2
*/
public String toString() {
return getClass().getName()
+ "[x=" + x +
",y=" + y +
",w=" + width +
",h=" + height + "]";
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = 3798716824173675777L;
}
/**
* The <code>Double</code> class defines a rectangle specified in
* double coordinates.
* @since 1.2
*/
public static class Double extends Rectangle2D implements Serializable {
/**
* The X coordinate of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public double x;
/**
* The Y coordinate of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public double y;
/**
* The width of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public double width;
/**
* The height of this <code>Rectangle2D</code>.
* @since 1.2
* @serial
*/
public double height;
/**
* Constructs a new <code>Rectangle2D</code>, initialized to
* location (0,&nbsp;0) and size (0,&nbsp;0).
* @since 1.2
*/
public Double() {
}
/**
* Constructs and initializes a <code>Rectangle2D</code>
* from the specified <code>double</code> coordinates.
*
* @param x the X coordinate of the upper-left corner
* of the newly constructed <code>Rectangle2D</code>
* @param y the Y coordinate of the upper-left corner
* of the newly constructed <code>Rectangle2D</code>
* @param w the width of the newly constructed
* <code>Rectangle2D</code>
* @param h the height of the newly constructed
* <code>Rectangle2D</code>
* @since 1.2
*/
public Double(double x, double y, double w, double h) {
setRect(x, y, w, h);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getWidth() {
return width;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getHeight() {
return height;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean isEmpty() {
return (width <= 0.0) || (height <= 0.0);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRect(double x, double y, double w, double h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRect(Rectangle2D r) {
this.x = r.getX();
this.y = r.getY();
this.width = r.getWidth();
this.height = r.getHeight();
}
/**
* {@inheritDoc}
* @since 1.2
*/
public int outcode(double x, double y) {
int out = 0;
if (this.width <= 0) {
out |= OUT_LEFT | OUT_RIGHT;
} else if (x < this.x) {
out |= OUT_LEFT;
} else if (x > this.x + this.width) {
out |= OUT_RIGHT;
}
if (this.height <= 0) {
out |= OUT_TOP | OUT_BOTTOM;
} else if (y < this.y) {
out |= OUT_TOP;
} else if (y > this.y + this.height) {
out |= OUT_BOTTOM;
}
return out;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return new Double(x, y, width, height);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D createIntersection(Rectangle2D r) {
Rectangle2D dest = new Rectangle2D.Double();
Rectangle2D.intersect(this, r, dest);
return dest;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D createUnion(Rectangle2D r) {
Rectangle2D dest = new Rectangle2D.Double();
Rectangle2D.union(this, r, dest);
return dest;
}
/**
* Returns the <code>String</code> representation of this
* <code>Rectangle2D</code>.
* @return a <code>String</code> representing this
* <code>Rectangle2D</code>.
* @since 1.2
*/
public String toString() {
return getClass().getName()
+ "[x=" + x +
",y=" + y +
",w=" + width +
",h=" + height + "]";
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = 7771313791441850493L;
}
/**
* This is an abstract class that cannot be instantiated directly.
* Type-specific implementation subclasses are available for
* instantiation and provide a number of formats for storing
* the information necessary to satisfy the various accessor
* methods below.
*
* @see java.awt.geom.Rectangle2D.Float
* @see java.awt.geom.Rectangle2D.Double
* @see java.awt.Rectangle
* @since 1.2
*/
protected Rectangle2D() {
}
/**
* Sets the location and size of this <code>Rectangle2D</code>
* to the specified <code>double</code> values.
*
* @param x the X coordinate of the upper-left corner
* of this <code>Rectangle2D</code>
* @param y the Y coordinate of the upper-left corner
* of this <code>Rectangle2D</code>
* @param w the width of this <code>Rectangle2D</code>
* @param h the height of this <code>Rectangle2D</code>
* @since 1.2
*/
public abstract void setRect(double x, double y, double w, double h);
/**
* Sets this <code>Rectangle2D</code> to be the same as the specified
* <code>Rectangle2D</code>.
* @param r the specified <code>Rectangle2D</code>
* @since 1.2
*/
public void setRect(Rectangle2D r) {
setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* Tests if the specified line segment intersects the interior of this
* <code>Rectangle2D</code>.
*
* @param x1 the X coordinate of the start point of the specified
* line segment
* @param y1 the Y coordinate of the start point of the specified
* line segment
* @param x2 the X coordinate of the end point of the specified
* line segment
* @param y2 the Y coordinate of the end point of the specified
* line segment
* @return <code>true</code> if the specified line segment intersects
* the interior of this <code>Rectangle2D</code>; <code>false</code>
* otherwise.
* @since 1.2
*/
public boolean intersectsLine(double x1, double y1, double x2, double y2) {
int out1, out2;
if ((out2 = outcode(x2, y2)) == 0) {
return true;
}
while ((out1 = outcode(x1, y1)) != 0) {
if ((out1 & out2) != 0) {
return false;
}
if ((out1 & (OUT_LEFT | OUT_RIGHT)) != 0) {
double x = getX();
if ((out1 & OUT_RIGHT) != 0) {
x += getWidth();
}
y1 = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
x1 = x;
} else {
double y = getY();
if ((out1 & OUT_BOTTOM) != 0) {
y += getHeight();
}
x1 = x1 + (y - y1) * (x2 - x1) / (y2 - y1);
y1 = y;
}
}
return true;
}
/**
* Tests if the specified line segment intersects the interior of this
* <code>Rectangle2D</code>.
* @param l the specified {@link Line2D} to test for intersection
* with the interior of this <code>Rectangle2D</code>
* @return <code>true</code> if the specified <code>Line2D</code>
* intersects the interior of this <code>Rectangle2D</code>;
* <code>false</code> otherwise.
* @since 1.2
*/
public boolean intersectsLine(Line2D l) {
return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
}
/**
* Determines where the specified coordinates lie with respect
* to this <code>Rectangle2D</code>.
* This method computes a binary OR of the appropriate mask values
* indicating, for each side of this <code>Rectangle2D</code>,
* whether or not the specified coordinates are on the same side
* of the edge as the rest of this <code>Rectangle2D</code>.
* @param x the specified X coordinate
* @param y the specified Y coordinate
* @return the logical OR of all appropriate out codes.
* @see #OUT_LEFT
* @see #OUT_TOP
* @see #OUT_RIGHT
* @see #OUT_BOTTOM
* @since 1.2
*/
public abstract int outcode(double x, double y);
/**
* Determines where the specified {@link Point2D} lies with
* respect to this <code>Rectangle2D</code>.
* This method computes a binary OR of the appropriate mask values
* indicating, for each side of this <code>Rectangle2D</code>,
* whether or not the specified <code>Point2D</code> is on the same
* side of the edge as the rest of this <code>Rectangle2D</code>.
* @param p the specified <code>Point2D</code>
* @return the logical OR of all appropriate out codes.
* @see #OUT_LEFT
* @see #OUT_TOP
* @see #OUT_RIGHT
* @see #OUT_BOTTOM
* @since 1.2
*/
public int outcode(Point2D p) {
return outcode(p.getX(), p.getY());
}
/**
* Sets the location and size of the outer bounds of this
* <code>Rectangle2D</code> to the specified rectangular values.
*
* @param x the X coordinate of the upper-left corner
* of this <code>Rectangle2D</code>
* @param y the Y coordinate of the upper-left corner
* of this <code>Rectangle2D</code>
* @param w the width of this <code>Rectangle2D</code>
* @param h the height of this <code>Rectangle2D</code>
* @since 1.2
*/
public void setFrame(double x, double y, double w, double h) {
setRect(x, y, w, h);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return (Rectangle2D) clone();
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y) {
double x0 = getX();
double y0 = getY();
return (x >= x0 &&
y >= y0 &&
x < x0 + getWidth() &&
y < y0 + getHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean intersects(double x, double y, double w, double h) {
if (isEmpty() || w <= 0 || h <= 0) {
return false;
}
double x0 = getX();
double y0 = getY();
return (x + w > x0 &&
y + h > y0 &&
x < x0 + getWidth() &&
y < y0 + getHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y, double w, double h) {
if (isEmpty() || w <= 0 || h <= 0) {
return false;
}
double x0 = getX();
double y0 = getY();
return (x >= x0 &&
y >= y0 &&
(x + w) <= x0 + getWidth() &&
(y + h) <= y0 + getHeight());
}
/**
* Returns a new <code>Rectangle2D</code> object representing the
* intersection of this <code>Rectangle2D</code> with the specified
* <code>Rectangle2D</code>.
* @param r the <code>Rectangle2D</code> to be intersected with
* this <code>Rectangle2D</code>
* @return the largest <code>Rectangle2D</code> contained in both
* the specified <code>Rectangle2D</code> and in this
* <code>Rectangle2D</code>.
* @since 1.2
*/
public abstract Rectangle2D createIntersection(Rectangle2D r);
/**
* Intersects the pair of specified source <code>Rectangle2D</code>
* objects and puts the result into the specified destination
* <code>Rectangle2D</code> object. One of the source rectangles
* can also be the destination to avoid creating a third Rectangle2D
* object, but in this case the original points of this source
* rectangle will be overwritten by this method.
* @param src1 the first of a pair of <code>Rectangle2D</code>
* objects to be intersected with each other
* @param src2 the second of a pair of <code>Rectangle2D</code>
* objects to be intersected with each other
* @param dest the <code>Rectangle2D</code> that holds the
* results of the intersection of <code>src1</code> and
* <code>src2</code>
* @since 1.2
*/
public static void intersect(Rectangle2D src1,
Rectangle2D src2,
Rectangle2D dest) {
double x1 = Math.max(src1.getMinX(), src2.getMinX());
double y1 = Math.max(src1.getMinY(), src2.getMinY());
double x2 = Math.min(src1.getMaxX(), src2.getMaxX());
double y2 = Math.min(src1.getMaxY(), src2.getMaxY());
dest.setFrame(x1, y1, x2-x1, y2-y1);
}
/**
* Returns a new <code>Rectangle2D</code> object representing the
* union of this <code>Rectangle2D</code> with the specified
* <code>Rectangle2D</code>.
* @param r the <code>Rectangle2D</code> to be combined with
* this <code>Rectangle2D</code>
* @return the smallest <code>Rectangle2D</code> containing both
* the specified <code>Rectangle2D</code> and this
* <code>Rectangle2D</code>.
* @since 1.2
*/
public abstract Rectangle2D createUnion(Rectangle2D r);
/**
* Unions the pair of source <code>Rectangle2D</code> objects
* and puts the result into the specified destination
* <code>Rectangle2D</code> object. One of the source rectangles
* can also be the destination to avoid creating a third Rectangle2D
* object, but in this case the original points of this source
* rectangle will be overwritten by this method.
* @param src1 the first of a pair of <code>Rectangle2D</code>
* objects to be combined with each other
* @param src2 the second of a pair of <code>Rectangle2D</code>
* objects to be combined with each other
* @param dest the <code>Rectangle2D</code> that holds the
* results of the union of <code>src1</code> and
* <code>src2</code>
* @since 1.2
*/
public static void union(Rectangle2D src1,
Rectangle2D src2,
Rectangle2D dest) {
double x1 = Math.min(src1.getMinX(), src2.getMinX());
double y1 = Math.min(src1.getMinY(), src2.getMinY());
double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
dest.setFrameFromDiagonal(x1, y1, x2, y2);
}
/**
* Adds a point, specified by the double precision arguments
* <code>newx</code> and <code>newy</code>, to this
* <code>Rectangle2D</code>. The resulting <code>Rectangle2D</code>
* is the smallest <code>Rectangle2D</code> that
* contains both the original <code>Rectangle2D</code> and the
* specified point.
* <p>
* After adding a point, a call to <code>contains</code> with the
* added point as an argument does not necessarily return
* <code>true</code>. The <code>contains</code> method does not
* return <code>true</code> for points on the right or bottom
* edges of a rectangle. Therefore, if the added point falls on
* the left or bottom edge of the enlarged rectangle,
* <code>contains</code> returns <code>false</code> for that point.
* @param newx the X coordinate of the new point
* @param newy the Y coordinate of the new point
* @since 1.2
*/
public void add(double newx, double newy) {
double x1 = Math.min(getMinX(), newx);
double x2 = Math.max(getMaxX(), newx);
double y1 = Math.min(getMinY(), newy);
double y2 = Math.max(getMaxY(), newy);
setRect(x1, y1, x2 - x1, y2 - y1);
}
/**
* Adds the <code>Point2D</code> object <code>pt</code> to this
* <code>Rectangle2D</code>.
* The resulting <code>Rectangle2D</code> is the smallest
* <code>Rectangle2D</code> that contains both the original
* <code>Rectangle2D</code> and the specified <code>Point2D</code>.
* <p>
* After adding a point, a call to <code>contains</code> with the
* added point as an argument does not necessarily return
* <code>true</code>. The <code>contains</code>
* method does not return <code>true</code> for points on the right
* or bottom edges of a rectangle. Therefore, if the added point falls
* on the left or bottom edge of the enlarged rectangle,
* <code>contains</code> returns <code>false</code> for that point.
* @param pt the new <code>Point2D</code> to add to this
* <code>Rectangle2D</code>.
* @since 1.2
*/
public void add(Point2D pt) {
add(pt.getX(), pt.getY());
}
/**
* Adds a <code>Rectangle2D</code> object to this
* <code>Rectangle2D</code>. The resulting <code>Rectangle2D</code>
* is the union of the two <code>Rectangle2D</code> objects.
* @param r the <code>Rectangle2D</code> to add to this
* <code>Rectangle2D</code>.
* @since 1.2
*/
public void add(Rectangle2D r) {
double x1 = Math.min(getMinX(), r.getMinX());
double x2 = Math.max(getMaxX(), r.getMaxX());
double y1 = Math.min(getMinY(), r.getMinY());
double y2 = Math.max(getMaxY(), r.getMaxY());
setRect(x1, y1, x2 - x1, y2 - y1);
}
/**
* Returns an iteration object that defines the boundary of this
* <code>Rectangle2D</code>.
* The iterator for this class is multi-threaded safe, which means
* that this <code>Rectangle2D</code> class guarantees that
* modifications to the geometry of this <code>Rectangle2D</code>
* object do not affect any iterations of that geometry that
* are already in process.
* @param at an optional <code>AffineTransform</code> to be applied to
* the coordinates as they are returned in the iteration, or
* <code>null</code> if untransformed coordinates are desired
* @return the <code>PathIterator</code> object that returns the
* geometry of the outline of this
* <code>Rectangle2D</code>, one segment at a time.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at) {
return new RectIterator(this, at);
}
/**
* Returns an iteration object that defines the boundary of the
* flattened <code>Rectangle2D</code>. Since rectangles are already
* flat, the <code>flatness</code> parameter is ignored.
* The iterator for this class is multi-threaded safe, which means
* that this <code>Rectangle2D</code> class guarantees that
* modifications to the geometry of this <code>Rectangle2D</code>
* object do not affect any iterations of that geometry that
* are already in process.
* @param at an optional <code>AffineTransform</code> to be applied to
* the coordinates as they are returned in the iteration, or
* <code>null</code> if untransformed coordinates are desired
* @param flatness the maximum distance that the line segments used to
* approximate the curved segments are allowed to deviate from any
* point on the original curve. Since rectangles are already flat,
* the <code>flatness</code> parameter is ignored.
* @return the <code>PathIterator</code> object that returns the
* geometry of the outline of this
* <code>Rectangle2D</code>, one segment at a time.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return new RectIterator(this, at);
}
/**
* Returns the hashcode for this <code>Rectangle2D</code>.
* @return the hashcode for this <code>Rectangle2D</code>.
* @since 1.2
*/
public int hashCode() {
long bits = java.lang.Double.doubleToLongBits(getX());
bits += java.lang.Double.doubleToLongBits(getY()) * 37;
bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
return (((int) bits) ^ ((int) (bits >> 32)));
}
/**
* Determines whether or not the specified <code>Object</code> is
* equal to this <code>Rectangle2D</code>. The specified
* <code>Object</code> is equal to this <code>Rectangle2D</code>
* if it is an instance of <code>Rectangle2D</code> and if its
* location and size are the same as this <code>Rectangle2D</code>.
* @param obj an <code>Object</code> to be compared with this
* <code>Rectangle2D</code>.
* @return <code>true</code> if <code>obj</code> is an instance
* of <code>Rectangle2D</code> and has
* the same values; <code>false</code> otherwise.
* @since 1.2
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Rectangle2D) {
Rectangle2D r2d = (Rectangle2D) obj;
return ((getX() == r2d.getX()) &&
(getY() == r2d.getY()) &&
(getWidth() == r2d.getWidth()) &&
(getHeight() == r2d.getHeight()));
}
return false;
}
}

View File

@@ -0,0 +1,397 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.awt.Shape;
import java.awt.Rectangle;
import java.beans.Transient;
/**
* <code>RectangularShape</code> is the base class for a number of
* {@link Shape} objects whose geometry is defined by a rectangular frame.
* This class does not directly specify any specific geometry by
* itself, but merely provides manipulation methods inherited by
* a whole category of <code>Shape</code> objects.
* The manipulation methods provided by this class can be used to
* query and modify the rectangular frame, which provides a reference
* for the subclasses to define their geometry.
*
* @author Jim Graham
* @since 1.2
*/
public abstract class RectangularShape implements Shape, Cloneable {
/**
* This is an abstract class that cannot be instantiated directly.
*
* @see Arc2D
* @see Ellipse2D
* @see Rectangle2D
* @see RoundRectangle2D
* @since 1.2
*/
protected RectangularShape() {
}
/**
* Returns the X coordinate of the upper-left corner of
* the framing rectangle in <code>double</code> precision.
* @return the X coordinate of the upper-left corner of
* the framing rectangle.
* @since 1.2
*/
public abstract double getX();
/**
* Returns the Y coordinate of the upper-left corner of
* the framing rectangle in <code>double</code> precision.
* @return the Y coordinate of the upper-left corner of
* the framing rectangle.
* @since 1.2
*/
public abstract double getY();
/**
* Returns the width of the framing rectangle in
* <code>double</code> precision.
* @return the width of the framing rectangle.
* @since 1.2
*/
public abstract double getWidth();
/**
* Returns the height of the framing rectangle
* in <code>double</code> precision.
* @return the height of the framing rectangle.
* @since 1.2
*/
public abstract double getHeight();
/**
* Returns the smallest X coordinate of the framing
* rectangle of the <code>Shape</code> in <code>double</code>
* precision.
* @return the smallest X coordinate of the framing
* rectangle of the <code>Shape</code>.
* @since 1.2
*/
public double getMinX() {
return getX();
}
/**
* Returns the smallest Y coordinate of the framing
* rectangle of the <code>Shape</code> in <code>double</code>
* precision.
* @return the smallest Y coordinate of the framing
* rectangle of the <code>Shape</code>.
* @since 1.2
*/
public double getMinY() {
return getY();
}
/**
* Returns the largest X coordinate of the framing
* rectangle of the <code>Shape</code> in <code>double</code>
* precision.
* @return the largest X coordinate of the framing
* rectangle of the <code>Shape</code>.
* @since 1.2
*/
public double getMaxX() {
return getX() + getWidth();
}
/**
* Returns the largest Y coordinate of the framing
* rectangle of the <code>Shape</code> in <code>double</code>
* precision.
* @return the largest Y coordinate of the framing
* rectangle of the <code>Shape</code>.
* @since 1.2
*/
public double getMaxY() {
return getY() + getHeight();
}
/**
* Returns the X coordinate of the center of the framing
* rectangle of the <code>Shape</code> in <code>double</code>
* precision.
* @return the X coordinate of the center of the framing rectangle
* of the <code>Shape</code>.
* @since 1.2
*/
public double getCenterX() {
return getX() + getWidth() / 2.0;
}
/**
* Returns the Y coordinate of the center of the framing
* rectangle of the <code>Shape</code> in <code>double</code>
* precision.
* @return the Y coordinate of the center of the framing rectangle
* of the <code>Shape</code>.
* @since 1.2
*/
public double getCenterY() {
return getY() + getHeight() / 2.0;
}
/**
* Returns the framing {@link Rectangle2D}
* that defines the overall shape of this object.
* @return a <code>Rectangle2D</code>, specified in
* <code>double</code> coordinates.
* @see #setFrame(double, double, double, double)
* @see #setFrame(Point2D, Dimension2D)
* @see #setFrame(Rectangle2D)
* @since 1.2
*/
@Transient
public Rectangle2D getFrame() {
return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
}
/**
* Determines whether the <code>RectangularShape</code> is empty.
* When the <code>RectangularShape</code> is empty, it encloses no
* area.
* @return <code>true</code> if the <code>RectangularShape</code> is empty;
* <code>false</code> otherwise.
* @since 1.2
*/
public abstract boolean isEmpty();
/**
* Sets the location and size of the framing rectangle of this
* <code>Shape</code> to the specified rectangular values.
*
* @param x the X coordinate of the upper-left corner of the
* specified rectangular shape
* @param y the Y coordinate of the upper-left corner of the
* specified rectangular shape
* @param w the width of the specified rectangular shape
* @param h the height of the specified rectangular shape
* @see #getFrame
* @since 1.2
*/
public abstract void setFrame(double x, double y, double w, double h);
/**
* Sets the location and size of the framing rectangle of this
* <code>Shape</code> to the specified {@link Point2D} and
* {@link Dimension2D}, respectively. The framing rectangle is used
* by the subclasses of <code>RectangularShape</code> to define
* their geometry.
* @param loc the specified <code>Point2D</code>
* @param size the specified <code>Dimension2D</code>
* @see #getFrame
* @since 1.2
*/
public void setFrame(Point2D loc, Dimension2D size) {
setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
}
/**
* Sets the framing rectangle of this <code>Shape</code> to
* be the specified <code>Rectangle2D</code>. The framing rectangle is
* used by the subclasses of <code>RectangularShape</code> to define
* their geometry.
* @param r the specified <code>Rectangle2D</code>
* @see #getFrame
* @since 1.2
*/
public void setFrame(Rectangle2D r) {
setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* Sets the diagonal of the framing rectangle of this <code>Shape</code>
* based on the two specified coordinates. The framing rectangle is
* used by the subclasses of <code>RectangularShape</code> to define
* their geometry.
*
* @param x1 the X coordinate of the start point of the specified diagonal
* @param y1 the Y coordinate of the start point of the specified diagonal
* @param x2 the X coordinate of the end point of the specified diagonal
* @param y2 the Y coordinate of the end point of the specified diagonal
* @since 1.2
*/
public void setFrameFromDiagonal(double x1, double y1,
double x2, double y2) {
if (x2 < x1) {
double t = x1;
x1 = x2;
x2 = t;
}
if (y2 < y1) {
double t = y1;
y1 = y2;
y2 = t;
}
setFrame(x1, y1, x2 - x1, y2 - y1);
}
/**
* Sets the diagonal of the framing rectangle of this <code>Shape</code>
* based on two specified <code>Point2D</code> objects. The framing
* rectangle is used by the subclasses of <code>RectangularShape</code>
* to define their geometry.
*
* @param p1 the start <code>Point2D</code> of the specified diagonal
* @param p2 the end <code>Point2D</code> of the specified diagonal
* @since 1.2
*/
public void setFrameFromDiagonal(Point2D p1, Point2D p2) {
setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
/**
* Sets the framing rectangle of this <code>Shape</code>
* based on the specified center point coordinates and corner point
* coordinates. The framing rectangle is used by the subclasses of
* <code>RectangularShape</code> to define their geometry.
*
* @param centerX the X coordinate of the specified center point
* @param centerY the Y coordinate of the specified center point
* @param cornerX the X coordinate of the specified corner point
* @param cornerY the Y coordinate of the specified corner point
* @since 1.2
*/
public void setFrameFromCenter(double centerX, double centerY,
double cornerX, double cornerY) {
double halfW = Math.abs(cornerX - centerX);
double halfH = Math.abs(cornerY - centerY);
setFrame(centerX - halfW, centerY - halfH, halfW * 2.0, halfH * 2.0);
}
/**
* Sets the framing rectangle of this <code>Shape</code> based on a
* specified center <code>Point2D</code> and corner
* <code>Point2D</code>. The framing rectangle is used by the subclasses
* of <code>RectangularShape</code> to define their geometry.
* @param center the specified center <code>Point2D</code>
* @param corner the specified corner <code>Point2D</code>
* @since 1.2
*/
public void setFrameFromCenter(Point2D center, Point2D corner) {
setFrameFromCenter(center.getX(), center.getY(),
corner.getX(), corner.getY());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(Point2D p) {
return contains(p.getX(), p.getY());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean intersects(Rectangle2D r) {
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(Rectangle2D r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle getBounds() {
double width = getWidth();
double height = getHeight();
if (width < 0 || height < 0) {
return new Rectangle();
}
double x = getX();
double y = getY();
double x1 = Math.floor(x);
double y1 = Math.floor(y);
double x2 = Math.ceil(x + width);
double y2 = Math.ceil(y + height);
return new Rectangle((int) x1, (int) y1,
(int) (x2 - x1), (int) (y2 - y1));
}
/**
* Returns an iterator object that iterates along the
* <code>Shape</code> object's boundary and provides access to a
* flattened view of the outline of the <code>Shape</code>
* object's geometry.
* <p>
* Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point types will
* be returned by the iterator.
* <p>
* The amount of subdivision of the curved segments is controlled
* by the <code>flatness</code> parameter, which specifies the
* maximum distance that any point on the unflattened transformed
* curve can deviate from the returned flattened path segments.
* An optional {@link AffineTransform} can
* be specified so that the coordinates returned in the iteration are
* transformed accordingly.
* @param at an optional <code>AffineTransform</code> to be applied to the
* coordinates as they are returned in the iteration,
* or <code>null</code> if untransformed coordinates are desired.
* @param flatness the maximum distance that the line segments used to
* approximate the curved segments are allowed to deviate
* from any point on the original curve
* @return a <code>PathIterator</code> object that provides access to
* the <code>Shape</code> object's flattened geometry.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return new FlatteningPathIterator(getPathIterator(at), flatness);
}
/**
* Creates a new object of the same class and with the same
* contents as this object.
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
* @since 1.2
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.util.*;
/**
* A utility class to iterate over the path segments of an rounded rectangle
* through the PathIterator interface.
*
* @author Jim Graham
*/
class RoundRectIterator implements PathIterator {
double x, y, w, h, aw, ah;
AffineTransform affine;
int index;
RoundRectIterator(RoundRectangle2D rr, AffineTransform at) {
this.x = rr.getX();
this.y = rr.getY();
this.w = rr.getWidth();
this.h = rr.getHeight();
this.aw = Math.min(w, Math.abs(rr.getArcWidth()));
this.ah = Math.min(h, Math.abs(rr.getArcHeight()));
this.affine = at;
if (aw < 0 || ah < 0) {
// Don't draw anything...
index = ctrlpts.length;
}
}
/**
* Return the winding rule for determining the insideness of the
* path.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_NON_ZERO;
}
/**
* Tests if there are more points to read.
* @return true if there are more points to read
*/
public boolean isDone() {
return index >= ctrlpts.length;
}
/**
* Moves the iterator to the next segment of the path forwards
* along the primary direction of traversal as long as there are
* more points in that direction.
*/
public void next() {
index++;
}
private static final double angle = Math.PI / 4.0;
private static final double a = 1.0 - Math.cos(angle);
private static final double b = Math.tan(angle);
private static final double c = Math.sqrt(1.0 + b * b) - 1 + a;
private static final double cv = 4.0 / 3.0 * a * b / c;
private static final double acv = (1.0 - cv) / 2.0;
// For each array:
// 4 values for each point {v0, v1, v2, v3}:
// point = (x + v0 * w + v1 * arcWidth,
// y + v2 * h + v3 * arcHeight);
private static double ctrlpts[][] = {
{ 0.0, 0.0, 0.0, 0.5 },
{ 0.0, 0.0, 1.0, -0.5 },
{ 0.0, 0.0, 1.0, -acv,
0.0, acv, 1.0, 0.0,
0.0, 0.5, 1.0, 0.0 },
{ 1.0, -0.5, 1.0, 0.0 },
{ 1.0, -acv, 1.0, 0.0,
1.0, 0.0, 1.0, -acv,
1.0, 0.0, 1.0, -0.5 },
{ 1.0, 0.0, 0.0, 0.5 },
{ 1.0, 0.0, 0.0, acv,
1.0, -acv, 0.0, 0.0,
1.0, -0.5, 0.0, 0.0 },
{ 0.0, 0.5, 0.0, 0.0 },
{ 0.0, acv, 0.0, 0.0,
0.0, 0.0, 0.0, acv,
0.0, 0.0, 0.0, 0.5 },
{},
};
private static int types[] = {
SEG_MOVETO,
SEG_LINETO, SEG_CUBICTO,
SEG_LINETO, SEG_CUBICTO,
SEG_LINETO, SEG_CUBICTO,
SEG_LINETO, SEG_CUBICTO,
SEG_CLOSE,
};
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A float array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
if (isDone()) {
throw new NoSuchElementException("roundrect iterator out of bounds");
}
double ctrls[] = ctrlpts[index];
int nc = 0;
for (int i = 0; i < ctrls.length; i += 4) {
coords[nc++] = (float) (x + ctrls[i + 0] * w + ctrls[i + 1] * aw);
coords[nc++] = (float) (y + ctrls[i + 2] * h + ctrls[i + 3] * ah);
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, nc / 2);
}
return types[index];
}
/**
* Returns the coordinates and type of the current path segment in
* the iteration.
* The return value is the path segment type:
* SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
* A double array of length 6 must be passed in and may be used to
* store the coordinates of the point(s).
* Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types will return one point,
* SEG_QUADTO will return two points,
* SEG_CUBICTO will return 3 points
* and SEG_CLOSE will not return any points.
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
if (isDone()) {
throw new NoSuchElementException("roundrect iterator out of bounds");
}
double ctrls[] = ctrlpts[index];
int nc = 0;
for (int i = 0; i < ctrls.length; i += 4) {
coords[nc++] = (x + ctrls[i + 0] * w + ctrls[i + 1] * aw);
coords[nc++] = (y + ctrls[i + 2] * h + ctrls[i + 3] * ah);
}
if (affine != null) {
affine.transform(coords, 0, coords, 0, nc / 2);
}
return types[index];
}
}

View File

@@ -0,0 +1,681 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.awt.geom;
import java.io.Serializable;
/**
* The <code>RoundRectangle2D</code> class defines a rectangle with
* rounded corners defined by a location {@code (x,y)}, a
* dimension {@code (w x h)}, and the width and height of an arc
* with which to round the corners.
* <p>
* This class is the abstract superclass for all objects that
* store a 2D rounded rectangle.
* The actual storage representation of the coordinates is left to
* the subclass.
*
* @author Jim Graham
* @since 1.2
*/
public abstract class RoundRectangle2D extends RectangularShape {
/**
* The <code>Float</code> class defines a rectangle with rounded
* corners all specified in <code>float</code> coordinates.
* @since 1.2
*/
public static class Float extends RoundRectangle2D
implements Serializable
{
/**
* The X coordinate of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public float x;
/**
* The Y coordinate of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public float y;
/**
* The width of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public float width;
/**
* The height of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public float height;
/**
* The width of the arc that rounds off the corners.
* @since 1.2
* @serial
*/
public float arcwidth;
/**
* The height of the arc that rounds off the corners.
* @since 1.2
* @serial
*/
public float archeight;
/**
* Constructs a new <code>RoundRectangle2D</code>, initialized to
* location (0.0,&nbsp;0.0), size (0.0,&nbsp;0.0), and corner arcs
* of radius 0.0.
* @since 1.2
*/
public Float() {
}
/**
* Constructs and initializes a <code>RoundRectangle2D</code>
* from the specified <code>float</code> coordinates.
*
* @param x the X coordinate of the newly
* constructed <code>RoundRectangle2D</code>
* @param y the Y coordinate of the newly
* constructed <code>RoundRectangle2D</code>
* @param w the width to which to set the newly
* constructed <code>RoundRectangle2D</code>
* @param h the height to which to set the newly
* constructed <code>RoundRectangle2D</code>
* @param arcw the width of the arc to use to round off the
* corners of the newly constructed
* <code>RoundRectangle2D</code>
* @param arch the height of the arc to use to round off the
* corners of the newly constructed
* <code>RoundRectangle2D</code>
* @since 1.2
*/
public Float(float x, float y, float w, float h,
float arcw, float arch)
{
setRoundRect(x, y, w, h, arcw, arch);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return (double) x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return (double) y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getWidth() {
return (double) width;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getHeight() {
return (double) height;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getArcWidth() {
return (double) arcwidth;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getArcHeight() {
return (double) archeight;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean isEmpty() {
return (width <= 0.0f) || (height <= 0.0f);
}
/**
* Sets the location, size, and corner radii of this
* <code>RoundRectangle2D</code> to the specified
* <code>float</code> values.
*
* @param x the X coordinate to which to set the
* location of this <code>RoundRectangle2D</code>
* @param y the Y coordinate to which to set the
* location of this <code>RoundRectangle2D</code>
* @param w the width to which to set this
* <code>RoundRectangle2D</code>
* @param h the height to which to set this
* <code>RoundRectangle2D</code>
* @param arcw the width to which to set the arc of this
* <code>RoundRectangle2D</code>
* @param arch the height to which to set the arc of this
* <code>RoundRectangle2D</code>
* @since 1.2
*/
public void setRoundRect(float x, float y, float w, float h,
float arcw, float arch)
{
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.arcwidth = arcw;
this.archeight = arch;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRoundRect(double x, double y, double w, double h,
double arcw, double arch)
{
this.x = (float) x;
this.y = (float) y;
this.width = (float) w;
this.height = (float) h;
this.arcwidth = (float) arcw;
this.archeight = (float) arch;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRoundRect(RoundRectangle2D rr) {
this.x = (float) rr.getX();
this.y = (float) rr.getY();
this.width = (float) rr.getWidth();
this.height = (float) rr.getHeight();
this.arcwidth = (float) rr.getArcWidth();
this.archeight = (float) rr.getArcHeight();
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return new Rectangle2D.Float(x, y, width, height);
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = -3423150618393866922L;
}
/**
* The <code>Double</code> class defines a rectangle with rounded
* corners all specified in <code>double</code> coordinates.
* @since 1.2
*/
public static class Double extends RoundRectangle2D
implements Serializable
{
/**
* The X coordinate of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public double x;
/**
* The Y coordinate of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public double y;
/**
* The width of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public double width;
/**
* The height of this <code>RoundRectangle2D</code>.
* @since 1.2
* @serial
*/
public double height;
/**
* The width of the arc that rounds off the corners.
* @since 1.2
* @serial
*/
public double arcwidth;
/**
* The height of the arc that rounds off the corners.
* @since 1.2
* @serial
*/
public double archeight;
/**
* Constructs a new <code>RoundRectangle2D</code>, initialized to
* location (0.0,&nbsp;0.0), size (0.0,&nbsp;0.0), and corner arcs
* of radius 0.0.
* @since 1.2
*/
public Double() {
}
/**
* Constructs and initializes a <code>RoundRectangle2D</code>
* from the specified <code>double</code> coordinates.
*
* @param x the X coordinate of the newly
* constructed <code>RoundRectangle2D</code>
* @param y the Y coordinate of the newly
* constructed <code>RoundRectangle2D</code>
* @param w the width to which to set the newly
* constructed <code>RoundRectangle2D</code>
* @param h the height to which to set the newly
* constructed <code>RoundRectangle2D</code>
* @param arcw the width of the arc to use to round off the
* corners of the newly constructed
* <code>RoundRectangle2D</code>
* @param arch the height of the arc to use to round off the
* corners of the newly constructed
* <code>RoundRectangle2D</code>
* @since 1.2
*/
public Double(double x, double y, double w, double h,
double arcw, double arch)
{
setRoundRect(x, y, w, h, arcw, arch);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getX() {
return x;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getY() {
return y;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getWidth() {
return width;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getHeight() {
return height;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getArcWidth() {
return arcwidth;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public double getArcHeight() {
return archeight;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean isEmpty() {
return (width <= 0.0f) || (height <= 0.0f);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRoundRect(double x, double y, double w, double h,
double arcw, double arch)
{
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.arcwidth = arcw;
this.archeight = arch;
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setRoundRect(RoundRectangle2D rr) {
this.x = rr.getX();
this.y = rr.getY();
this.width = rr.getWidth();
this.height = rr.getHeight();
this.arcwidth = rr.getArcWidth();
this.archeight = rr.getArcHeight();
}
/**
* {@inheritDoc}
* @since 1.2
*/
public Rectangle2D getBounds2D() {
return new Rectangle2D.Double(x, y, width, height);
}
/*
* JDK 1.6 serialVersionUID
*/
private static final long serialVersionUID = 1048939333485206117L;
}
/**
* This is an abstract class that cannot be instantiated directly.
* Type-specific implementation subclasses are available for
* instantiation and provide a number of formats for storing
* the information necessary to satisfy the various accessor
* methods below.
*
* @see java.awt.geom.RoundRectangle2D.Float
* @see java.awt.geom.RoundRectangle2D.Double
* @since 1.2
*/
protected RoundRectangle2D() {
}
/**
* Gets the width of the arc that rounds off the corners.
* @return the width of the arc that rounds off the corners
* of this <code>RoundRectangle2D</code>.
* @since 1.2
*/
public abstract double getArcWidth();
/**
* Gets the height of the arc that rounds off the corners.
* @return the height of the arc that rounds off the corners
* of this <code>RoundRectangle2D</code>.
* @since 1.2
*/
public abstract double getArcHeight();
/**
* Sets the location, size, and corner radii of this
* <code>RoundRectangle2D</code> to the specified
* <code>double</code> values.
*
* @param x the X coordinate to which to set the
* location of this <code>RoundRectangle2D</code>
* @param y the Y coordinate to which to set the
* location of this <code>RoundRectangle2D</code>
* @param w the width to which to set this
* <code>RoundRectangle2D</code>
* @param h the height to which to set this
* <code>RoundRectangle2D</code>
* @param arcWidth the width to which to set the arc of this
* <code>RoundRectangle2D</code>
* @param arcHeight the height to which to set the arc of this
* <code>RoundRectangle2D</code>
* @since 1.2
*/
public abstract void setRoundRect(double x, double y, double w, double h,
double arcWidth, double arcHeight);
/**
* Sets this <code>RoundRectangle2D</code> to be the same as the
* specified <code>RoundRectangle2D</code>.
* @param rr the specified <code>RoundRectangle2D</code>
* @since 1.2
*/
public void setRoundRect(RoundRectangle2D rr) {
setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(),
rr.getArcWidth(), rr.getArcHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public void setFrame(double x, double y, double w, double h) {
setRoundRect(x, y, w, h, getArcWidth(), getArcHeight());
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y) {
if (isEmpty()) {
return false;
}
double rrx0 = getX();
double rry0 = getY();
double rrx1 = rrx0 + getWidth();
double rry1 = rry0 + getHeight();
// Check for trivial rejection - point is outside bounding rectangle
if (x < rrx0 || y < rry0 || x >= rrx1 || y >= rry1) {
return false;
}
double aw = Math.min(getWidth(), Math.abs(getArcWidth())) / 2.0;
double ah = Math.min(getHeight(), Math.abs(getArcHeight())) / 2.0;
// Check which corner point is in and do circular containment
// test - otherwise simple acceptance
if (x >= (rrx0 += aw) && x < (rrx0 = rrx1 - aw)) {
return true;
}
if (y >= (rry0 += ah) && y < (rry0 = rry1 - ah)) {
return true;
}
x = (x - rrx0) / aw;
y = (y - rry0) / ah;
return (x * x + y * y <= 1.0);
}
private int classify(double coord, double left, double right,
double arcsize)
{
if (coord < left) {
return 0;
} else if (coord < left + arcsize) {
return 1;
} else if (coord < right - arcsize) {
return 2;
} else if (coord < right) {
return 3;
} else {
return 4;
}
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean intersects(double x, double y, double w, double h) {
if (isEmpty() || w <= 0 || h <= 0) {
return false;
}
double rrx0 = getX();
double rry0 = getY();
double rrx1 = rrx0 + getWidth();
double rry1 = rry0 + getHeight();
// Check for trivial rejection - bounding rectangles do not intersect
if (x + w <= rrx0 || x >= rrx1 || y + h <= rry0 || y >= rry1) {
return false;
}
double aw = Math.min(getWidth(), Math.abs(getArcWidth())) / 2.0;
double ah = Math.min(getHeight(), Math.abs(getArcHeight())) / 2.0;
int x0class = classify(x, rrx0, rrx1, aw);
int x1class = classify(x + w, rrx0, rrx1, aw);
int y0class = classify(y, rry0, rry1, ah);
int y1class = classify(y + h, rry0, rry1, ah);
// Trivially accept if any point is inside inner rectangle
if (x0class == 2 || x1class == 2 || y0class == 2 || y1class == 2) {
return true;
}
// Trivially accept if either edge spans inner rectangle
if ((x0class < 2 && x1class > 2) || (y0class < 2 && y1class > 2)) {
return true;
}
// Since neither edge spans the center, then one of the corners
// must be in one of the rounded edges. We detect this case if
// a [xy]0class is 3 or a [xy]1class is 1. One of those two cases
// must be true for each direction.
// We now find a "nearest point" to test for being inside a rounded
// corner.
x = (x1class == 1) ? (x = x + w - (rrx0 + aw)) : (x = x - (rrx1 - aw));
y = (y1class == 1) ? (y = y + h - (rry0 + ah)) : (y = y - (rry1 - ah));
x = x / aw;
y = y / ah;
return (x * x + y * y <= 1.0);
}
/**
* {@inheritDoc}
* @since 1.2
*/
public boolean contains(double x, double y, double w, double h) {
if (isEmpty() || w <= 0 || h <= 0) {
return false;
}
return (contains(x, y) &&
contains(x + w, y) &&
contains(x, y + h) &&
contains(x + w, y + h));
}
/**
* Returns an iteration object that defines the boundary of this
* <code>RoundRectangle2D</code>.
* The iterator for this class is multi-threaded safe, which means
* that this <code>RoundRectangle2D</code> class guarantees that
* modifications to the geometry of this <code>RoundRectangle2D</code>
* object do not affect any iterations of that geometry that
* are already in process.
* @param at an optional <code>AffineTransform</code> to be applied to
* the coordinates as they are returned in the iteration, or
* <code>null</code> if untransformed coordinates are desired
* @return the <code>PathIterator</code> object that returns the
* geometry of the outline of this
* <code>RoundRectangle2D</code>, one segment at a time.
* @since 1.2
*/
public PathIterator getPathIterator(AffineTransform at) {
return new RoundRectIterator(this, at);
}
/**
* Returns the hashcode for this <code>RoundRectangle2D</code>.
* @return the hashcode for this <code>RoundRectangle2D</code>.
* @since 1.6
*/
public int hashCode() {
long bits = java.lang.Double.doubleToLongBits(getX());
bits += java.lang.Double.doubleToLongBits(getY()) * 37;
bits += java.lang.Double.doubleToLongBits(getWidth()) * 43;
bits += java.lang.Double.doubleToLongBits(getHeight()) * 47;
bits += java.lang.Double.doubleToLongBits(getArcWidth()) * 53;
bits += java.lang.Double.doubleToLongBits(getArcHeight()) * 59;
return (((int) bits) ^ ((int) (bits >> 32)));
}
/**
* Determines whether or not the specified <code>Object</code> is
* equal to this <code>RoundRectangle2D</code>. The specified
* <code>Object</code> is equal to this <code>RoundRectangle2D</code>
* if it is an instance of <code>RoundRectangle2D</code> and if its
* location, size, and corner arc dimensions are the same as this
* <code>RoundRectangle2D</code>.
* @param obj an <code>Object</code> to be compared with this
* <code>RoundRectangle2D</code>.
* @return <code>true</code> if <code>obj</code> is an instance
* of <code>RoundRectangle2D</code> and has the same values;
* <code>false</code> otherwise.
* @since 1.6
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof RoundRectangle2D) {
RoundRectangle2D rr2d = (RoundRectangle2D) obj;
return ((getX() == rr2d.getX()) &&
(getY() == rr2d.getY()) &&
(getWidth() == rr2d.getWidth()) &&
(getHeight() == rr2d.getHeight()) &&
(getArcWidth() == rr2d.getArcWidth()) &&
(getArcHeight() == rr2d.getArcHeight()));
}
return false;
}
}