FileDocCategorySizeDatePackage
Area.javaAPI DocJava SE 5 API19782Fri Aug 26 14:56:52 BST 2005java.awt.geom

Area

public class Area extends Object implements Shape, Cloneable
The Area class is a device-independent specification of an arbitrarily-shaped area. The Area object is defined as an object that performs certain binary CAG (Constructive Area Geometry) operations on other area-enclosing geometries, such as rectangles, ellipses, and polygons. The CAG operations are Add(union), Subtract, Intersect, and ExclusiveOR. For example, an Area can be made up of the area of a rectangle minus the area of an ellipse.

Fields Summary
private static Vector
EmptyCurves
private Vector
curves
private Rectangle2D
cachedBounds
Constructors Summary
public Area()
Default constructor which creates an empty area.


                
      
	curves = EmptyCurves;
    
public Area(Shape s)
The Area class creates an area geometry from the specified {@link Shape} object. The geometry is explicitly closed, if the Shape is not already closed. The fill rule (even-odd or winding) specified by the geometry of the Shape is used to determine the resulting enclosed area.

param
s the Shape from which the area is constructed

	if (s instanceof Area) {
	    curves = ((Area) s).curves;
	    return;
	}
	curves = new Vector();
	PathIterator pi = s.getPathIterator(null);
	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();
	}
	curves = operator.calculate(this.curves, EmptyCurves);
    
Methods Summary
public voidadd(java.awt.geom.Area rhs)
Adds the shape of the specified Area to the shape of this Area. Addition is achieved through union.

param
rhs the Area to be added to the current shape

	curves = new AreaOp.AddOp().calculate(this.curves, rhs.curves);
	invalidateBounds();
    
public java.lang.Objectclone()
Returns an exact copy of this Area object.

return
Created clone object

	return new Area(this);
    
public booleancontains(double x, double y)
Tests if a specifed point lies inside the boundary of this Area object.

param
x, y the specified point
return
true if the point lies completely within the interior of the Area; false otherwise.

	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);
    
public booleancontains(java.awt.geom.Point2D p)
Tests if a specified {@link Point2D} lies inside the boundary of the this Area object.

param
p the Point2D to test
return
true if the specified Point2D lies completely within the interior of the Area; false otherwise.

	return contains(p.getX(), p.getY());
    
public booleancontains(double x, double y, double w, double h)
Tests whether or not the interior of this Area object completely contains the specified rectangular area.

param
x, y the coordinates of the upper left corner of the specified rectangular area
param
w the width of the specified rectangular area
param
h the height of the specified rectangular area
return
true if the specified rectangular area lies completely within the interior of the Area; false otherwise.

	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));
    
public booleancontains(java.awt.geom.Rectangle2D p)
Tests whether or not the interior of this Area object completely contains the specified Rectangle2D.

param
p the Rectangle2D to test
return
true if the Rectangle2D lies completely within the interior of the Area; false otherwise.

	return contains(p.getX(), p.getY(), p.getWidth(), p.getHeight());
    
public java.awt.geom.AreacreateTransformedArea(java.awt.geom.AffineTransform t)
Creates a new Area object that contains the same geometry as this Area transformed by the specified AffineTransform. This Area object is unchanged.

param
t the specified AffineTransform used to transform the new Area
return
a new Area object representing the transformed geometry.

	// REMIND: A simpler operation can be performed for some types
	// of transform.
	// REMIND: this could be simplified by "breaking out" the
	// PathIterator code from the constructor
	return new Area(t.createTransformedShape(this));
    
public booleanequals(java.awt.geom.Area other)
Tests whether the geometries of the two Area objects are equal.

param
other the Area to be compared to this Area
return
true if the two geometries are equal; false otherwise.

	// 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();
    
public voidexclusiveOr(java.awt.geom.Area rhs)
Sets the shape of this Area to be the combined area of its current shape and the shape of the specified Area, minus their intersection.

param
rhs the Area to be exclusive ORed with this Area.

	curves = new AreaOp.XorOp().calculate(this.curves, rhs.curves);
	invalidateBounds();
    
