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

GeneralPath

public final class GeneralPath extends Object implements Shape, Cloneable
The GeneralPath class represents a geometric path constructed from straight lines, and quadratic and cubic (Bézier) curves. It can contain multiple subpaths.

The winding rule specifies how the interior of a path is determined. There are two types of winding rules: EVEN_ODD and NON_ZERO.

An EVEN_ODD winding rule means that enclosed regions of the path alternate between interior and exterior areas as traversed from the outside of the path towards a point inside the region.

A NON_ZERO winding rule means that if a ray is drawn in any direction from a given point to infinity and the places where the path intersects the ray are examined, the point is inside of the path if and only if the number of times that the path crosses the ray from left to right does not equal the number of times that the path crosses the ray from right to left.

version
1.59, 12/19/03
author
Jim Graham

Fields Summary
public static final int
WIND_EVEN_ODD
An even-odd winding rule for determining the interior of a path.
public static final int
WIND_NON_ZERO
A non-zero winding rule for determining the interior of a path.
private static final byte
SEG_MOVETO
private static final byte
SEG_LINETO
private static final byte
SEG_QUADTO
private static final byte
SEG_CUBICTO
private static final byte
SEG_CLOSE
byte[]
pointTypes
float[]
pointCoords
int
numTypes
int
numCoords
int
windingRule
static final int
INIT_SIZE
static final int
EXPAND_MAX
Constructors Summary
public GeneralPath()
Constructs a new GeneralPath object. If an operation performed on this path requires the interior of the path to be defined then the default NON_ZERO winding rule is used.

see
#WIND_NON_ZERO


                                        
      
	this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE);
    
public GeneralPath(int rule)
Constructs a new GeneralPath 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

	this(rule, INIT_SIZE, INIT_SIZE);
    
public GeneralPath(int rule, int initialCapacity)
Constructs a new GeneralPath 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 are in the path, but the storage is expanded as needed to store whatever path segments are added to this path.

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

	this(rule, initialCapacity, initialCapacity);
    
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.pointCoords = pointCoords;
	this.numCoords = numCoords;
    
GeneralPath(int rule, int initialTypes, int initialCoords)
Constructs a new GeneralPath object with the specified winding rule and the specified initial capacities to store point types and coordinates. These numbers are an initial guess as to how many path segments and how many points are to be in the path, but the storage is expanded as needed to store whatever path segments are added to this path.

param
rule the winding rule
param
initialTypes the estimate for the number of path segments in the path
param
initialCapacity the estimate for the number of points
see
#WIND_EVEN_ODD
see
#WIND_NON_ZERO

	setWindingRule(rule);
	pointTypes = new byte[initialTypes];
	pointCoords = new float[initialCoords * 2];
    
public GeneralPath(Shape s)
Constructs a new GeneralPath object from an arbitrary {@link Shape} object. All of the initial geometry and the winding rule for this path are taken from the specified Shape object.

param
s the specified Shape object

	this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE);
	PathIterator pi = s.getPathIterator(null);
	setWindingRule(pi.getWindingRule());
	append(pi, false);
    
Methods Summary
public voidappend(java.awt.Shape s, boolean connect)
Appends the geometry of the specified Shape object to the path, possibly connecting the new geometry to the existing path segments with a line segment. If the connect parameter is true and the path is not empty then any initial moveTo in the geometry of the appended Shape is turned into a lineTo segment. If the destination coordinates of such a connecting lineTo segment match the ending coordinates of a currently open subpath then the segment is omitted as superfluous. The winding rule of the specified Shape is ignored and the appended geometry is governed by the winding rule specified for this path.

param
s the Shape whose geometry is appended to this path
param
connect a boolean to control whether or not to turn an initial moveTo segment into a lineTo segment to connect the new geometry to the existing path

	PathIterator pi = s.getPathIterator(null);
        append(pi,connect);
    
public voidappend(java.awt.geom.PathIterator pi, boolean connect)
Appends the geometry of the specified {@link PathIterator} object to the path, possibly connecting the new geometry to the existing path segments with a line segment. If the connect parameter is true and the path is not empty then any initial moveTo in the geometry of the appended Shape is turned into a lineTo segment. If the destination coordinates of such a connecting lineTo segment match the ending coordinates of a currently open subpath then the segment is omitted as superfluous. The winding rule of the specified Shape is ignored and the appended geometry is governed by the winding rule specified for this path.

