org.jhotdraw.geom
Class BezierPath

java.lang.Object
  extended by java.util.AbstractCollection<E>
      extended by java.util.AbstractList<E>
          extended by java.util.ArrayList<BezierPath.Node>
              extended by org.jhotdraw.geom.BezierPath
All Implemented Interfaces:
java.awt.Shape, java.io.Serializable, java.lang.Cloneable, java.lang.Iterable<BezierPath.Node>, java.util.Collection<BezierPath.Node>, java.util.List<BezierPath.Node>, java.util.RandomAccess

public class BezierPath
extends java.util.ArrayList<BezierPath.Node>
implements java.awt.Shape, java.io.Serializable, java.lang.Cloneable

BezierPath allows the construction of paths consisting of straight lines, quadratic curves and cubic curves.

A BezierPath is defined by its nodes. Each node has three control points: C0, C1, C2. A mask defines which control points are in use. At a node, the path passes through C0. C1 controls the curve going towards C0. C2 controls the curve going away from C0.

Version:
$Id: BezierPath.java 728 2011-01-09 16:14:14Z rawcoder $
Author:
Werner Randelshofer
See Also:
Serialized Form

Nested Class Summary
static class BezierPath.Node
          Defines a vertex (node) of the bezier path.
 
Field Summary
private  java.awt.geom.Rectangle2D.Double bounds
          
Fields inherited from class java.util.AbstractList
modCount
 
Constructor Summary
BezierPath()
          Creates a new instance.
 
Method Summary
 void add(double x, double y)
          Adds a node to the path.
 void add(int ctrlMask, java.awt.geom.Point2D.Double c0, java.awt.geom.Point2D.Double c1, java.awt.geom.Point2D.Double c2)
          Adds a node to the path.
 void add(java.awt.geom.Point2D.Double c0)
          Adds a node to the path.
 void addPolyline(java.util.Collection<java.awt.geom.Point2D.Double> points)
          Adds a set of nodes to the path.
 void arcTo(double rx, double ry, double xAxisRotation, boolean largeArcFlag, boolean sweepFlag, double x, double y)
          Adds an elliptical arc, defined by two radii, an angle from the x-axis, a flag to choose the large arc or not, a flag to indicate if we increase or decrease the angles and the final point of the arc.
 java.awt.geom.Point2D.Double chop(java.awt.geom.Point2D.Double p)
          Returns a point on the edge of the bezier path which crosses the line from the center of the bezier path to the specified point.
 BezierPath clone()
          Creates a deep copy of the BezierPath.
 boolean contains(double x, double y)
           
 boolean contains(double x, double y, double w, double h)
           
 boolean contains(java.awt.geom.Point2D p)
           
 boolean contains(java.awt.geom.Rectangle2D r)
           
 void curveTo(double x1, double y1, double x2, double y2, double x3, double y3)
          Adds a cubic curve to the bezier path.
 int findSegment(java.awt.geom.Point2D.Double find, double tolerance)
          Gets the segment of the polyline that is hit by the given Point2D.Double.
 java.awt.geom.Point2D.Double get(int nodeIndex, int ctrlIndex)
          Convenience method for getting a single control point of a node.
 java.awt.Rectangle getBounds()
           
 java.awt.geom.Rectangle2D.Double getBounds2D()
           
 java.awt.geom.Point2D.Double getCenter()
          Returns the point at the center of the bezier path.
 double getLengthOfPath(double flatness)
          Returns the length of the path.
 java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform at)
           
 java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform at, double flatness)
           
 java.awt.geom.Point2D.Double getPointOnPath(double relative, double flatness)
          
Methods inherited from class java.util.ArrayList
add, add, addAll, addAll, clear, contains, ensureCapacity, get, indexOf, isEmpty, lastIndexOf, remove, remove, removeRange, set, size, toArray, toArray, trimToSize
 
Methods inherited from class java.util.AbstractList
equals, hashCode, iterator, listIterator, listIterator, subList
 
Methods inherited from class java.util.AbstractCollection
containsAll, removeAll, retainAll, toString
 
Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface java.util.List
containsAll, equals, hashCode, iterator, listIterator, listIterator, removeAll, retainAll, subList
 

Field Detail

C0_MASK

public static final int C0_MASK
Constant for having only control point C0 in effect. C0 is the point through whitch the curve passes.

See Also:
Constant Field Values

C1_MASK

public static final int C1_MASK
Constant for having control point C1 in effect (in addition to C0). C1 controls the curve going towards C0.

See Also:
Constant Field Values

C2_MASK

public static final int C2_MASK
Constant for having control point C2 in effect (in addition to C0). C2 controls the curve going away from C0.

See Also:
Constant Field Values