public java.awt.RectanglegetBounds()
Returns a bounding {@link Rectangle} that completely encloses this Area.

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 Rectangle for the Area.

	return getCachedBounds().getBounds();
    
public java.awt.geom.Rectangle2DgetBounds2D()
Returns a high precision bounding {@link Rectangle2D} that completely encloses this Area.

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 Rectangle2D for the Area.

	return getCachedBounds().getBounds2D();
    
private java.awt.geom.Rectangle2DgetCachedBounds()

	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);
    
public java.awt.geom.PathIteratorgetPathIterator(java.awt.geom.AffineTransform at)
Creates a {@link PathIterator} for the outline of this Area object. This Area object is unchanged.

param
at an optional AffineTransform to be applied to the coordinates as they are returned in the iteration, or null if untransformed coordinates are desired
return
the PathIterator object that returns the geometry of the outline of this Area, one segment at a time.

	return new AreaIterator(curves, at);
    
public java.awt.geom.PathIteratorgetPathIterator(java.awt.geom.AffineTransform at, double flatness)
Creates a PathIterator for the flattened outline of this Area object. Only uncurved path segments represented by the SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point types are returned by the iterator. This Area object is unchanged.

param
at an optional AffineTransform to be applied to the coordinates as they are returned in the iteration, or null 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 endpoints
return
the PathIterator object that returns the geometry of the outline of this Area, one segment at a time.

	return new FlatteningPathIterator(getPathIterator(at), flatness);
    
public voidintersect(java.awt.geom.Area rhs)
Sets the shape of this Area to the intersection of its current shape and the shape of the specified Area.

param
rhs the Area to be intersected with this Area

	curves = new AreaOp.IntOp().calculate(this.curves, rhs.curves);
	invalidateBounds();
    
public booleanintersects(double x, double y, double w, double h)
Tests whether the interior of this Area object intersects the interior of the specified rectangular area.

param
x, y the coordinates of the upper left corner of the specified rectangular area
param
w the width of the specified rectangular area
param
h the height of teh specified rectangular area
return
true if the interior intersects the specified rectangular area; false otherwise;

	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());
    
public booleanintersects(java.awt.geom.Rectangle2D p)
Tests whether the interior of this Area object intersects the interior of the specified Rectangle2D.

param
p the Rectangle2D to test for intersection
return
true if the interior intersects the specified Rectangle2D; false otherwise.

	return intersects(p.getX(), p.getY(), p.getWidth(), p.getHeight());
    
private voidinvalidateBounds()

	cachedBounds = null;
    
public booleanisEmpty()
Tests whether this Area object encloses any area.

return
true if this Area object represents an empty area; false otherwise.

	return (curves.size() == 0);
    
public booleanisPolygonal()
Tests whether this Area consists entirely of straight edged polygonal geometry.

return
true if the geometry of this Area consists entirely of line segments; false otherwise.

	Enumeration enum_ = curves.elements();
	while (enum_.hasMoreElements()) {
	    if (((Curve) enum_.nextElement()).getOrder() > 1) {
		return false;
	    }
	}
	return true;
    
public booleanisRectangular()
Tests whether this Area is rectangular in shape.

return
true if the geometry of this Area is rectangular in shape; false otherwise.

	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;
    
public booleanisSingular()
Tests whether this Area is comprised of a single closed subpath. This method returns true if the path contains 0 or 1 subpaths, or false 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
true if the Area is comprised of a single basic geometry; false otherwise.

	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;
    
public voidreset()
Removes all of the geometry from this Area and restores it to an empty area.

	curves = new Vector();
	invalidateBounds();
    
public voidsubtract(java.awt.geom.Area rhs)
Subtracts the shape of the specified Area from the shape of this Area.

param
rhs the Area to be subtracted from the current shape

	curves = new AreaOp.SubOp().calculate(this.curves, rhs.curves);
	invalidateBounds();
    
public voidtransform(java.awt.geom.AffineTransform t)
Transforms the geometry of this Area 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

	// REMIND: A simpler operation can be performed for some types
	// of transform.
	// REMIND: this could be simplified by "breaking out" the
	// PathIterator code from the constructor
	curves = new Area(t.createTransformedShape(this)).curves;
	invalidateBounds();