param
pi the PathIterator whose geometry is appended to this path
param
connect a boolean to control whether or not to turn an initial moveTo segment into a lineTo segment to connect the new geometry to the existing path

	float coords[] = new float[6];
	while (!pi.isDone()) {
	    switch (pi.currentSegment(coords)) {
	    case SEG_MOVETO:
		if (!connect || numTypes < 1 || numCoords < 2) {
		    moveTo(coords[0], coords[1]);
		    break;
		}
		if (pointTypes[numTypes - 1] != SEG_CLOSE &&
		    pointCoords[numCoords - 2] == coords[0] &&
		    pointCoords[numCoords - 1] == coords[1])
		{
		    // Collapse out initial moveto/lineto
		    break;
		}
		// NO BREAK;
	    case SEG_LINETO:
		lineTo(coords[0], coords[1]);
		break;
	    case SEG_QUADTO:
		quadTo(coords[0], coords[1],
		       coords[2], coords[3]);
		break;
	    case SEG_CUBICTO:
		curveTo(coords[0], coords[1],
			coords[2], coords[3],
			coords[4], coords[5]);
		break;
	    case SEG_CLOSE:
		closePath();
		break;
	    }
	    pi.next();
	    connect = false;
	}
    
public java.lang.Objectclone()
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

	try {
	    GeneralPath copy = (GeneralPath) super.clone();
	    copy.pointTypes = (byte[]) pointTypes.clone();
	    copy.pointCoords = (float[]) pointCoords.clone();
	    return copy;
	} catch (CloneNotSupportedException e) {
	    // this shouldn't happen, since we are Cloneable
	    throw new InternalError();
	}
    
public synchronized voidclosePath()
Closes the current subpath by drawing a straight line back to the coordinates of the last moveTo. If the path is already closed then this method has no effect.

	if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
	    needRoom(1, 0, true);
	    pointTypes[numTypes++] = SEG_CLOSE;
	}
    
public booleancontains(double x, double y)
Tests if the specified coordinates are inside the boundary of this Shape.

param
x, y the specified coordinates
return
true if the specified coordinates are inside this Shape; false otherwise

	if (numTypes < 2) {
	    return false;
	}
	int cross = Curve.crossingsForPath(getPathIterator(null), x, y);
	if (windingRule == WIND_NON_ZERO) {
	    return (cross != 0);
	} else {
	    return ((cross & 1) != 0);
	}
    
public booleancontains(java.awt.geom.Point2D p)
Tests if the specified Point2D is inside the boundary of this Shape.

param
p the specified Point2D
return
true if this Shape contains the specified Point2D, false otherwise.

	return contains(p.getX(), p.getY());
    
public booleancontains(double x, double y, double w, double h)
Tests if the specified rectangular area is inside the boundary of this Shape.

param
x, y the specified coordinates
param
w the width of the specified rectangular area
param
h the height of the specified rectangular area
return
true if this Shape contains the specified rectangluar area; false otherwise.

	Crossings c = Crossings.findCrossings(getPathIterator(null),
					      x, y, x+w, y+h);
	return (c != null && c.covers(y, y+h));
    
public booleancontains(java.awt.geom.Rectangle2D r)
Tests if the specified Rectangle2D is inside the boundary of this Shape.

param
r a specified Rectangle2D
return
true if this Shape bounds the specified Rectangle2D; false otherwise.

	return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    
public synchronized java.awt.ShapecreateTransformedShape(java.awt.geom.AffineTransform at)
Returns a new transformed Shape.

param
at the AffineTransform used to transform a new Shape.
return
a new Shape, transformed with the specified AffineTransform.

	GeneralPath gp = (GeneralPath) clone();
	if (at != null) {
	    gp.transform(at);
	}
	return gp;
    
public synchronized voidcurveTo(float x1, float y1, float x2, float y2, float x3, float y3)
Adds a curved segment, defined by three new points, to the path by drawing a Bézier curve that intersects both the current coordinates and the coordinates (x3, y3), using the specified points (x1, y1) and (x2, y2) as Bézier control points.