C1C2_MASK

public static final int C1C2_MASK
Constant for having control points C1 and C2 in effect (in addition to C0).

See Also:
Constant Field Values

generalPath

We cache a Path2D.Double instance to speed up Shape operations.


bounds

We cache a Rectangle2D.Double instance to speed up getBounds operations.


outer

private int outer
We cache the index of the outermost node to speed up method indexOfOutermostNode();


isClosed

private boolean isClosed
If this value is set to true, closes the bezier path.


windingRule

private int windingRule
The winding rule for filling the bezier path.

Constructor Detail

BezierPath

public BezierPath()
Creates a new instance.

Method Detail

add

public void add(java.awt.geom.Point2D.Double c0)
Adds a node to the path.

This is a convenience method for adding a node with a single control point C0 to the path.


add

public void add(double x,
                double y)
Adds a node to the path.

This is a convenience method for adding a node with a single control point C0 to the path.


add

public void add(int ctrlMask,
                java.awt.geom.Point2D.Double c0,
                java.awt.geom.Point2D.Double c1,
                java.awt.geom.Point2D.Double c2)
Adds a node to the path.

This is a convenience method for adding a node with three control points C0, C1 and C2, and a mask.

Parameters:
ctrlMask - An or-combination of C0_MASK,C1_MASK and C2_MASK.
c0 - The coordinates of the C0 control point.
c1 - The coordinates of the C1 control point.
c2 - The coordinates of the C2 control point.

addPolyline

public void addPolyline(java.util.Collection<java.awt.geom.Point2D.Double> points)
Adds a set of nodes to the path.

Convenience method for adding multiple nodes with a single control point C0.


set

public void set(int nodeIndex,
                int ctrlIndex,
                java.awt.geom.Point2D.Double p)
Convenience method for changing a single control point of a node.

Parameters:
nodeIndex - The index of the node.
ctrlIndex - Either C0_MASK, C1_MASK or C2_MASK.
p - The control point. The coordinates will be cloned.

get

public java.awt.geom.Point2D.Double get(int nodeIndex,
                                        int ctrlIndex)
Convenience method for getting a single control point of a node.

Parameters:
nodeIndex - The index of the node.
ctrlIndex - Either C0_MASK, C1_MASK or C2_MASK.
Returns:
Returns a clone of the control point.

invalidatePath

public void invalidatePath()
This must be called after the BezierPath has been changed.


validatePath

public void validatePath()
Recomputes the BezierPath, if it is invalid.


toGeneralPath

public java.awt.geom.Path2D.Double toGeneralPath()
Converts the BezierPath into a Path2D.Double.


contains

public boolean contains(java.awt.geom.Point2D p)
Specified by:
contains in interface java.awt.Shape

outlineContains

public boolean outlineContains(java.awt.geom.Point2D.Double p,
                               double tolerance)
Returns true, if the outline of this bezier path contains the specified point.

Parameters:
p - The point to be tested.
tolerance - The tolerance for the test.

intersects

public boolean intersects(java.awt.geom.Rectangle2D r)
Specified by:
intersects in interface java.awt.Shape

getPathIterator

public java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform at)
Specified by:
getPathIterator in interface java.awt.Shape

getPathIterator

public java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform at,
                                                  double flatness)
Specified by:
getPathIterator in interface java.awt.Shape

contains

public boolean contains(java.awt.geom.Rectangle2D r)
Specified by:
contains in interface java.awt.Shape

intersects

public boolean intersects(double x,
                          double y,
                          double w,
                          double h)
Specified by:
intersects in interface java.awt.Shape

getBounds2D

public java.awt.geom.Rectangle2D.Double getBounds2D()
Specified by:
getBounds2D in interface java.awt.Shape

getBounds

public java.awt.Rectangle getBounds()
Specified by:
getBounds in interface java.awt.Shape

contains

public boolean contains(double x,
                        double y,
                        double w,
                        double h)
Specified by:
contains in interface java.awt.Shape

contains

public boolean contains(double x,
                        double y)
Specified by:
contains in interface java.awt.Shape

setClosed

public void setClosed(boolean newValue)

isClosed

public boolean isClosed()

clone

public BezierPath clone()
Creates a deep copy of the BezierPath.

Overrides:
clone in class java.util.ArrayList<BezierPath.Node>

transform

public void transform(java.awt.geom.AffineTransform tx)
Transforms the BezierPath.

Parameters:
tx - the transformation.

setTo

public void setTo(BezierPath that)
Sets all values of this bezier path to that bezier path, so that this path becomes identical to that path.


getCenter

public java.awt.geom.Point2D.Double getCenter()
Returns the point at the center of the bezier path.


chop