param
x1, y1 the coordinates of the first Béezier control point
param
x2, y2 the coordinates of the second Bézier control point
param
x3, y3 the coordinates of the final endpoint

	needRoom(1, 6, true);
	pointTypes[numTypes++] = SEG_CUBICTO;
	pointCoords[numCoords++] = x1;
	pointCoords[numCoords++] = y1;
	pointCoords[numCoords++] = x2;
	pointCoords[numCoords++] = y2;
	pointCoords[numCoords++] = x3;
	pointCoords[numCoords++] = y3;
    
public java.awt.RectanglegetBounds()
Return the bounding box of the path.

return
a {@link java.awt.Rectangle} object that bounds the current path.

	return getBounds2D().getBounds();
    
public synchronized java.awt.geom.Rectangle2DgetBounds2D()
Returns the bounding box of the path.

return
a {@link Rectangle2D} object that bounds the current path.

	float x1, y1, x2, y2;
	int i = numCoords;
	if (i > 0) {
	    y1 = y2 = pointCoords[--i];
	    x1 = x2 = pointCoords[--i];
	    while (i > 0) {
		float y = pointCoords[--i];
		float x = pointCoords[--i];
		if (x < x1) x1 = x;
		if (y < y1) y1 = y;
		if (x > x2) x2 = x;
		if (y > y2) y2 = y;
	    }
	} else {
	    x1 = y1 = x2 = y2 = 0.0f;
	}
	return new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1);
    
public synchronized java.awt.geom.Point2DgetCurrentPoint()
Returns the coordinates most recently added to the end of the path as a {@link Point2D} object.

return
a Point2D object containing the ending coordinates of the path or null if there are no points in the path.

	if (numTypes < 1 || numCoords < 2) {
	    return null;
	}
	int index = numCoords;
	if (pointTypes[numTypes - 1] == SEG_CLOSE) {
	loop:
	    for (int i = numTypes - 2; i > 0; i--) {
		switch (pointTypes[i]) {
		case SEG_MOVETO:
		    break loop;
		case SEG_LINETO:
		    index -= 2;
		    break;
		case SEG_QUADTO:
		    index -= 4;
		    break;
		case SEG_CUBICTO:
		    index -= 6;
		    break;
		case SEG_CLOSE:
		    break;
		}
	    }
	}
	return new Point2D.Float(pointCoords[index - 2],
				 pointCoords[index - 1]);
    
public java.awt.geom.PathIteratorgetPathIterator(java.awt.geom.AffineTransform at)
Returns a PathIterator object that iterates along the boundary of this Shape and provides access to the geometry of the outline of this Shape. The iterator for this class is not multi-threaded safe, which means that this GeneralPath class does not guarantee that modifications to the geometry of this GeneralPath object do not affect any iterations of that geometry that are already in process.

param
at an AffineTransform
return
a new PathIterator that iterates along the boundary of this Shape and provides access to the geometry of this Shape's outline

	return new GeneralPathIterator(this, at);
    
public java.awt.geom.PathIteratorgetPathIterator(java.awt.geom.AffineTransform at, double flatness)
Returns a PathIterator object that iterates along the boundary of the flattened Shape and provides access to the geometry of the outline of the Shape. The iterator for this class is not multi-threaded safe, which means that this GeneralPath class does not guarantee that modifications to the geometry of this GeneralPath object do not affect any iterations of that geometry that are already in process.

param
at an AffineTransform
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 new PathIterator that iterates along the flattened Shape boundary.

	return new FlatteningPathIterator(getPathIterator(at), flatness);
    
public synchronized intgetWindingRule()
Returns the fill style winding rule.

return
an integer representing the current winding rule.
see
#WIND_EVEN_ODD
see
#WIND_NON_ZERO
see
#setWindingRule

        return windingRule;
    
public booleanintersects(double x, double y, double w, double h)
Tests if the interior of this Shape intersects the interior of a specified set of rectangular coordinates.

param
x, y the specified coordinates
param
w the width of the specified rectangular coordinates
param
h the height of the specified rectangular coordinates
return
true if this Shape and the interior of the specified set of rectangular coordinates intersect each other; false otherwise.

	Crossings c = Crossings.findCrossings(getPathIterator(null),
					      x, y, x+w, y+h);
	return (c == null || !c.isEmpty());
    
public booleanintersects(java.awt.geom.Rectangle2D r)
Tests if the interior of this Shape intersects the interior of a specified Rectangle2D.

param
r the specified Rectangle2D
return
true if this Shape and the interior of the specified Rectangle2D intersect each other; false otherwise.

	return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    
public synchronized voidlineTo(float x, float y)
Adds a point to the path by drawing a straight line from the current coordinates to the new specified coordinates.

param
x, y the specified coordinates

	needRoom(1, 2, true);
	pointTypes[numTypes++] = SEG_LINETO;
	pointCoords[numCoords++] = x;
	pointCoords[numCoords++] = y;
    
public synchronized voidmoveTo(float x, float y)
Adds a point to the path by moving to the specified coordinates.

param
x, y the specified coordinates

	if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
	    pointCoords[numCoords - 2] = x;
	    pointCoords[numCoords - 1] = y;
	} else {
	    needRoom(1, 2, false);
	    pointTypes[numTypes++] = SEG_MOVETO;
	    pointCoords[numCoords++] = x;
	    pointCoords[numCoords++] = y;
	}
    
private voidneedRoom(int newTypes, int newCoords, boolean needMove)

	if (needMove && numTypes == 0) {
	    throw new IllegalPathStateException("missing initial moveto "+
						"in path definition");
	}
	int size = pointCoords.length;
	if (numCoords + newCoords > size) {
	    int grow = size;
	    if (grow > EXPAND_MAX * 2) {
		grow = EXPAND_MAX * 2;
	    }
	    if (grow < newCoords) {
		grow = newCoords;
	    }
	    float[] arr = new float[size + grow];
	    System.arraycopy(pointCoords, 0, arr, 0, numCoords);
	    pointCoords = arr;
	}
	size = pointTypes.length;
	if (numTypes + newTypes > size) {
	    int grow = size;
	    if (grow > EXPAND_MAX) {
		grow = EXPAND_MAX;
	    }
	    if (grow < newTypes) {
		grow = newTypes;
	    }
	    byte[] arr = new byte[size + grow];
	    System.arraycopy(pointTypes, 0, arr, 0, numTypes);
	    pointTypes = arr;
	}
    
public synchronized voidquadTo(float x1, float y1, float x2, float y2)
Adds a curved segment, defined by two new points, to the path by drawing a Quadratic curve that intersects both the current coordinates and the coordinates (x2, y2), using the specified point (x1, y1) as a quadratic parametric control point.

param
x1, y1 the coordinates of the first quadratic control point
param
x2, y2 the coordinates of the final endpoint

	needRoom(1, 4, true);
	pointTypes[numTypes++] = SEG_QUADTO;
	pointCoords[numCoords++] = x1;
	pointCoords[numCoords++] = y1;
	pointCoords[numCoords++] = x2;
	pointCoords[numCoords++] = y2;
    
public synchronized voidreset()
Resets the path to empty. The append position is set back to the beginning of the path and all coordinates and point types are forgotten.

	numTypes = numCoords = 0;
    
public voidsetWindingRule(int rule)
Sets the winding rule for this path to the specified value.

param
rule an integer representing the specified winding rule
exception
IllegalArgumentException if rule is not either WIND_EVEN_ODD or WIND_NON_ZERO
see
#WIND_EVEN_ODD
see
#WIND_NON_ZERO
see
#getWindingRule

	if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
	    throw new IllegalArgumentException("winding rule must be "+
					       "WIND_EVEN_ODD or "+
					       "WIND_NON_ZERO");
	}
	windingRule = rule;
    
public voidtransform(java.awt.geom.AffineTransform at)
Transforms the geometry of this path using the specified {@link AffineTransform}. The geometry is transformed in place, which permanently changes the boundary defined by this object.

param
at the AffineTransform used to transform the area

	at.transform(pointCoords, 0, pointCoords, 0, numCoords / 2);