public java.awt.geom.Point2D.Double chop(java.awt.geom.Point2D.Double p)
Returns a point on the edge of the bezier path which crosses the line from the center of the bezier path to the specified point. If no edge crosses the line, the nearest C0 control point is returned.


indexOfOutermostNode

public int indexOfOutermostNode()
Return the index of the node that is the furthest away from the center


getPointOnPath

Returns a relative point on the path. Where 0 is the start point of the path and 1 is the end point of the path.

Parameters:
relative - a value between 0 and 1.

getLengthOfPath

public double getLengthOfPath(double flatness)
Returns the length of the path.

Parameters:
flatness - the flatness used to approximate the length.

getRelativePositionOnPath

public double getRelativePositionOnPath(java.awt.geom.Point2D.Double find,
                                        double flatness)
Returns the relative position of the specified point on the path.

Parameters:
flatness - the flatness used to approximate the length.
Returns:
relative position on path, this is a number between 0 and 1. Returns -1, if the point is not on the path.

findSegment

public int findSegment(java.awt.geom.Point2D.Double find,
                       double tolerance)
Gets the segment of the polyline that is hit by the given Point2D.Double.

Returns:
the index of the segment or -1 if no segment was hit.

joinSegments

public int joinSegments(java.awt.geom.Point2D.Double join,
                        double tolerance)
Joins two segments into one if the given Point2D.Double hits a node of the bezier path.

Returns:
the index of the joined segment or -1 if no segment was joined.

splitSegment

public int splitSegment(java.awt.geom.Point2D.Double split,
                        double tolerance)
Splits the segment at the given Point2D.Double if a segment was hit.

Returns:
the index of the segment or -1 if no segment was hit.

moveTo

public void moveTo(double x1,
                   double y1)
Adds the first node to the bezier path.

This is a convenience method for adding the first node with a single control point C0 to the bezier path.


lineTo

public void lineTo(double x1,
                   double y1)
Adds a (at least) linear 'curve' to the bezier path.

If the previous node has no C2 control point the line will be straight (linear), otherwise the line will be quadratic.

This is a convenience method for adding a node with a single control point C0.

The bezier path must already have at least one node.


quadTo

public void quadTo(double x1,
                   double y1,
                   double x2,
                   double y2)
Adds a (at least) quadratic curve to the bezier path.

If the previous node has no C2 control point the line will be quadratic otherwise the line will be cubic.

This is a convenience method for adding a node with control point C0 and C1 (incoming curve) to the bezier path.

The bezier path must already have at least one node.


curveTo

public void curveTo(double x1,
                    double y1,
                    double x2,
                    double y2,
                    double x3,
                    double y3)
Adds a cubic curve to the bezier path.

This is a convenience method for adding a node with control point C0 and C1 (incoming curve) to the bezier path, and also specifying the control point C2 (outgoing curve) of the previous node.

The bezier path must already have at least one node.


arcTo

public void arcTo(double rx,
                  double ry,
                  double xAxisRotation,
                  boolean largeArcFlag,
                  boolean sweepFlag,
                  double x,
                  double y)
Adds an elliptical arc, defined by two radii, an angle from the x-axis, a flag to choose the large arc or not, a flag to indicate if we increase or decrease the angles and the final point of the arc.

As specified in http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands

The implementation of this method has been derived from Apache Batik class org.apache.batik.ext.awt.geom.ExtendedGeneralPath#computArc

Parameters:
rx - the x radius of the ellipse
ry - the y radius of the ellipse
xAxisRotation - the angle from the x-axis of the current coordinate system to the x-axis of the ellipse in degrees.
largeArcFlag - the large arc flag. If true the arc spanning less than or equal to 180 degrees is chosen, otherwise the arc spanning greater than 180 degrees is chosen
sweepFlag - the sweep flag. If true the line joining center to arc sweeps through decreasing angles otherwise it sweeps through increasing angles
x - the absolute x coordinate of the final point of the arc.
y - the absolute y coordinate of the final point of the arc.

toPolygonArray

public java.awt.geom.Point2D.Double[] toPolygonArray()
Creates a polygon/polyline array of the bezier path which only includes the C0 control points of the bezier nodes.

If the bezier path is closed, the array describes a polygon. If the bezier path is open, the array describes a polyline.

Returns:
Point array.

setWindingRule

public void setWindingRule(int newValue)
Sets winding rule for filling the bezier path.

Parameters:
newValue - Must be Path2D.Double.WIND_EVEN_ODD or Path2D.Double.WIND_NON_ZERO.

getWindingRule

public int getWindingRule()
Gets winding rule for filling the bezier path.

Returns:
Path2D.Double.WIND_EVEN_ODD or Path2D.Double.WIND_NON_ZERO.