diff --git a/Readme.txt b/Readme.txt
index 6a8ba9f..e0266cb 100644
--- a/Readme.txt
+++ b/Readme.txt
@@ -10,11 +10,11 @@
 REQUIREMENTS
 
 To run Piccolo2D.Java applications you need to have a Java Runtime
-Environment (JRE) or Java Development Kit (JDK) version 1.4 or newer.
+Environment (JRE) or Java Development Kit (JDK) version 1.6 or newer.
 
 To build Piccolo2D.Java you need to have a Java Runtime Environment
-(JRE) or Java Development Kit (JDK) version 1.5 or newer, and Apache
-Maven version 2.0.10 or newer.
+(JRE) or Java Development Kit (JDK) version 1.6 or newer, and Apache
+Maven version 3.0.5 or newer.
 
 Java Runtime Environment (JRE)
 http://java.sun.com/javase/downloads/index.jsp#jre
@@ -46,7 +46,7 @@
 area property change listeners will not be notified.
+     *
+     * @return the area backing this area node
+     */
+    public Area getAreaReference() {
+        return area;
+    }
+
+    /**
+     * Add the shape of the specified area to the shape of this area node.
+     * The resulting shape of this area node will include the union of both shapes,
+     * or all areas that were contained in either this or the specified area.
+     *
+     * @param area area to add, must not be null
+     * @throws NullPointerException if area is null
+     */
+    public void add(final Area area) {
+        Area oldArea = (Area) this.area.clone();
+        this.area.add(area);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "area", oldArea, getArea());
+    }
+
+    /**
+     * Set the shape of this area node to be the combined area of its current
+     * shape and the shape of the specified area, minus their intersection. The
+     * resulting shape of this area node will include only areas that were contained
+     * in either this area node or in the specified area, but not in both. 
+     *
+     * @param area area to exclusive or, must not be null
+     * @throws NullPointerException if area is null
+     */
+    public void exclusiveOr(final Area area) {
+        Area oldArea = (Area) this.area.clone();
+        this.area.exclusiveOr(area);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "area", oldArea, getArea());
+    }
+
+    /**
+     * Set the shape of this area node to the intersection of its current shape
+     * and the shape of the specified area. The resulting shape of this area node
+     * will include only areas that were contained in both this area node and also
+     * in the specified area.
+     *
+     * @param area area to intersect, must not be null
+     * @throws NullPointerException if area is null
+     */
+    public void intersect(final Area area) {
+        Area oldArea = (Area) this.area.clone();
+        this.area.intersect(area);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "area", oldArea, getArea());
+    }
+
+    /**
+     * Subtract the shape of the specified area from the shape of this area node.
+     * The resulting shape of this area node will include areas that were contained
+     * only in this area node and not in the specified area.
+     *
+     * @param area area to subtract, must not be null
+     * @throws NullPointerException if area is null
+     */
+    public void subtract(final Area area) {
+        Area oldArea = (Area) this.area.clone();
+        this.area.subtract(area);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "area", oldArea, getArea());
+    }
+
+    /**
+     * Removes all of the geometry from this area node and restores it to an empty area.
+     */
+    public void reset() {
+        Area oldArea = (Area) area.clone();
+        area.reset();
+        updateBoundsFromShape();
+        firePropertyChange(-1, "area", oldArea, getArea());
+    }
+
+    /**
+     * Return true if this area node represents an empty area.
+     *
+     * @return true if this area node represents an empty area
+     */
+    public boolean isEmpty() {
+        return area.isEmpty();
+    }
+
+    /**
+     * Return true if this area node consists entirely of straight-edged polygonal geometry.
+     *
+     * @return true if this area node consists entirely of straight-edged polygonal geometry
+     */
+    public boolean isPolygonal() {
+        return area.isPolygonal();
+    }
+
+    /**
+     * Return true if this area node is rectangular in shape.
+     *
+     * @return true if this area node is rectangular in shape
+     */
+    public boolean isRectangular() {
+        return area.isRectangular();
+    }
+
+    /**
+     * Return true if this area node 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
+     * SEG_MOVETO segments that appear in the path. 
+     *
+     * @return true if this area node is comprised of a single closed subpath
+     */
+    public boolean isSingular() {
+        return area.isSingular();
+    }
+
+    // todo:
+    //    should modifiers return this to allow chaining, e.g. add(area0).intersect(area1)
+    //    test serialization, may have to add custom code to serialize areas
+
+    /** {@inheritDoc} */
+    protected Shape getShape() {
+        return area;
+    }
+
+    /** {@inheritDoc} */
+    protected void transform(final AffineTransform transform) {
+        area.transform(transform);
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/piccolo2d/nodes/PPath.java b/core/src/main/java/org/piccolo2d/nodes/PPath.java
index 08d4052..7cea604 100644
--- a/core/src/main/java/org/piccolo2d/nodes/PPath.java
+++ b/core/src/main/java/org/piccolo2d/nodes/PPath.java
@@ -1,666 +1,671 @@
-/*
- * Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.nodes;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Paint;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-import org.piccolo2d.PNode;
-import org.piccolo2d.util.PAffineTransform;
-import org.piccolo2d.util.PPaintContext;
-import org.piccolo2d.util.PUtil;
-
-
-/**
- * PPath is a wrapper around a java.awt.geom.GeneralPath. The setBounds
- * method works by scaling the path to fit into the specified bounds. This
- * normally works well, but if the specified base bounds get too small then it
- * is impossible to expand the path shape again since all its numbers have
- * tended to zero, so application code may need to take this into consideration.
- * 
- * One option that applications have is to call startResizeBounds
- * before starting an interaction that may make the bounds very small, and
- * calling endResizeBounds when this interaction is finished. When
- * this is done PPath will use a copy of the original path to do the resizing so
- * the numbers in the path wont loose resolution.
- * 
- * This class also provides methods for constructing common shapes using a - * general path. - *
- * 
- * @version 1.0
- * @author Jesse Grosjean
- */
-public class PPath extends PNode {
-
-    /**
-     * Allows for future serialization code to understand versioned binary
-     * formats.
-     */
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * The property name that identifies a change of this node's stroke paint
-     * (see {@link #getStrokePaint getStrokePaint}). Both old and new value will
-     * be set correctly to Paint objects in any property change event.
-     */
-    public static final String PROPERTY_STROKE_PAINT = "strokePaint";
-
-    /**
-     * The property code that identifies a change of this node's stroke paint
-     * (see {@link #getStrokePaint getStrokePaint}). Both old and new value will
-     * be set correctly to Paint objects in any property change event.
-     */
-    public static final int PROPERTY_CODE_STROKE_PAINT = 1 << 16;
-
-    /**
-     * The property name that identifies a change of this node's stroke (see
-     * {@link #getStroke getStroke}). Both old and new value will be set
-     * correctly to Stroke objects in any property change event.
-     */
-    public static final String PROPERTY_STROKE = "stroke";
-
-    /**
-     * The property code that identifies a change of this node's stroke (see
-     * {@link #getStroke getStroke}). Both old and new value will be set
-     * correctly to Stroke objects in any property change event.
-     */
-    public static final int PROPERTY_CODE_STROKE = 1 << 17;
-
-    /**
-     * The property name that identifies a change of this node's path (see
-     * {@link #getPathReference getPathReference}). In any property change event
-     * the new value will be a reference to this node's path, but old value will
-     * always be null.
-     */
-    public static final String PROPERTY_PATH = "path";
-
-    /**
-     * The property code that identifies a change of this node's path (see
-     * {@link #getPathReference getPathReference}). In any property change event
-     * the new value will be a reference to this node's path, but old value will
-     * always be null.
-     */
-    public static final int PROPERTY_CODE_PATH = 1 << 18;
-
-    private static final Rectangle2D.Float TEMP_RECTANGLE = new Rectangle2D.Float();
-    private static final RoundRectangle2D.Float TEMP_ROUNDRECTANGLE = new RoundRectangle2D.Float();
-    private static final Ellipse2D.Float TEMP_ELLIPSE = new Ellipse2D.Float();
-    private static final PAffineTransform TEMP_TRANSFORM = new PAffineTransform();
-    private static final BasicStroke DEFAULT_STROKE = new BasicStroke(1.0f);
-    private static final Color DEFAULT_STROKE_PAINT = Color.black;
-
-    private transient GeneralPath path;
-    private transient GeneralPath resizePath;
-    private transient Stroke stroke;
-    private transient boolean updatingBoundsFromPath;
-    private Paint strokePaint;
-
-    /**
-     * Creates a PPath object in the shape of a rectangle.
-     * 
-     * @param x left of the rectangle
-     * @param y top of the rectangle
-     * @param width width of the rectangle
-     * @param height height of the rectangle
-     * 
-     * @return created rectangle
-     */
-    public static PPath createRectangle(final float x, final float y, final float width, final float height) {
-        TEMP_RECTANGLE.setFrame(x, y, width, height);
-        final PPath result = new PPath(TEMP_RECTANGLE);
-        result.setPaint(Color.white);
-        return result;
-    }
-
-    /**
-     * Creates a PPath object in the shape of a rounded rectangle.
-     * 
-     * @param x left of the rectangle
-     * @param y top of the rectangle
-     * @param width width of the rectangle
-     * @param height height of the rectangle
-     * @param arcWidth the arc width at the corners of the rectangle
-     * @param arcHeight the arc height at the corners of the rectangle
-     * 
-     * @return created rounded rectangle
-     */
-    public static PPath createRoundRectangle(final float x, final float y, final float width, final float height,
-            final float arcWidth, final float arcHeight) {
-        TEMP_ROUNDRECTANGLE.setRoundRect(x, y, width, height, arcWidth, arcHeight);
-        final PPath result = new PPath(TEMP_ROUNDRECTANGLE);
-        result.setPaint(Color.white);
-        return result;
-    }
-
-    /**
-     * Creates a PPath object in the shape of an ellipse.
-     * 
-     * @param x left of the ellipse
-     * @param y top of the ellipse
-     * @param width width of the ellipse
-     * @param height height of the ellipse
-     * 
-     * @return created ellipse
-     */
-    public static PPath createEllipse(final float x, final float y, final float width, final float height) {
-        TEMP_ELLIPSE.setFrame(x, y, width, height);
-        final PPath result = new PPath(TEMP_ELLIPSE);
-        result.setPaint(Color.white);
-        return result;
-    }
-
-    /**
-     * Creates a PPath in the shape of a line.
-     * 
-     * @param x1 x component of the first point
-     * @param y1 y component of the first point
-     * @param x2 x component of the second point
-     * @param y2 y component of the second point
-     * 
-     * @return created line
-     */
-    public static PPath createLine(final float x1, final float y1, final float x2, final float y2) {
-        final PPath result = new PPath();
-        result.moveTo(x1, y1);
-        result.lineTo(x2, y2);
-        result.setPaint(Color.white);
-        return result;
-    }
-
-    /**
-     * Creates a PPath for the poly-line for the given points.
-     * 
-     * @param points array of points for the point lines
-     * 
-     * @return created poly-line for the given points
-     */
-    public static PPath createPolyline(final Point2D[] points) {
-        final PPath result = new PPath();
-        result.setPathToPolyline(points);
-        result.setPaint(Color.white);
-        return result;
-    }
-
-    /**
-     * Creates a PPath for the poly-line for the given points.
-     * 
-     * @param xp array of x components of the points of the poly-lines
-     * @param yp array of y components of the points of the poly-lines
-     * 
-     * @return created poly-line for the given points
-     */
-    public static PPath createPolyline(final float[] xp, final float[] yp) {
-        final PPath result = new PPath();
-        result.setPathToPolyline(xp, yp);
-        result.setPaint(Color.white);
-        return result;
-    }
-
-    /**
-     * Creates an empty PPath with the default paint and stroke.
-     */
-    public PPath() {
-        strokePaint = DEFAULT_STROKE_PAINT;
-        stroke = DEFAULT_STROKE;
-        path = new GeneralPath();
-    }
-
-    /**
-     * Creates an PPath in the given shape with the default paint and stroke.
-     * 
-     * @param aShape the desired shape
-     */
-    public PPath(final Shape aShape) {
-        this(aShape, DEFAULT_STROKE);
-    }
-
-    /**
-     * Construct this path with the given shape and stroke. This method may be
-     * used to optimize the creation of a large number of PPaths. Normally
-     * PPaths have a default stroke of width one, but when a path has a non null
-     * stroke it takes significantly longer to compute its bounds. This method
-     * allows you to override that default stroke before the bounds are ever
-     * calculated, so if you pass in a null stroke here you won't ever have to
-     * pay that bounds calculation price if you don't need to.
-     * 
-     * @param aShape desired shape or null if you desire an empty path
-     * @param aStroke desired stroke
-     */
-    public PPath(final Shape aShape, final Stroke aStroke) {
-        this();
-        stroke = aStroke;
-        if (aShape != null) {
-            append(aShape, false);
-        }
-    }
-
-    /**
-     * Returns the stroke paint of the PPath.
-     * 
-     * @return stroke paint of the PPath
-     */
-    public Paint getStrokePaint() {
-        return strokePaint;
-    }
-
-    /**
-     * Sets the stroke paint of the path.
-     * 
-     * @param newStrokePaint the paint to use as this path's stroke paint
-     */
-    public void setStrokePaint(final Paint newStrokePaint) {
-        final Paint oldStrokePaint = strokePaint;
-        strokePaint = newStrokePaint;
-        invalidatePaint();
-        firePropertyChange(PROPERTY_CODE_STROKE_PAINT, PROPERTY_STROKE_PAINT, oldStrokePaint, strokePaint);
-    }
-
-    /**
-     * Returns the stroke to use when drawing the path.
-     * 
-     * @return current stroke of path
-     */
-    public Stroke getStroke() {
-        return stroke;
-    }
-
-    /**
-     * Sets the stroke to use when drawing the path.
-     * 
-     * @param aStroke stroke to use when drawing the path
-     */
-    public void setStroke(final Stroke aStroke) {
-        final Stroke old = stroke;
-        stroke = aStroke;
-        updateBoundsFromPath();
-        invalidatePaint();
-        firePropertyChange(PROPERTY_CODE_STROKE, PROPERTY_STROKE, old, stroke);
-    }
-
-    /** Stores the original size of the path before resizing started. */
-    public void startResizeBounds() {
-        resizePath = new GeneralPath(path);
-    }
-
-    /** Clears the size of the path before resizing. */
-    public void endResizeBounds() {
-        resizePath = null;
-    }
-
-    /**
-     * Set the bounds of this path. This method works by scaling the path to fit
-     * into the specified bounds. This normally works well, but if the specified
-     * base bounds get too small then it is impossible to expand the path shape
-     * again since all its numbers have tended to zero, so application code may
-     * need to take this into consideration.
-     * 
-     * @param x new left position of bounds
-     * @param y new top position of bounds
-     * @param width the new width of the bounds
-     * @param height the new height of the bounds
-     */
-    protected void internalUpdateBounds(final double x, final double y, final double width, final double height) {
-        if (updatingBoundsFromPath || path == null) {
-            return;
-        }
-
-        if (resizePath != null) {
-            path.reset();
-            path.append(resizePath, false);
-        }
-
-        final Rectangle2D pathBounds = path.getBounds2D();
-        final Rectangle2D pathStrokeBounds = getPathBoundsWithStroke();
-        final double strokeOutset = Math.max(pathStrokeBounds.getWidth() - pathBounds.getWidth(), pathStrokeBounds
-                .getHeight()
-                - pathBounds.getHeight());
-
-        double adjustedX = x + strokeOutset / 2;
-        double adjustedY = y + strokeOutset / 2;
-        double adjustedWidth = width - strokeOutset;
-        double adjustedHeight = height - strokeOutset;
-
-        final double scaleX;
-        if (adjustedWidth == 0 || pathBounds.getWidth() == 0) {
-            scaleX = 1;
-        }
-        else {
-            scaleX = adjustedWidth / pathBounds.getWidth();
-        }
-
-        final double scaleY;
-        if (adjustedHeight == 0 || pathBounds.getHeight() == 0) {
-            scaleY = 1;
-        }
-        else {
-            scaleY = adjustedHeight / pathBounds.getHeight();
-        }
-
-        TEMP_TRANSFORM.setToIdentity();
-        TEMP_TRANSFORM.translate(adjustedX, adjustedY);
-        TEMP_TRANSFORM.scale(scaleX, scaleY);
-        TEMP_TRANSFORM.translate(-pathBounds.getX(), -pathBounds.getY());
-
-        path.transform(TEMP_TRANSFORM);
-    }
-
-    /**
-     * Returns true if path crosses the provided bounds. Takes visibility of
-     * path into account.
-     * 
-     * @param aBounds bounds being tested for intersection
-     * @return true if path visibly crosses bounds
-     */
-    public boolean intersects(final Rectangle2D aBounds) {
-        if (super.intersects(aBounds)) {
-            if (getPaint() != null && path.intersects(aBounds)) {
-                return true;
-            }
-            else if (stroke != null && strokePaint != null) {
-                return stroke.createStrokedShape(path).intersects(aBounds);
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Calculates the path's bounds taking stroke into account.
-     * 
-     * @return bounds of the path taking stroke width into account
-     */
-    public Rectangle2D getPathBoundsWithStroke() {
-        if (stroke != null) {
-            return stroke.createStrokedShape(path).getBounds2D();
-        }
-        else {
-            return path.getBounds2D();
-        }
-    }
-
-    /**
-     * Recomputes the bounds taking stroke into account.
-     */
-    public void updateBoundsFromPath() {
-        updatingBoundsFromPath = true;
-        if (path == null) {
-            resetBounds();
-        }
-        else {
-            final Rectangle2D b = getPathBoundsWithStroke();
-            setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight());
-        }
-        updatingBoundsFromPath = false;
-    }
-
-    /**
-     * Paints the path in the provided paintContext. Can perform very
-     * differently depending on whether the path is being drawn using its stroke
-     * or its paint.
-     * 
-     * It both are provided to the path, fun ensues.
-     * 
-     * @param paintContext context in which painting is occurring
-     */
-    protected void paint(final PPaintContext paintContext) {
-        final Paint p = getPaint();
-        final Graphics2D g2 = paintContext.getGraphics();
-
-        if (p != null) {
-            g2.setPaint(p);
-            g2.fill(path);
-        }
-
-        if (stroke != null && strokePaint != null) {
-            g2.setPaint(strokePaint);
-            g2.setStroke(stroke);
-            g2.draw(path);
-        }
-    }
-
-    /**
-     * Provides direct access to the underlying GeneralPath object.
-     * 
-     * @return underlying GeneralPath
-     */
-    public GeneralPath getPathReference() {
-        return path;
-    }
-
-    /**
-     * Appends a "move" operation to the end of the path.
-     * 
-     * @param x the x component of the point to move to
-     * @param y the y component of the point to move to
-     */
-    public void moveTo(final float x, final float y) {
-        path.moveTo(x, y);
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Draws a line from the last point in the path to point provided.
-     * 
-     * @param x the x component of the point
-     * @param y the y component of the point
-     */
-    public void lineTo(final float x, final float y) {
-        path.lineTo(x, y);
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * 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 x component of quadratic parametric control point
-     * @param y1 y component of quadratic parametric control point
-     * @param x2 x component of point through which quad curve will pass
-     * @param y2 y component of point through which quad curve will pass
-     */
-    public void quadTo(final float x1, final float y1, final float x2, final float y2) {
-        path.quadTo(x1, y1, x2, y2);
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * 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 x component of first Bézier control point
-     * @param y1 y component of first Bézier control point
-     * @param x2 x component of second Bézier control point
-     * @param y2 y component of second Bézier control point
-     * @param x3 x component of point through which curve must pass
-     * @param y3 y component of point through which curve must pass
-     */
-    public void curveTo(final float x1, final float y1, final float x2, final float y2,
-            final float x3, final float y3) {
-        path.curveTo(x1, y1, x2, y2, x3, y3);
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Appends the provided shape to the end of this path, it may conditionally
-     * connect them together if they are disjoint.
-     * 
-     * @param aShape shape to append
-     * @param connect whether to perform a lineTo operation to the beginning of
-     *            the shape before appending
-     */
-    public void append(final Shape aShape, final boolean connect) {
-        path.append(aShape, connect);
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Replaces this PPath's path with the one provided.
-     * 
-     * @param aShape shape to replace the current one with
-     */
-    public void setPathTo(final Shape aShape) {
-        path.reset();
-        append(aShape, false);
-    }
-
-    /**
-     * Resets the path to a rectangle with the dimensions and position provided.
-     * 
-     * @param x left of the rectangle
-     * @param y top of te rectangle
-     * @param width width of the rectangle
-     * @param height height of the rectangle
-     */
-    public void setPathToRectangle(final float x, final float y, final float width, final float height) {
-        TEMP_RECTANGLE.setFrame(x, y, width, height);
-        setPathTo(TEMP_RECTANGLE);
-    }
-
-    /**
-     * Resets the path to an ellipse positioned at the coordinate provided with
-     * the dimensions provided.
-     * 
-     * @param x left of the ellipse
-     * @param y top of the ellipse
-     * @param width width of the ellipse
-     * @param height height of the ellipse
-     */
-    public void setPathToEllipse(final float x, final float y, final float width, final float height) {
-        TEMP_ELLIPSE.setFrame(x, y, width, height);
-        setPathTo(TEMP_ELLIPSE);
-    }
-
-    /**
-     * Sets the path to a sequence of segments described by the points.
-     * 
-     * @param points points to that lie along the generated path
-     */
-    public void setPathToPolyline(final Point2D[] points) {
-        path.reset();
-        path.moveTo((float) points[0].getX(), (float) points[0].getY());
-        for (int i = 1; i < points.length; i++) {
-            path.lineTo((float) points[i].getX(), (float) points[i].getY());
-        }
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Sets the path to a sequence of segments described by the point components
-     * provided.
-     * 
-     * @param xp the x components of the points along the path
-     * @param yp the y components of the points along the path
-     */
-    public void setPathToPolyline(final float[] xp, final float[] yp) {
-        path.reset();
-        path.moveTo(xp[0], yp[0]);
-        for (int i = 1; i < xp.length; i++) {
-            path.lineTo(xp[i], yp[i]);
-        }
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Marks the path as closed. Making changes to it impossible.
-     */
-    public void closePath() {
-        path.closePath();
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Empties the path.
-     */
-    public void reset() {
-        path.reset();
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
-    }
-
-    /**
-     * Writes this PPath object to the output stream provided. Necessary since
-     * stroke and path are not serializable by default.
-     * 
-     * @param out output stream into which objects are to be serialized
-     * @throws IOException if serialiazing to output stream fails
-     */
-    private void writeObject(final ObjectOutputStream out) throws IOException {
-        out.defaultWriteObject();
-        PUtil.writeStroke(stroke, out);
-        PUtil.writePath(path, out);
-    }
-
-    /**
-     * Deserializes a PPath object from the provided input stream. This method
-     * is required since Strokes and GeneralPaths are not serializable by
-     * default.
-     * 
-     * @param in stream from which to read this PPath's state
-     * @throws IOException when exception occurs reading from input stream
-     * @throws ClassNotFoundException
-     */
-    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
-        in.defaultReadObject();
-        stroke = PUtil.readStroke(in);
-        path = PUtil.readPath(in);
-    }
-}
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.Shape;
+import java.awt.Stroke;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.geom.PathIterator;
+
+/**
+ * Abstract path node.
+ */
+public abstract class PPath extends PShape {
+
+    /** Path for this path node. */
+    private final Path2D path;
+
+
+    /**
+     * Create a new path node with the specified path.
+     *
+     * @param path path
+     */
+    private PPath(final Path2D path) {
+        this.path = (Path2D) path.clone();
+        updateBoundsFromShape();
+    }
+
+    /**
+     * Create a new path node with the specified path and stroke.
+     *
+     * @param path path
+     * @param stroke stroke
+     */
+    private PPath(final Path2D path, final Stroke stroke) {
+        this.path = (Path2D) path.clone();
+        setStroke(stroke);
+    }
+
+
+    /**
+     * Path node with coordinates stored in single precision floating point.
+     */
+    public static class Float extends PPath {
+
+        /**
+         * Create a new empty path node.
+         */
+        public Float() {
+            super(new Path2D.Float());
+        }
+
+        /**
+         * Create a new empty path node with the specified stroke.
+         *
+         * @param stroke stroke
+         */
+        public Float(final Stroke stroke) {
+            super(new Path2D.Float(), stroke);
+        }
+
+        /**
+         * Create a new path node with the specified shape.
+         *
+         * @param shape shape, must not be null
+         * @throws NullPointerException if shape is null
+         */
+        public Float(final Shape shape) {
+            super(new Path2D.Float(shape));
+        }
+
+        /**
+         * Create a new path node with the specified shape and stroke.
+         *
+         * @param shape shape, must not be null
+         * @param stroke stroke
+         * @throws NullPointerException if shape is null
+         */
+        public Float(final Shape shape, final Stroke stroke) {
+            super(new Path2D.Float(shape), stroke);
+        }
+
+        /**
+         * Create a new path node with the specified path.
+         *
+         * @param path path, must not be null
+         * @throws NullPointerException if path is null
+         */
+        public Float(final Path2D.Float path) {
+            super(path);
+        }
+
+        /**
+         * Create a new path node with the specified path and stroke.
+         *
+         * @param path path, must not be null
+         * @param stroke stroke, must not be null
+         * @throws NullPointerException if path is null
+         */
+        public Float(final Path2D.Float path, final Stroke stroke) {
+            super(path, stroke);
+        }
+    }
+
+    /**
+     * Path node with coordinates stored in double precision floating point.
+     */
+    public static class Double extends PPath {
+
+        /**
+         * Create a new empty path node.
+         */
+        public Double() {
+            super(new Path2D.Double());
+        }
+
+        /**
+         * Create a new empty path node with the specified stroke.
+         *
+         * @param stroke stroke
+         */
+        public Double(final Stroke stroke) {
+            super(new Path2D.Double(), stroke);
+        }
+
+        /**
+         * Create a new path node with the specified shape.
+         *
+         * @param shape shape, must not be null
+         * @throws NullPointerException if shape is null
+         */
+        public Double(final Shape shape) {
+            super(new Path2D.Double(shape));
+        }
+
+        /**
+         * Create a new path node with the specified shape and stroke.
+         *
+         * @param shape shape, must not be null
+         * @param stroke stroke
+         * @throws NullPointerException if shape is null
+         */
+        public Double(final Shape shape, final Stroke stroke) {
+            super(new Path2D.Double(shape), stroke);
+        }
+
+        /**
+         * Create a new path node with the specified path.
+         *
+         * @param path path, must not be null
+         * @throws NullPointerException if path is null
+         */
+        public Double(final Path2D.Double path) {
+            super(path);
+        }
+
+        /**
+         * Create a new path node with the specified path and stroke.
+         *
+         * @param path path, must not be null
+         * @param stroke stroke
+         * @throws NullPointerException if path is null
+         */
+        public Double(final Path2D.Double path, final Stroke stroke) {
+            super(path, stroke);
+        }
+    }
+
+
+    /**
+     * Create and return a new path node with the specified arc in single
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate of the upper-left corner of the arc's framing rectangle
+     * @param y y coordinate of the upper-left corner of the arc's framing rectangle
+     * @param width width of the full ellipse of which this arc is a partial section
+     * @param height height of the full ellipse of which this arc is a partial section
+     * @param start starting angle of the arc in degrees
+     * @param extent angular extent of the arc in degrees
+     * @param type closure type for the arc, one of {@link Arc2D#OPEN}, {@link Arc2D#CHORD},
+     *    or {@link Arc2D#PIE}
+     * @return a new path node with the specified arc in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createArc(final float x,
+                                        final float y,
+                                        final float width,
+                                        final float height,
+                                        final float start,
+                                        final float extent,
+                                        final int type) {
+        return new PPath.Float(new Arc2D.Float(x, y, width, height, start, extent, type));
+    }
+
+    /**
+     * Create and return a new path node with the specified cubic curve in single
+     * precision floating point coordinates.
+     *
+     * @param x1 x coordinate of the start point
+     * @param y1 y coordinate of the start point
+     * @param ctrlx1 x coordinate of the first control point
+     * @param ctrly1 y coordinate of the first control point
+     * @param ctrlx2 x coordinate of the second control point
+     * @param ctrly2 y coordinate of the second control point
+     * @param x2 x coordinate of the end point
+     * @param y2 y coordinate of the end point
+     * @return a new path node with the specified cubic curve in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createCubicCurve(final float x1,
+                                               final float y1,
+                                               final float ctrlx1,
+                                               final float ctrly1,
+                                               final float ctrlx2,
+                                               final float ctrly2,
+                                               final float x2,
+                                               final float y2) {
+        return new PPath.Float(new CubicCurve2D.Float(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
+    }
+
+    /**
+     * Create and return a new path node with the specified ellipse in single
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @param width width
+     * @param height height
+     * @return a new path node with the specified ellipse in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createEllipse(final float x, final float y, final float width, final float height) {
+        return new PPath.Float(new Ellipse2D.Float(x, y, width, height));
+    }
+
+    /**
+     * Create and return a new path node with the specified line in single
+     * precision floating point coordinates.
+     *
+     * @param x1 x coordinate of the start point
+     * @param y1 y coordinate of the start point
+     * @param x2 x coordinate of the end point
+     * @param y2 y coordinate of the end point
+     * @return a new path node with the specified line in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createLine(final float x1, final float y1, final float x2, final float y2) {
+        return new PPath.Float(new Line2D.Float(x1, y1, x2, y2));
+    }
+
+    /*
+      need setPathToPolyline
+    public static final PPath createPolyline(final float[] xp, final float[] yp) {
+    }
+
+    public static final PPath createPolyline(final Point2D.Float[] points) {
+    }
+    */
+
+    /**
+     * Create and return a new path node with the specified quadratic curve in single
+     * precision floating point coordinates.
+     *
+     * @param x1 x coordinate of the start point
+     * @param y1 y coordinate of the start point
+     * @param ctrlx x coordinate of the control point
+     * @param ctrly y coordinate of the control point
+     * @param x2 x coordinate of the end point
+     * @param y2 y coordinate of the end point
+     * @return a new path node with the specified quadratic curve in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createQuadCurve(final float x1,
+                                              final float y1,
+                                              final float ctrlx,
+                                              final float ctrly,
+                                              final float x2,
+                                              final float y2) {
+        return new PPath.Float(new QuadCurve2D.Float(x1, y1, ctrlx, ctrly, x2, y2));
+    }
+
+    /**
+     * Create and return a new path node with the specified rectangle in single
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @param width width
+     * @param height height
+     * @return a new path node with the specified rectangle in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createRectangle(final float x, final float y, final float width, final float height) {
+        return new PPath.Float(new Rectangle2D.Float(x, y, width, height));
+    }
+
+    /**
+     * Create and return a new path node with the specified round rectangle in single
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @param width width
+     * @param height height
+     * @param arcWidth width of the arc that rounds off the corners
+     * @param arcHeight height of the arc that rounds off the corners
+     * @return a new path node with the specified round rectangle in single
+     *    precision floating point coordinates
+     */
+    public static final PPath createRoundRectangle(final float x,
+                                                   final float y,
+                                                   final float width,
+                                                   final float height,
+                                                   final float arcWidth,
+                                                   final float arcHeight) {
+        return new PPath.Float(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+    }
+
+    /**
+     * Create and return a new path node with the specified arc in double
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate of the upper-left corner of the arc's framing rectangle
+     * @param y y coordinate of the upper-left corner of the arc's framing rectangle
+     * @param width width of the full ellipse of which this arc is a partial section
+     * @param height height of the full ellipse of which this arc is a partial section
+     * @param start starting angle of the arc in degrees
+     * @param extent angular extent of the arc in degrees
+     * @param type closure type for the arc, one of {@link Arc2D#OPEN}, {@link Arc2D#CHORD},
+     *    or {@link Arc2D#PIE}
+     * @return a new path node with the specified arc in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createArc(final double x,
+                                        final double y,
+                                        final double width,
+                                        final double height,
+                                        final double start,
+                                        final double extent,
+                                        final int type) {
+        return new PPath.Double(new Arc2D.Double(x, y, width, height, start, extent, type));
+    }
+
+    /**
+     * Create and return a new path node with the specified cubic curve in double
+     * precision floating point coordinates.
+     *
+     * @param x1 x coordinate of the start point
+     * @param y1 y coordinate of the start point
+     * @param ctrlx1 x coordinate of the first control point
+     * @param ctrly1 y coordinate of the first control point
+     * @param ctrlx2 x coordinate of the second control point
+     * @param ctrly2 y coordinate of the second control point
+     * @param x2 x coordinate of the end point
+     * @param y2 y coordinate of the end point
+     * @return a new path node with the specified cubic curve in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createCubicCurve(final double x1,
+                                               final double y1,
+                                               final double ctrlx1,
+                                               final double ctrly1,
+                                               final double ctrlx2,
+                                               final double ctrly2,
+                                               final double x2,
+                                               final double y2) {
+        return new PPath.Double(new CubicCurve2D.Double(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
+    }
+
+    /**
+     * Create and return a new path node with the specified ellipse in double
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @param width width
+     * @param height height
+     * @return a new path node with the specified ellipse in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createEllipse(final double x, final double y, final double width, final double height) {
+        return new PPath.Double(new Ellipse2D.Double(x, y, width, height));
+    }
+
+    /**
+     * Create and return a new path node with the specified line in double
+     * precision floating point coordinates.
+     *
+     * @param x1 x coordinate of the start point
+     * @param y1 y coordinate of the start point
+     * @param x2 x coordinate of the end point
+     * @param y2 y coordinate of the end point
+     * @return a new path node with the specified line in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createLine(final double x1, final double y1, final double x2, final double y2) {
+        return new PPath.Double(new Line2D.Double(x1, y1, x2, y2));
+    }
+
+    /*
+    public static final PPath createPolyline(final double[] xp, final double[] yp) {
+    }
+
+    public static final PPath createPolyline(final Point2D.Double[] points) {
+    }
+    */
+
+    /**
+     * Create and return a new path node with the specified quadratic curve in double
+     * precision floating point coordinates.
+     *
+     * @param x1 x coordinate of the start point
+     * @param y1 y coordinate of the start point
+     * @param ctrlx x coordinate of the control point
+     * @param ctrly y coordinate of the control point
+     * @param x2 x coordinate of the end point
+     * @param y2 y coordinate of the end point
+     * @return a new path node with the specified quadratic curve in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createQuadCurve(final double x1,
+                                              final double y1,
+                                              final double ctrlx,
+                                              final double ctrly,
+                                              final double x2,
+                                              final double y2) {
+        return new PPath.Double(new QuadCurve2D.Double(x1, y1, ctrlx, ctrly, x2, y2));
+    }
+
+    /**
+     * Create and return a new path node with the specified rectangle in double
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @param width width
+     * @param height height
+     * @return a new path node with the specified rectangle in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createRectangle(final double x, final double y, final double width, final double height) {
+        return new PPath.Double(new Rectangle2D.Double(x, y, width, height));
+    }
+
+    /**
+     * Create and return a new path node with the specified round rectangle in double
+     * precision floating point coordinates.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @param width width
+     * @param height height
+     * @param arcWidth width of the arc that rounds off the corners
+     * @param arcHeight height of the arc that rounds off the corners
+     * @return a new path node with the specified round rectangle in double
+     *    precision floating point coordinates
+     */
+    public static final PPath createRoundRectangle(final double x,
+                                                   final double y,
+                                                   final double width,
+                                                   final double height,
+                                                   final double arcWidth,
+                                                   final double arcHeight) {
+        return new PPath.Double(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
+    }
+
+
+    /**
+     * Return a copy of the path backing this path node.
+     *
+     * @return a copy of the path backing this path node
+     */
+    public final Path2D getPath() {
+        return (Path2D) path.clone();
+    }
+
+    /**
+     * Return the path backing this node.  The returned path must not be
+     * modified or the bounds of this node may no longer be valid and any
+     * path property change listeners will not be notified.
+     *
+     * @return the path backing this path node
+     */
+    public final Path2D getPathReference() {
+        return path;
+    }
+
+    /**
+     * Append the geometry of the specified shape to this path node, 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 node.
+     *
+     * @param shape shape to append to this path node
+     * @param connect true to turn an initial moveTo segment into a
+     *    lineTo segment to connect the new geometry to the existing path
+     */
+    public final void append(final Shape shape, final boolean connect) {
+        Path2D oldPath = (Path2D) path.clone();
+        path.append(shape, connect);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Append the geometry of the specified path iterator to this path node, 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 path iterator 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.
+     *
+     * @param pathIterator path iterator to append to this path node
+     * @param connect true to turn an initial moveTo segment into a
+     *    lineTo segment to connect the new geometry to the existing path
+     */
+    public final void append(final PathIterator pathIterator, final boolean connect) {
+        Path2D oldPath = (Path2D) path.clone();
+        path.append(pathIterator, connect);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Add a curved segment, defined by three new points, to this path node by drawing
+     * a Bézier curve that intersects both the current coordinates and the specified
+     * coordinates (x3,y3), using the specified points (x1,y1)
+     * and (x2,y2) as Bézier control points. All coordinates are specified in
+     * double precision. 
+     *
+     * @param x1 x coordinate of the first Bézier control point
+     * @param y1 y coordinate of the first Bézier control point
+     * @param x2 x coordinate of the second Bézier control point
+     * @param y2 y coordinate of the second Bézier control point
+     * @param x3 x coordinate of the final end point
+     * @param y3 y coordinate of the final end point
+     */
+    public final void curveTo(final double x1,
+                              final double y1,
+                              final double x2,
+                              final double y2,
+                              final double x3,
+                              final double y3) {
+        Path2D oldPath = (Path2D) path.clone();
+        path.curveTo(x1, y1, x2, y2, x3, y3);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Add a point to this path node by drawing a straight line from the
+     * current coordinates to the new specified coordinates specified in double precision.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     */
+    public final void lineTo(final double x, final double y) {
+        Path2D oldPath = (Path2D) path.clone();
+        path.lineTo(x, y);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Add a point to this path node by moving to the specified coordinates
+     * specified in double precision.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     */
+    public final void moveTo(final double x, final double y) {
+        Path2D oldPath = (Path2D) path.clone();
+        path.moveTo(x, y);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Add a curved segment, defined by two new points, to this path node by
+     * drawing a Quadratic curve that intersects both the current coordinates and
+     * the specified coordinates (x2,y2), using the specified point
+     * (x1,y1) as a quadratic parametric control point.  All coordinates
+     * are specified in double precision.
+     *
+     * @param x1 x coordinate of the quadratic control point
+     * @param y1 y coordinate of the quadratic control point
+     * @param x2 x coordinate of the final end point
+     * @param y2 y coordinate of the final end point
+     */
+    public final void quadTo(final double x1, final double y1, final double x2, final double y2) {
+        Path2D oldPath = (Path2D) path.clone();
+        path.quadTo(x1, y1, x2, y2);
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Reset the geometry for this path node to empty.
+     */
+    public final void reset() {
+        Path2D oldPath = (Path2D) path.clone();
+        path.reset();
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    /**
+     * Close 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. 
+     */
+    public final void closePath() {
+        Path2D oldPath = (Path2D) path.clone();
+        path.closePath();
+        updateBoundsFromShape();
+        firePropertyChange(-1, "path", oldPath, getPath());
+    }
+
+    // todo:  setPathTo...
+
+    /** {@inheritDoc} */
+    protected final Shape getShape() {
+        return path;
+    }
+
+    /** {@inheritDoc} */
+    protected final void transform(final AffineTransform transform) {
+        path.transform(transform);
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/piccolo2d/nodes/PShape.java b/core/src/main/java/org/piccolo2d/nodes/PShape.java
new file mode 100644
index 0000000..e061417
--- /dev/null
+++ b/core/src/main/java/org/piccolo2d/nodes/PShape.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.Stroke;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.piccolo2d.PNode;
+
+import org.piccolo2d.util.PPaintContext;
+
+/**
+ * Abstract shape node.
+ */
+public abstract class PShape extends PNode {
+
+    /** Stroke for this shape node, defaults to {@link #DEFAULT_STROKE}. */
+    private transient Stroke stroke = DEFAULT_STROKE;
+
+    /** Stroke paint for this shape node, defaults to {@link #DEFAULT_STROKE_PAINT}. */
+    private Paint strokePaint = DEFAULT_STROKE_PAINT;
+
+    /** True if bounds are currently being updated to match the shape. */
+    private transient boolean updatingBoundsFromShape = false;
+
+    /** Default paint for this shape node, Color.WHITE. */
+    public static final Paint DEFAULT_PAINT = Color.WHITE;
+
+    /** Default stroke, a basic stroke of width 1.0f. */
+    public static final Stroke DEFAULT_STROKE = new BasicStroke(1.0f);
+
+    /** Default stroke paint, Color.BLACK. */
+    public static final Paint DEFAULT_STROKE_PAINT = Color.BLACK;
+
+
+    /**
+     * This is an abstract class that cannot be instantiated directly.
+     */
+    protected PShape() {
+        super();
+        setPaint(DEFAULT_PAINT);
+    }
+
+
+    /**
+     * Return the shape for this shape node.
+     *
+     * @return the shape for this shape node
+     */
+    protected abstract Shape getShape();
+
+    /**
+     * Apply the specified transform to the shape for this shape node.
+     *
+     * @param transform transform to apply to the shape for this shape node
+     */
+    protected abstract void transform(AffineTransform transform);
+
+
+    /**
+     * Return the stroke for this shape node.  Defaults to {@link #DEFAULT_STROKE}.
+     *
+     * @return the stroke for this shape node
+     */
+    public final Stroke getStroke() {
+        return stroke;
+    }
+
+    /**
+     * Set the stroke for this shape node to stroke.  This is
+     * a bound property.
+     *
+     * @param stroke stroke for this shape node
+     */
+    public final void setStroke(final Stroke stroke) {
+        Stroke oldStroke = this.stroke;
+        this.stroke = stroke;
+        updateBoundsFromShape();
+        invalidatePaint();
+        firePropertyChange(-1, "stroke", oldStroke, this.stroke);
+    }
+
+    /**
+     * Return the stroke paint for this shape node.  Defaults to {@link #DEFAULT_STROKE_PAINT}.
+     *
+     * @return the stroke paint for this shape node
+     */
+    public final Paint getStrokePaint() {
+        return strokePaint;
+    }
+
+    /**
+     * Set the stroke paint for this shape node to strokePaint.  This is
+     * a bound property.
+     *
+     * @param strokePaint stroke paint for this shape node
+     */
+    public final void setStrokePaint(final Paint strokePaint) {
+        Paint oldStrokePaint = this.strokePaint;
+        this.strokePaint = strokePaint;
+        invalidatePaint();
+        firePropertyChange(-1, "strokePaint", oldStrokePaint, this.strokePaint);
+    }
+
+    /**
+     * Update the bounds of this shape node from its shape.
+     */
+    protected final void updateBoundsFromShape() {
+        updatingBoundsFromShape = true;
+        final Rectangle2D b = getBoundsWithStroke();
+        setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight());
+        updatingBoundsFromShape = false;
+    }
+
+    /**
+     * Return the bounds of this node, taking the stroke into consideration if necessary.
+     *
+     * @return the bounds of this node, taking the stroke into consideration if necessary
+     */
+    protected final Rectangle2D getBoundsWithStroke() {
+        if (stroke != null) {
+            return stroke.createStrokedShape(getShape()).getBounds2D();
+        }
+        else {
+            return getShape().getBounds2D();
+        }
+    }
+
+    /** {@inheritDoc} */
+    protected final void internalUpdateBounds(final double x, final double y, final double width, final double height) {
+        if (updatingBoundsFromShape) {
+            return;
+        }
+
+        final Rectangle2D bounds = getShape().getBounds2D();
+        final Rectangle2D strokeBounds = getBoundsWithStroke();
+        final double strokeOutset = Math.max(strokeBounds.getWidth() - bounds.getWidth(),
+                                             strokeBounds.getHeight() - bounds.getHeight());
+
+        double adjustedX = x + strokeOutset / 2.0d;
+        double adjustedY = y + strokeOutset / 2.0d;
+        double adjustedWidth = width - strokeOutset;
+        double adjustedHeight = height - strokeOutset;
+
+        final double scaleX;
+        if (adjustedWidth == 0 || bounds.getWidth() == 0) {
+            scaleX = 1.0d;
+        }
+        else {
+            scaleX = adjustedWidth / bounds.getWidth();
+        }
+        final double scaleY;
+        if (adjustedHeight == 0 || bounds.getHeight() == 0) {
+            scaleY = 1.0d;
+        }
+        else {
+            scaleY = adjustedHeight / bounds.getHeight();
+        }
+
+        final AffineTransform transform = new AffineTransform();
+        transform.translate(adjustedX, adjustedY);
+        transform.scale(scaleX, scaleY);
+        transform.translate(-bounds.getX(), -bounds.getY());
+        transform(transform);
+    }
+
+    /** {@inheritDoc} */
+    public final boolean intersects(final Rectangle2D bounds) {
+        if (super.intersects(bounds)) {
+            if (getPaint() != null && getShape().intersects(bounds)) {
+                return true;
+            }
+            else if (stroke != null && strokePaint != null) {
+                return stroke.createStrokedShape(getShape()).intersects(bounds);
+            }
+        }
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    protected void paint(final PPaintContext paintContext) {
+        final Paint p = getPaint();
+        final Graphics2D g2 = paintContext.getGraphics();
+
+        if (p != null) {
+            g2.setPaint(p);
+            g2.fill(getShape());
+        }
+
+        if (stroke != null && strokePaint != null) {
+            g2.setPaint(strokePaint);
+            g2.setStroke(stroke);
+            g2.draw(getShape());
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/piccolo2d/PNodeTest.java b/core/src/test/java/org/piccolo2d/PNodeTest.java
index cc9ebc9..07f877b 100644
--- a/core/src/test/java/org/piccolo2d/PNodeTest.java
+++ b/core/src/test/java/org/piccolo2d/PNodeTest.java
@@ -1315,25 +1315,153 @@
         assertFalse(grandChild.isDescendentOf(unrelated));
     }
 
-    public void testMoveToBackMovesNodeToBeFirstChild() {
+    public void testRaise() {
         final PNode parent = new PNode();
-        parent.addChild(new PNode());
-        parent.addChild(new PNode());
         parent.addChild(node);
-        node.moveToBack();
+        parent.addChild(new PNode());
+        parent.addChild(new PNode());
+        node.raise();
+        assertEquals(1, parent.indexOfChild(node));
+    }
+
+    public void testRaiseOnly() {
+        final PNode parent = new PNode();
+        parent.addChild(node);
+        node.raise();
         assertEquals(0, parent.indexOfChild(node));
     }
 
-    public void testMoveToFrontMovesNodeToBeLastChild() {
+    public void testLower() {
+        final PNode parent = new PNode();
+        parent.addChild(new PNode());
+        parent.addChild(new PNode());
+        parent.addChild(node);
+        node.lower();
+        assertEquals(1, parent.indexOfChild(node));
+    }
+
+    public void testLowerOnly() {
+        final PNode parent = new PNode();
+        parent.addChild(node);
+        node.lower();
+        assertEquals(0, parent.indexOfChild(node));
+    }
+
+    public void testRaiseToTop() {
         final PNode parent = new PNode();
         parent.addChild(node);
         parent.addChild(new PNode());
         parent.addChild(new PNode());
-        node.moveToFront();
+        node.raiseToTop();
         assertEquals(2, parent.indexOfChild(node));
     }
 
-    public void testMoveInBackOfMovesNodeToBeforeSibling() {
+    public void testRaiseToTopOnly() {
+        final PNode parent = new PNode();
+        parent.addChild(node);
+        node.raiseToTop();
+        assertEquals(0, parent.indexOfChild(node));
+    }
+
+    public void testLowerToBottom() {
+        final PNode parent = new PNode();
+        parent.addChild(new PNode());
+        parent.addChild(new PNode());
+        parent.addChild(node);
+        node.lowerToBottom();
+        assertEquals(0, parent.indexOfChild(node));
+    }
+
+    public void testLowerToBottomOnly() {
+        final PNode parent = new PNode();
+        parent.addChild(node);
+        node.lowerToBottom();
+        assertEquals(0, parent.indexOfChild(node));
+    }
+
+    public void testRaiseAbove() {
+        final PNode parent = new PNode();
+        parent.addChild(node);
+        final PNode sibling = new PNode();
+        parent.addChild(sibling);
+        parent.addChild(new PNode());
+        node.raiseAbove(sibling);
+        assertEquals(1, parent.indexOfChild(node));
+    }
+
+    public void testLowerBelow() {
+        final PNode parent = new PNode();
+        parent.addChild(new PNode());
+        final PNode sibling = new PNode();
+        parent.addChild(sibling);
+        parent.addChild(node);
+        node.lowerBelow(sibling);
+        assertEquals(1, parent.indexOfChild(node));
+    }
+
+    public void testRaiseChild() {
+        final PNode child0 = new PNode();
+        final PNode child1 = new PNode();
+        final PNode child2 = new PNode();
+        node.addChild(child0);
+        node.addChild(child1);
+        node.addChild(child2);
+        node.raise(child0);
+        assertEquals(1, node.indexOfChild(child0));
+    }
+
+    public void testLowerChild() {
+        final PNode child0 = new PNode();
+        final PNode child1 = new PNode();
+        final PNode child2 = new PNode();
+        node.addChild(child0);
+        node.addChild(child1);
+        node.addChild(child2);
+        node.lower(child2);
+        assertEquals(1, node.indexOfChild(child2));
+    }
+
+    public void testRaiseChildToTop() {
+        final PNode child0 = new PNode();
+        final PNode child1 = new PNode();
+        final PNode child2 = new PNode();
+        node.addChild(child0);
+        node.addChild(child1);
+        node.addChild(child2);
+        node.raiseToTop(child0);
+        assertEquals(2, node.indexOfChild(child0));
+    }
+
+    public void testLowerChildToBottom() {
+        final PNode child0 = new PNode();
+        final PNode child1 = new PNode();
+        final PNode child2 = new PNode();
+        node.addChild(child0);
+        node.addChild(child1);
+        node.addChild(child2);
+        node.lowerToBottom(child2);
+        assertEquals(0, node.indexOfChild(child2));
+    }
+
+    public void testLowerToBottomMovesNodeToBeFirstChild() {
+        final PNode parent = new PNode();
+        parent.addChild(new PNode());
+        parent.addChild(new PNode());
+        parent.addChild(node);
+        node.lowerToBottom();
+        assertEquals(0, parent.indexOfChild(node));
+    }
+
+    public void testRaiseToTopMovesNodeToBeLastChild() {
+        final PNode parent = new PNode();
+        parent.addChild(node);
+        parent.addChild(new PNode());
+        parent.addChild(new PNode());
+        node.raiseToTop();
+        assertEquals(2, parent.indexOfChild(node));
+    }
+
+    public void testLowerBelowMovesNodeToBeforeSibling() {
         final PNode parent = new PNode();
         final PNode sibling = new PNode();
 
@@ -1342,11 +1470,11 @@
         parent.addChild(new PNode());
         parent.addChild(sibling);
 
-        node.moveInBackOf(sibling);
+        node.lowerBelow(sibling);
         assertEquals(2, parent.indexOfChild(node));
     }
 
-    public void testMoveInFrontOfMovesNodeToAfterSibling() {
+    public void testRaiseAboveMovesNodeToAfterSibling() {
         final PNode parent = new PNode();
         final PNode sibling = new PNode();
 
@@ -1355,11 +1483,11 @@
         parent.addChild(new PNode());
         parent.addChild(sibling);
 
-        node.moveInFrontOf(sibling);
+        node.raiseAbove(sibling);
         assertEquals(3, parent.indexOfChild(node));
     }
 
-    public void testMoveInFrontOfDoesNothingIfNotSibling() {
+    public void testRaiseAboveDoesNothingIfNotSibling() {
         final PNode parent = new PNode();
         final PNode stranger = new PNode();
 
@@ -1367,11 +1495,11 @@
         parent.addChild(new PNode());
         parent.addChild(new PNode());
 
-        node.moveInFrontOf(stranger);
+        node.raiseAbove(stranger);
         assertEquals(0, parent.indexOfChild(node));
     }
 
-    public void testMoveInBackOfDoesNothingIfNotSibling() {
+    public void testLowerBelowDoesNothingIfNotSibling() {
         final PNode parent = new PNode();
         final PNode stranger = new PNode();
 
@@ -1379,7 +1507,7 @@
         parent.addChild(new PNode());
         parent.addChild(new PNode());
 
-        node.moveInBackOf(stranger);
+        node.lowerBelow(stranger);
         assertEquals(0, parent.indexOfChild(node));
     }
 
diff --git a/core/src/test/java/org/piccolo2d/SerializationTest.java b/core/src/test/java/org/piccolo2d/SerializationTest.java
index d224a62..ce82a73 100644
--- a/core/src/test/java/org/piccolo2d/SerializationTest.java
+++ b/core/src/test/java/org/piccolo2d/SerializationTest.java
@@ -53,7 +53,7 @@
         for (int i = 0; i < 100; i++) {
             l.addChild(new PNode());
             l.addChild(new PText("Hello World"));
-            l.addChild(new PPath());
+            l.addChild(new PPath.Float());
         }
 
         l = (PNode) l.clone(); // copy uses serialization internally
diff --git a/core/src/test/java/org/piccolo2d/event/PDragEventHandlerTest.java b/core/src/test/java/org/piccolo2d/event/PDragEventHandlerTest.java
index 9092d94..c4ac377 100644
--- a/core/src/test/java/org/piccolo2d/event/PDragEventHandlerTest.java
+++ b/core/src/test/java/org/piccolo2d/event/PDragEventHandlerTest.java
@@ -42,13 +42,13 @@
         handler = new PDragEventHandler();
     }
 
-    public void testMoveToFrontOnPressDefaultToFalse() {
-        assertFalse(handler.getMoveToFrontOnPress());
+    public void testRaiseToTopOnPressDefaultToFalse() {
+        assertFalse(handler.getRaiseToTopOnPress());
     }
 
-    public void testMoveToFrontOnPressPersists() {
-        handler.setMoveToFrontOnPress(true);
-        assertTrue(handler.getMoveToFrontOnPress());
+    public void testRaiseToTopOnPressPersists() {
+        handler.setRaiseToTopOnPress(true);
+        assertTrue(handler.getRaiseToTopOnPress());
     }
 
 }
diff --git a/core/src/test/java/org/piccolo2d/nodes/AbstractPPathTest.java b/core/src/test/java/org/piccolo2d/nodes/AbstractPPathTest.java
new file mode 100644
index 0000000..a11064e
--- /dev/null
+++ b/core/src/test/java/org/piccolo2d/nodes/AbstractPPathTest.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.Color;
+import java.awt.Shape;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+import org.piccolo2d.util.PBounds;
+import org.piccolo2d.util.PObjectOutputStream;
+
+/**
+ * Abstract unit test for subclasses of PPath.
+ */
+public abstract class AbstractPPathTest extends AbstractPShapeTest {
+
+    private static final double TOLERANCE = 0.0001d;
+    private static final double LOW_TOLERANCE = 1.0d;
+
+    /** {@inheritDoc} */
+    protected void setUp() {
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
+    protected PShape createShapeNode() {
+        return createPathNode();
+    }
+
+    /**
+     * Create a new instance of a subclass of PPath to test.
+     *
+     * @return a new instance of a subclass of PPath to test
+     */
+    protected abstract PPath createPathNode();
+
+    // todo:  rewrite in terms of createPathNode()
+
+    public void testClone() {
+        PPath p = PPath.createEllipse(0, 0, 100, 100);        
+        PPath cloned = (PPath) p.clone();
+        assertEquals(p.getBounds(), cloned.getBounds());
+        //assertEquals(p.getPathReference()., cloned.getPathReference());
+    }
+
+    public void testSerialization() throws IOException, ClassNotFoundException {
+        final PPath srcPath = PPath.createEllipse(0, 0, 100, 100);
+        final PBounds srcBounds = srcPath.getBounds();
+
+        final File file = File.createTempFile("test", "ser");
+
+        serializeToFile(srcPath, file);
+        final PPath resultPath = deserializeFromFile(srcBounds, file);
+        file.deleteOnExit();
+
+        assertEquals(resultPath.getBounds(), srcBounds);
+    }
+
+    private PPath deserializeFromFile(final PBounds b, final File file) throws FileNotFoundException, IOException,
+            ClassNotFoundException {
+        PPath path;
+        final FileInputStream fin = new FileInputStream(file);
+        final ObjectInputStream in = new ObjectInputStream(fin);
+        path = (PPath) in.readObject();
+
+        return path;
+    }
+
+    private void serializeToFile(final PPath p, final File file) throws FileNotFoundException, IOException {
+        final FileOutputStream fout = new FileOutputStream(file);
+        final PObjectOutputStream out = new PObjectOutputStream(fout);
+        out.writeObjectTree(p);
+        out.flush();
+        out.close();
+    }
+
+    public void testCreateArcFloat() {
+        assertNotNull(PPath.createArc(0.0f, 0.0f, 50.0f, 100.0f, 25.0f, 75.0f, Arc2D.OPEN));
+    }
+
+    public void testCreateCubicCurveFloat() {
+        assertNotNull(PPath.createCubicCurve(0.0f, 0.0f, 25.0f, 75.0f, 75.0f, 25.0f, 50.0f, 100.0f));
+    }
+
+    public void testCreateEllipseFloat() {
+        assertNotNull(PPath.createEllipse(0.0f, 0.0f, 50.0f, 100.0f));
+    }
+
+    public void testCreateLineFloat() {
+        assertNotNull(PPath.createLine(0.0f, 0.0f, 50.0f, 100.0f));
+    }
+
+    public void testCreateQuadCurveFloat() {
+        assertNotNull(PPath.createQuadCurve(0.0f, 0.0f, 25.0f, 75.0f, 50.0f, 100.0f));
+    }
+
+    public void testCreateRectangleFloat() {
+        assertNotNull(PPath.createRectangle(0.0f, 0.0f, 50.0f, 100.0f));
+    }
+
+    public void testCreateRoundRectangleFloat() {
+        assertNotNull(PPath.createRoundRectangle(0.0f, 0.0f, 50.0f, 100.0f, 4.0f, 8.0f));
+    }
+
+    public void testCreateArcDouble() {
+        assertNotNull(PPath.createArc(0.0d, 0.0d, 50.0d, 100.0d, 25.0d, 75.0d, Arc2D.OPEN));
+    }
+
+    public void testCreateCubicCurveDouble() {
+        assertNotNull(PPath.createCubicCurve(0.0d, 0.0d, 25.0d, 75.0d, 75.0d, 25.0d, 50.0d, 100.0d));
+    }
+
+    public void testCreateEllipseDouble() {
+        assertNotNull(PPath.createEllipse(0.0d, 0.0d, 50.0d, 100.0d));
+    }
+
+    public void testCreateLineDouble() {
+        assertNotNull(PPath.createLine(0.0d, 0.0d, 50.0d, 100.0d));
+    }
+
+    public void testCreateQuadCurveDouble() {
+        assertNotNull(PPath.createQuadCurve(0.0d, 0.0d, 25.0d, 75.0d, 50.0d, 100.0d));
+    }
+
+    public void testCreateRectangleDouble() {
+        assertNotNull(PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d));
+    }
+
+    public void testCreateRoundRectangleDouble() {
+        assertNotNull(PPath.createRoundRectangle(0.0d, 0.0d, 50.0d, 100.0d, 4.0d, 8.0d));
+    }
+
+    public void testAppendShape() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
+        path.append(rect, true);
+        // todo:  shouldn't this be width + 2 * strokeWidth?
+        assertEquals(101.0d, path.getWidth(), TOLERANCE);
+        assertEquals(201.0d, path.getHeight(), TOLERANCE);
+    }
+
+    public void testAppendShapeNullArgument() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        try {
+            path.append((Shape) null, true);
+            fail("append((Shape) null, true) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testAppendPathIterator() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
+        PathIterator pathIterator = rect.getPathIterator(new AffineTransform());
+        path.append(pathIterator, true);
+        assertEquals(101.0d, path.getWidth(), TOLERANCE);
+        assertEquals(201.0d, path.getHeight(), TOLERANCE);
+    }
+
+    public void testAppendPathIteratorNullArgument() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        try {
+            path.append((PathIterator) null, true);
+            fail("append((PathIterator) null, true) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testCurveTo() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.curveTo(70.0d, 140.0d, 80.0d, 140.0d, 100.0d, 200.0d);
+        assertEquals(101.0d, path.getWidth(), LOW_TOLERANCE);
+        assertEquals(201.0d, path.getHeight(), LOW_TOLERANCE);
+    }
+
+    public void testLineTo() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.lineTo(100.0d, 200.0d);
+        assertEquals(101.0d, path.getWidth(), LOW_TOLERANCE);
+        assertEquals(201.0d, path.getHeight(), LOW_TOLERANCE);
+    }
+
+    public void testMoveTo() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.moveTo(100.0d, 200.0d);
+        assertEquals(51.0d, path.getWidth(), TOLERANCE);
+        assertEquals(101.0d, path.getHeight(), TOLERANCE);
+    }
+
+    public void testQuadTo() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.quadTo(70.0d, 140.0d, 100.0d, 200.0d);
+        assertEquals(101.0d, path.getWidth(), LOW_TOLERANCE);
+        assertEquals(201.0d, path.getHeight(), LOW_TOLERANCE);
+    }
+
+    public void testClosePath() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.lineTo(100.0d, 200.0d);
+        path.closePath();
+    }
+
+    public void testClosePathAlreadyClosed() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.lineTo(100.0d, 200.0d);
+        path.closePath();
+        path.closePath();
+    }
+
+    public void testIntersects() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        assertTrue(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertTrue(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testIntersectsNullStroke() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.setStroke(null);
+        assertTrue(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertTrue(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testIntersectsNullPaint() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.setPaint(null);
+        assertTrue(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testIntersectsNullPaintNullStroke() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.setPaint(null);
+        path.setStroke(null);
+        assertFalse(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testFullIntersects() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testFullIntersectsNullStroke() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.setStroke(null);
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testFullIntersectsNullPaint() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.setPaint(null);
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    public void testFullIntersectsNullPaintNullStroke() {
+        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
+        path.setPaint(null);
+        path.setStroke(null);
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
+        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
+        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
+    }
+
+    /*
+    public void testPath() {
+        PPath path = createPathNode();
+        assertNotNull(path.getPath()); // or (Path) getShape(), or getPathReference() ?
+        Path2D.Double rect = new Path2D.Double((new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
+        path.setPath(rect);
+        assertEquals(rect, path.getPath());
+    }
+
+    public void testPathNullArgument() {
+        PPath path = createPathNode();
+        try {
+            path.setPath(null);
+            fail("setPath(null) expected IllegalArgumentException");
+        }
+        catch (IllegalArgumentException e) { // or NPE?
+            // expected
+        }
+    }
+
+    public void testPathBoundProperty() {
+        PPath path = createPathNode();
+        path.addPropertyChangeListener("path", mockListener);
+        Path2D.Double rect = new Path2D.Double((new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
+        path.setPath(rect);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+    */
+
+    public void testAppendShapeFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.addPropertyChangeListener("path", mockListener);
+        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
+        path.append(rect, true);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testAppendPathIteratorFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.moveTo(0.0d, 0.0d);
+        path.addPropertyChangeListener("path", mockListener);
+        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
+        PathIterator pathIterator = rect.getPathIterator(new AffineTransform());
+        path.append(pathIterator, true);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testCurveToFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.moveTo(0.0d, 0.0d);
+        path.addPropertyChangeListener("path", mockListener);
+        path.curveTo(70.0d, 140.0d, 80.0d, 140.0d, 100.0d, 200.0d);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testLineToFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.moveTo(0.0d, 0.0d);
+        path.addPropertyChangeListener("path", mockListener);
+        path.lineTo(100.0d, 200.0d);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testMoveToFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.moveTo(0.0d, 0.0d);
+        path.addPropertyChangeListener("path", mockListener);
+        path.moveTo(100.0d, 200.0d);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testQuadToFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.moveTo(0.0d, 0.0d);
+        path.addPropertyChangeListener("path", mockListener);
+        path.quadTo(70.0d, 140.0d, 100.0d, 200.0d);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testClosePathFiresPropertyChangeEvent() {
+        PPath path = createPathNode();
+        path.moveTo(0.0d, 0.0d);
+        path.lineTo(100.0d, 200.0d);
+        path.addPropertyChangeListener("path", mockListener);
+        path.closePath();
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+}
diff --git a/core/src/test/java/org/piccolo2d/nodes/AbstractPShapeTest.java b/core/src/test/java/org/piccolo2d/nodes/AbstractPShapeTest.java
new file mode 100644
index 0000000..36eda12
--- /dev/null
+++ b/core/src/test/java/org/piccolo2d/nodes/AbstractPShapeTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Paint;
+import java.awt.Stroke;
+
+import junit.framework.TestCase;
+
+/**
+ * Abstract unit test for subclasses of PShape.
+ */
+public abstract class AbstractPShapeTest extends TestCase {
+
+    /** Mock property change listener. */
+    protected MockPropertyChangeListener mockListener;
+
+
+    /** {@inheritDoc} */
+    protected void setUp() {
+        mockListener = new MockPropertyChangeListener();
+    }
+
+    /**
+     * Create a new instance of a subclass of PShape to test.
+     *
+     * @return a new instance of a subclass of PShape to test
+     */
+    protected abstract PShape createShapeNode();
+
+    public void testCreateShapeNode() {
+        assertNotNull(createShapeNode());
+    }
+
+    public void testDefaultPaint() {
+        PShape shape = createShapeNode();
+        assertEquals(PShape.DEFAULT_PAINT, shape.getPaint());
+    }
+
+    public void testDefaultStroke() {
+        PShape shape = createShapeNode();
+        assertEquals(PShape.DEFAULT_STROKE, shape.getStroke());
+    }
+
+    public void testDefaultStrokePaint() {
+        PShape shape = createShapeNode();
+        assertEquals(PShape.DEFAULT_STROKE_PAINT, shape.getStrokePaint());
+    }
+
+    public void testStroke() {
+        PShape shape = createShapeNode();
+        Stroke stroke = new BasicStroke(2.0f);
+        shape.setStroke(stroke);
+        assertEquals(stroke, shape.getStroke());
+    }
+
+    public void testStrokeBoundProperty() {
+        PShape shape = createShapeNode();
+        shape.addPropertyChangeListener("stroke", mockListener);
+        Stroke stroke = new BasicStroke(2.0f);
+        shape.setStroke(stroke);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testStrokePaint() {
+        PShape shape = createShapeNode();
+        Paint strokePaint = Color.RED;
+        shape.setStrokePaint(strokePaint);
+        assertEquals(strokePaint, shape.getStrokePaint());
+    }
+
+    public void testStrokePaintBoundProperty() {
+        PShape shape = createShapeNode();
+        shape.addPropertyChangeListener("strokePaint", mockListener);
+        Paint strokePaint = Color.RED;
+        shape.setStrokePaint(strokePaint);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/piccolo2d/nodes/MockPropertyChangeListener.java b/core/src/test/java/org/piccolo2d/nodes/MockPropertyChangeListener.java
new file mode 100644
index 0000000..9587457
--- /dev/null
+++ b/core/src/test/java/org/piccolo2d/nodes/MockPropertyChangeListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mock PropertyChangeListener.
+ */
+public class MockPropertyChangeListener implements PropertyChangeListener {
+    private final List changes = new ArrayList();
+
+    public void propertyChange(final PropertyChangeEvent evt) {
+        changes.add(evt);
+    }
+
+    public int getPropertyChangeCount() {
+        return changes.size();
+    }
+
+    public PropertyChangeEvent getPropertyChange(final int index) {
+        return (PropertyChangeEvent) changes.get(index);
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/piccolo2d/nodes/PAreaTest.java b/core/src/test/java/org/piccolo2d/nodes/PAreaTest.java
new file mode 100644
index 0000000..e0696e1
--- /dev/null
+++ b/core/src/test/java/org/piccolo2d/nodes/PAreaTest.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.Shape;
+
+import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Unit test for PArea.
+ */
+public class PAreaTest extends AbstractPShapeTest {
+
+    private static final double TOLERANCE = 0.0001d;
+    private static final Rectangle2D FIRST = new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d);
+    private static final Rectangle2D SECOND = new Rectangle2D.Double(50.0, 50.0d, 100.0d, 100.0d);
+    private static final Rectangle2D FIRST_INTERIOR = new Rectangle2D.Double(25.0d, 25.0d, 2.0d, 2.0d);
+    private static final Rectangle2D FIRST_PATH = new Rectangle2D.Double(25.0d, 100.0d, 1.0d, 1.0d);
+    private static final Rectangle2D SECOND_INTERIOR = new Rectangle2D.Double(125.0d, 125.0d, 2.0d, 2.0d);
+    private static final Rectangle2D SECOND_PATH = new Rectangle2D.Double(125.0d, 150.0d, 1.0d, 1.0d);
+    private static final Rectangle2D INTERSECTION_INTERIOR = new Rectangle2D.Double(75.0, 75.0d, 2.0d, 2.0d);
+    private static final Rectangle2D INTERSECTION_PATH = new Rectangle2D.Double(75.0, 100.0d, 1.0d, 1.0d);
+    private static final Rectangle2D EXTERIOR = new Rectangle2D.Double(200.0, 200.0d, 2.0d, 2.0d);
+
+    /** {@inheritDoc} */
+    protected void setUp() {
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
+    protected PShape createShapeNode() {
+        return new PArea();
+    }
+
+    public void testNoArgConstructor() {
+        assertNotNull(new PArea());
+    }
+
+    public void testShapeConstructor() {
+        assertNotNull(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
+    }
+
+    public void testShapeConstructorNullArgument() {
+        try {
+            new PArea((Shape) null);
+            fail("ctr((Shape) null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testAreaConstructor() {
+        assertNotNull(new PArea(new Area()));
+    }
+
+    public void testAreaConstructorNullArgument() {
+        try {
+            new PArea((Area) null);
+            fail("ctr((Area) null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testAdd() {
+        PArea area = new PArea();
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.add(rect1);
+
+        // todo:  shouldn't this be width + 2 * strokeWidth?
+        assertEquals(151.0d, area.getWidth(), TOLERANCE);
+        assertEquals(151.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertTrue(area.intersects(FIRST_PATH));
+        assertTrue(area.intersects(SECOND_INTERIOR));
+        assertTrue(area.intersects(SECOND_PATH));
+        assertTrue(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testAddNullPaint() {
+        PArea area = new PArea();
+        area.setPaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.add(rect1);
+
+        assertEquals(151.0d, area.getWidth(), TOLERANCE);
+        assertEquals(151.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertTrue(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertTrue(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testAddNullStroke() {
+        PArea area = new PArea();
+        area.setStroke(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.add(rect1);
+
+        assertEquals(150.0d, area.getWidth(), TOLERANCE);
+        assertEquals(150.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertTrue(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertTrue(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testAddNullStrokePaint() {
+        PArea area = new PArea();
+        area.setStrokePaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.add(rect1);
+
+        assertEquals(151.0d, area.getWidth(), TOLERANCE);
+        assertEquals(151.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertTrue(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertTrue(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testAddNullArgument() {
+        PArea area = new PArea();
+        try {
+            area.add(null);
+            fail("add(null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testExclusiveOr() {
+        PArea area = new PArea();
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.exclusiveOr(rect1);
+
+        assertEquals(151.0d, area.getWidth(), TOLERANCE);
+        assertEquals(151.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertTrue(area.intersects(FIRST_PATH));
+        assertTrue(area.intersects(SECOND_INTERIOR));
+        assertTrue(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testExclusiveOrNullPaint() {
+        PArea area = new PArea();
+        area.setPaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.exclusiveOr(rect1);
+
+        assertEquals(151.0d, area.getWidth(), TOLERANCE);
+        assertEquals(151.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertTrue(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertTrue(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testExclusiveOrNullStroke() {
+        PArea area = new PArea();
+        area.setStroke(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.exclusiveOr(rect1);
+
+        assertEquals(150.0d, area.getWidth(), TOLERANCE);
+        assertEquals(150.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertTrue(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testExclusiveOrNullStrokePaint() {
+        PArea area = new PArea();
+        area.setStrokePaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.exclusiveOr(rect1);
+
+        assertEquals(151.0d, area.getWidth(), TOLERANCE);
+        assertEquals(151.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertTrue(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testExclusiveOrNullArgument() {
+        PArea area = new PArea();
+        try {
+            area.exclusiveOr(null);
+            fail("exclusiveOr(null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testIntersect() {
+        PArea area = new PArea();
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.intersect(rect1);        
+
+        assertEquals(51.0d, area.getWidth(), TOLERANCE);
+        assertEquals(51.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertTrue(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testIntersectNullPaint() {
+        PArea area = new PArea();
+        area.setPaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.intersect(rect1);        
+
+        assertEquals(51.0d, area.getWidth(), TOLERANCE);
+        assertEquals(51.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertTrue(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testIntersectNullStroke() {
+        PArea area = new PArea();
+        area.setStroke(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.intersect(rect1);        
+
+        assertEquals(50.0d, area.getWidth(), TOLERANCE);
+        assertEquals(50.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertTrue(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testIntersectNullStrokePaint() {
+        PArea area = new PArea();
+        area.setStrokePaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.intersect(rect1);        
+
+        assertEquals(51.0d, area.getWidth(), TOLERANCE);
+        assertEquals(51.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertTrue(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testIntersectNullArgument() {
+        PArea area = new PArea();
+        try {
+            area.intersect(null);
+            fail("intersect(null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testSubtract() {
+        PArea area = new PArea();
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.subtract(rect1);        
+
+        assertEquals(101.0d, area.getWidth(), TOLERANCE);
+        assertEquals(101.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertTrue(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testSubtractNullPaint() {
+        PArea area = new PArea();
+        area.setPaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.subtract(rect1);        
+
+        assertEquals(101.0d, area.getWidth(), TOLERANCE);
+        assertEquals(101.0d, area.getHeight(), TOLERANCE);
+
+        assertFalse(area.intersects(FIRST_INTERIOR));
+        assertTrue(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testSubtractNullStroke() {
+        PArea area = new PArea();
+        area.setStroke(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.subtract(rect1);        
+
+        assertEquals(100.0d, area.getWidth(), TOLERANCE);
+        assertEquals(100.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testSubtractNullStrokePaint() {
+        PArea area = new PArea();
+        area.setStrokePaint(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(FIRST);
+        area.add(rect0);
+        Area rect1 = new Area(SECOND);
+        area.subtract(rect1);        
+
+        assertEquals(101.0d, area.getWidth(), TOLERANCE);
+        assertEquals(101.0d, area.getHeight(), TOLERANCE);
+
+        assertTrue(area.intersects(FIRST_INTERIOR));
+        assertFalse(area.intersects(FIRST_PATH));
+        assertFalse(area.intersects(SECOND_INTERIOR));
+        assertFalse(area.intersects(SECOND_PATH));
+        assertFalse(area.intersects(INTERSECTION_INTERIOR));
+        assertFalse(area.intersects(INTERSECTION_PATH));
+        assertFalse(area.intersects(EXTERIOR));
+    }
+
+    public void testSubtractNullArgument() {
+        PArea area = new PArea();
+        try {
+            area.subtract(null);
+            fail("subtract(null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testReset() {
+        PArea area = new PArea();
+        area.setStroke(null);
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+
+        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect0);
+        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect1);
+
+        assertEquals(150.0d, area.getWidth(), TOLERANCE);
+        assertEquals(100.0, area.getHeight(), TOLERANCE);
+
+        area.reset();
+        assertEquals(0.0d, area.getWidth(), TOLERANCE);
+        assertEquals(0.0d, area.getHeight(), TOLERANCE);
+    }
+
+    public void testIsEmpty() {
+        assertTrue(new PArea().isEmpty());
+        assertFalse(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isEmpty());
+        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isEmpty());
+        assertFalse(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isEmpty());
+    }
+
+    public void testIsPolygonal() {
+        assertTrue(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isPolygonal());
+        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isPolygonal());
+        assertFalse(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isPolygonal());
+    }
+
+    public void testIsRectangular() {
+        assertTrue(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isRectangular());
+        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isRectangular());
+        assertFalse(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isRectangular());
+    }
+
+    public void testIsSingular() {
+        assertTrue(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isSingular());
+        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isSingular());
+        assertTrue(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isSingular());
+
+        PArea exclusiveOr = new PArea();
+        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        exclusiveOr.add(rect0);
+        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
+        exclusiveOr.exclusiveOr(rect1);
+
+        assertFalse(exclusiveOr.isSingular());
+    }
+
+    /*
+    public void testArea() {
+        PArea area = new PArea();
+        assertNotNull(area.getArea()); // or (Area) getShape(), or getAreaReference() ?
+        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.setArea(rect);
+        assertEquals(rect, area.getArea());
+    }
+
+    public void testAreaNullArgument() {
+        PArea area = new PArea();
+        try {
+            area.setArea(null);
+            fail("setArea(null) expected IllegalArgumentException");
+        }
+        catch (IllegalArgumentException e) { // or NPE?
+            // expected
+        }
+    }
+
+    public void testAreaBoundProperty() {
+        PArea area = new PArea();
+        area.addPropertyChangeListener("area", mockListener);
+        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.setArea(rect);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+    */
+
+    public void testAddFiresPropertyChangeEvent() {
+        PArea area = new PArea();
+        area.addPropertyChangeListener("area", mockListener);
+        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testExclusiveOrFiresPropertyChangeEvent() {
+        PArea area = new PArea();
+        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect0);
+        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
+        area.addPropertyChangeListener("area", mockListener);
+        area.exclusiveOr(rect1);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testIntersectFiresPropertyChangeEvent() {
+        PArea area = new PArea();
+        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect0);
+        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
+        area.addPropertyChangeListener("area", mockListener);
+        area.intersect(rect1);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testSubtractFiresPropertyChangeEvent() {
+        PArea area = new PArea();
+        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect0);
+        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
+        area.addPropertyChangeListener("area", mockListener);
+        area.subtract(rect1);
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testResetFiresPropertyChangeEvent() {
+        PArea area = new PArea();
+        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
+        area.add(rect);
+        area.addPropertyChangeListener("area", mockListener);
+        area.reset();
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/piccolo2d/nodes/PPathDoubleTest.java b/core/src/test/java/org/piccolo2d/nodes/PPathDoubleTest.java
new file mode 100644
index 0000000..9ea34f2
--- /dev/null
+++ b/core/src/test/java/org/piccolo2d/nodes/PPathDoubleTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.BasicStroke;
+import java.awt.Shape;
+import java.awt.Stroke;
+
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Unit test for PPath.Double.
+ */
+public class PPathDoubleTest extends AbstractPPathTest {
+
+    /** {@inheritDoc} */
+    protected PPath createPathNode() {
+        return new PPath.Double();
+    }
+
+    public void testNoArgConstructor() {
+        assertNotNull(new PPath.Double());
+    }
+
+    public void testStrokeConstructor() {
+        assertNotNull(new PPath.Double((Stroke) null));
+        assertNotNull(new PPath.Double(new BasicStroke(2.0f)));
+    }
+
+    public void testShapeConstructor() {
+        assertNotNull(new PPath.Double(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
+    }
+
+    public void testShapeStrokeConstructor() {
+        assertNotNull(new PPath.Double(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d), null));
+        assertNotNull(new PPath.Double(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d), new BasicStroke(2.0f)));
+    }
+
+    public void testShapeConstructorNullArgument() {
+        try {
+            new PPath.Double((Shape) null);
+            fail("ctr((Shape) null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testShapeStrokeConstructorNullArgument() {
+        try {
+            new PPath.Double((Shape) null, null);
+            fail("ctr((Shape) null, ) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testPathConstructor() {
+        assertNotNull(new PPath.Double(new Path2D.Double()));
+    }
+
+    public void testPathStrokeConstructor() {
+        assertNotNull(new PPath.Double(new Path2D.Double(), null));
+        assertNotNull(new PPath.Double(new Path2D.Double(), new BasicStroke(2.0f)));
+    }
+
+    public void testPathConstructorNullArgument() {
+        try {
+            new PPath.Double((Path2D) null);
+            fail("ctr((Path2D) null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testPathStrokeConstructorNullArgument() {
+        try {
+            new PPath.Double((Path2D) null, null);
+            fail("ctr((Path2D) null, ) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/piccolo2d/nodes/PPathFloatTest.java b/core/src/test/java/org/piccolo2d/nodes/PPathFloatTest.java
new file mode 100644
index 0000000..1ab0ccb
--- /dev/null
+++ b/core/src/test/java/org/piccolo2d/nodes/PPathFloatTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2008-2012, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.nodes;
+
+import java.awt.BasicStroke;
+import java.awt.Shape;
+import java.awt.Stroke;
+
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Unit test for PPath.Float.
+ */
+public class PPathFloatTest extends AbstractPPathTest {
+
+    /** {@inheritDoc} */
+    protected PPath createPathNode() {
+        return new PPath.Float();
+    }
+
+    public void testNoArgConstructor() {
+        assertNotNull(new PPath.Float());
+    }
+
+    public void testStrokeConstructor() {
+        assertNotNull(new PPath.Float((Stroke) null));
+        assertNotNull(new PPath.Float(new BasicStroke(2.0f)));
+    }
+
+    public void testShapeConstructor() {
+        assertNotNull(new PPath.Float(new Rectangle2D.Float(0.0f, 0.0f, 100.0f, 100.0f)));
+    }
+
+    public void testShapeStrokeConstructor() {
+        assertNotNull(new PPath.Float(new Rectangle2D.Float(0.0f, 0.0f, 100.0f, 100.0f), null));
+        assertNotNull(new PPath.Float(new Rectangle2D.Float(0.0f, 0.0f, 100.0f, 100.0f), new BasicStroke(2.0f)));
+    }
+
+    public void testShapeConstructorNullArgument() {
+        try {
+            new PPath.Float((Shape) null);
+            fail("ctr((Shape) null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testShapeStrokeConstructorNullArgument() {
+        try {
+            new PPath.Float((Shape) null, null);
+            fail("ctr((Shape) null, ) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testPathConstructor() {
+        assertNotNull(new PPath.Float(new Path2D.Float()));
+    }
+
+    public void testPathStrokeConstructor() {
+        assertNotNull(new PPath.Float(new Path2D.Float(), null));
+        assertNotNull(new PPath.Float(new Path2D.Float(), new BasicStroke(2.0f)));
+    }
+
+    public void testPathConstructorNullArgument() {
+        try {
+            new PPath.Float((Path2D) null);
+            fail("ctr((Path2D) null) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testStrokePathConstructorNullArgument() {
+        try {
+            new PPath.Float((Path2D) null, null);
+            fail("ctr((Path2D) null, ) expected NullPointerException");
+        }
+        catch (NullPointerException e) {
+            // expected
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/piccolo2d/nodes/PPathTest.java b/core/src/test/java/org/piccolo2d/nodes/PPathTest.java
deleted file mode 100644
index 0898b27..0000000
--- a/core/src/test/java/org/piccolo2d/nodes/PPathTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.nodes;
-
-import java.awt.Color;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-
-import org.piccolo2d.MockPropertyChangeListener;
-import org.piccolo2d.PiccoloAsserts;
-import org.piccolo2d.nodes.PPath;
-import org.piccolo2d.util.PBounds;
-import org.piccolo2d.util.PObjectOutputStream;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test for PPath.
- */
-public class PPathTest extends TestCase {
-
-    private MockPropertyChangeListener mockListener;
-
-    public void setUp() {
-        mockListener = new MockPropertyChangeListener();
-    }
-
-    public void testStrokeIsNotNullByDefault() {
-        final PPath path = new PPath();
-        assertNotNull(path.getStroke());
-    }
-
-    public void testStrokePaintIsBlackByDefault() {
-        final PPath path = new PPath();
-        assertEquals(Color.BLACK, path.getStrokePaint());
-    }
-
-    public void testClone() {
-        PPath p = PPath.createEllipse(0, 0, 100, 100);        
-        PPath cloned = (PPath) p.clone();
-        assertEquals(p.getBounds(), cloned.getBounds());
-        //assertEquals(p.getPathReference()., cloned.getPathReference());
-    }
-
-    public void testSerialization() throws IOException, ClassNotFoundException {
-        final PPath srcPath = PPath.createEllipse(0, 0, 100, 100);
-        final PBounds srcBounds = srcPath.getBounds();
-
-        final File file = File.createTempFile("test", "ser");
-
-        serializeToFile(srcPath, file);
-        final PPath resultPath = deserializeFromFile(srcBounds, file);
-        file.deleteOnExit();
-
-        assertEquals(resultPath.getBounds(), srcBounds);
-    }
-
-    private PPath deserializeFromFile(final PBounds b, final File file) throws FileNotFoundException, IOException,
-            ClassNotFoundException {
-        PPath path;
-        final FileInputStream fin = new FileInputStream(file);
-        final ObjectInputStream in = new ObjectInputStream(fin);
-        path = (PPath) in.readObject();
-
-        return path;
-    }
-
-    private void serializeToFile(final PPath p, final File file) throws FileNotFoundException, IOException {
-        final FileOutputStream fout = new FileOutputStream(file);
-        final PObjectOutputStream out = new PObjectOutputStream(fout);
-        out.writeObjectTree(p);
-        out.flush();
-        out.close();
-    }
-
-    public void testCreateRectangleReturnsValidPPath() {
-        final PPath path = PPath.createRectangle(0, 0, 100, 50);
-        assertNotNull(path);
-
-        // Seems like rounding is affecting the bounds greatly
-        PiccoloAsserts.assertEquals(new PBounds(0, 0, 100, 50), path.getBounds(), 2.0d);
-    }
-
-    public void testCreateEllipseReturnsValidPPath() {
-        final PPath path = PPath.createEllipse(0, 0, 100, 50);
-        assertNotNull(path);
-
-        // Seems like rounding is affecting the bounds greatly
-        PiccoloAsserts.assertEquals(new PBounds(0, 0, 100, 50), path.getBounds(), 2.0d);
-    }
-
-    public void testCreateRoundedRectReturnsValidPPath() {
-        final PPath path = PPath.createRoundRectangle(0, 0, 100, 50, 10, 10);
-        assertNotNull(path);
-
-        // Seems like rounding is affecting the bounds greatly
-        PiccoloAsserts.assertEquals(new PBounds(0, 0, 100, 50), path.getBounds(), 2.0d);
-    }
-
-    public void testCreateLineReturnsValidPPath() {
-        final PPath path = PPath.createLine(0, 0, 100, 0);
-        assertNotNull(path);
-
-        // Seems like rounding is affecting the bounds greatly
-        PiccoloAsserts.assertEquals(new PBounds(0, 0, 100, 0), path.getBounds(), 2.0d);
-    }
-
-    public void testCreatePolyLinePoint2DReturnsValidPPath() {
-        final PPath path = PPath.createPolyline(new Point2D[] { new Point2D.Double(0, 0), new Point2D.Double(100, 50),
-                new Point2D.Double(100, 0) });
-        assertNotNull(path);
-
-        // Seems like rounding is affecting the bounds greatly
-        PiccoloAsserts.assertEquals(new PBounds(0, 0, 100, 50), path.getBounds(), 2.0d);
-    }
-
-    public void testCreatePolyLineFloatsReturnsValidPPath() {
-        final PPath path = PPath.createPolyline(new float[] { 0, 100, 100 }, new float[] { 0, 50, 0 });
-        assertNotNull(path);
-
-        // Seems like rounding is affecting the bounds greatly
-        PiccoloAsserts.assertEquals(new PBounds(0, 0, 100, 50), path.getBounds(), 2.0d);
-    }
-
-    public void testSetStrokePaintPersists() {
-        final PPath path = new PPath();
-        path.setStrokePaint(Color.RED);
-        assertEquals(Color.RED, path.getStrokePaint());
-    }
-
-    public void testSetStrokeFiresPropertyChangeEvent() {
-        final PPath path = new PPath();
-        path.addPropertyChangeListener(PPath.PROPERTY_STROKE_PAINT, mockListener);
-        path.setStrokePaint(Color.RED);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testChangingPathFiresPropertyChangeEvent() {
-        final PPath path = new PPath();
-        path.addPropertyChangeListener(PPath.PROPERTY_PATH, mockListener);
-        path.append(new Rectangle2D.Double(0, 0, 100, 50), true);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-}
diff --git a/examples/pom.xml b/examples/pom.xml
index 0134414..eea9d7d 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -34,16 +34,16 @@
   area property change listeners will not be notified.
-     *
-     * @return the area backing this area node
-     */
-    public Area getAreaReference() {
-        return area;
-    }
-
-    /**
-     * Add the shape of the specified area to the shape of this area node.
-     * The resulting shape of this area node will include the union of both shapes,
-     * or all areas that were contained in either this or the specified area.
-     *
-     * @param area area to add, must not be null
-     * @throws NullPointerException if area is null
-     */
-    public void add(final Area area) {
-        Area oldArea = (Area) this.area.clone();
-        this.area.add(area);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "area", oldArea, getArea());
-    }
-
-    /**
-     * Set the shape of this area node to be the combined area of its current
-     * shape and the shape of the specified area, minus their intersection. The
-     * resulting shape of this area node will include only areas that were contained
-     * in either this area node or in the specified area, but not in both. 
-     *
-     * @param area area to exclusive or, must not be null
-     * @throws NullPointerException if area is null
-     */
-    public void exclusiveOr(final Area area) {
-        Area oldArea = (Area) this.area.clone();
-        this.area.exclusiveOr(area);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "area", oldArea, getArea());
-    }
-
-    /**
-     * Set the shape of this area node to the intersection of its current shape
-     * and the shape of the specified area. The resulting shape of this area node
-     * will include only areas that were contained in both this area node and also
-     * in the specified area.
-     *
-     * @param area area to intersect, must not be null
-     * @throws NullPointerException if area is null
-     */
-    public void intersect(final Area area) {
-        Area oldArea = (Area) this.area.clone();
-        this.area.intersect(area);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "area", oldArea, getArea());
-    }
-
-    /**
-     * Subtract the shape of the specified area from the shape of this area node.
-     * The resulting shape of this area node will include areas that were contained
-     * only in this area node and not in the specified area.
-     *
-     * @param area area to subtract, must not be null
-     * @throws NullPointerException if area is null
-     */
-    public void subtract(final Area area) {
-        Area oldArea = (Area) this.area.clone();
-        this.area.subtract(area);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "area", oldArea, getArea());
-    }
-
-    /**
-     * Removes all of the geometry from this area node and restores it to an empty area.
-     */
-    public void reset() {
-        Area oldArea = (Area) area.clone();
-        area.reset();
-        updateBoundsFromShape();
-        firePropertyChange(-1, "area", oldArea, getArea());
-    }
-
-    /**
-     * Return true if this area node represents an empty area.
-     *
-     * @return true if this area node represents an empty area
-     */
-    public boolean isEmpty() {
-        return area.isEmpty();
-    }
-
-    /**
-     * Return true if this area node consists entirely of straight-edged polygonal geometry.
-     *
-     * @return true if this area node consists entirely of straight-edged polygonal geometry
-     */
-    public boolean isPolygonal() {
-        return area.isPolygonal();
-    }
-
-    /**
-     * Return true if this area node is rectangular in shape.
-     *
-     * @return true if this area node is rectangular in shape
-     */
-    public boolean isRectangular() {
-        return area.isRectangular();
-    }
-
-    /**
-     * Return true if this area node 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
-     * SEG_MOVETO segments that appear in the path. 
-     *
-     * @return true if this area node is comprised of a single closed subpath
-     */
-    public boolean isSingular() {
-        return area.isSingular();
-    }
-
-    // todo:
-    //    should modifiers return this to allow chaining, e.g. add(area0).intersect(area1)
-    //    test serialization, may have to add custom code to serialize areas
-
-    /** {@inheritDoc} */
-    protected Shape getShape() {
-        return area;
-    }
-
-    /** {@inheritDoc} */
-    protected void transform(final AffineTransform transform) {
-        area.transform(transform);
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/PPath.java b/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/PPath.java
deleted file mode 100644
index 3ed3763..0000000
--- a/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/PPath.java
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.Shape;
-import java.awt.Stroke;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.CubicCurve2D;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.Line2D;
-import java.awt.geom.Path2D;
-import java.awt.geom.QuadCurve2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.awt.geom.PathIterator;
-
-/**
- * Abstract path node.
- */
-public abstract class PPath extends PShape {
-
-    /** Path for this path node. */
-    private final Path2D path;
-
-
-    /**
-     * Create a new path node with the specified path.
-     *
-     * @param path path
-     */
-    private PPath(final Path2D path) {
-        this.path = (Path2D) path.clone();
-        updateBoundsFromShape();
-    }
-
-    /**
-     * Create a new path node with the specified path and stroke.
-     *
-     * @param path path
-     * @param stroke stroke
-     */
-    private PPath(final Path2D path, final Stroke stroke) {
-        this.path = (Path2D) path.clone();
-        setStroke(stroke);
-    }
-
-
-    /**
-     * Path node with coordinates stored in single precision floating point.
-     */
-    public static final class Float extends PPath {
-
-        /**
-         * Create a new empty path node.
-         */
-        public Float() {
-            super(new Path2D.Float());
-        }
-
-        /**
-         * Create a new empty path node with the specified stroke.
-         *
-         * @param stroke stroke
-         */
-        public Float(final Stroke stroke) {
-            super(new Path2D.Float(), stroke);
-        }
-
-        /**
-         * Create a new path node with the specified shape.
-         *
-         * @param shape shape, must not be null
-         * @throws NullPointerException if shape is null
-         */
-        public Float(final Shape shape) {
-            super(new Path2D.Float(shape));
-        }
-
-        /**
-         * Create a new path node with the specified shape and stroke.
-         *
-         * @param shape shape, must not be null
-         * @param stroke stroke
-         * @throws NullPointerException if shape is null
-         */
-        public Float(final Shape shape, final Stroke stroke) {
-            super(new Path2D.Float(shape), stroke);
-        }
-
-        /**
-         * Create a new path node with the specified path.
-         *
-         * @param path path, must not be null
-         * @throws NullPointerException if path is null
-         */
-        public Float(final Path2D.Float path) {
-            super(path);
-        }
-
-        /**
-         * Create a new path node with the specified path and stroke.
-         *
-         * @param path path, must not be null
-         * @param stroke stroke, must not be null
-         * @throws NullPointerException if path is null
-         */
-        public Float(final Path2D.Float path, final Stroke stroke) {
-            super(path, stroke);
-        }
-    }
-
-    /**
-     * Path node with coordinates stored in double precision floating point.
-     */
-    public static final class Double extends PPath {
-
-        /**
-         * Create a new empty path node.
-         */
-        public Double() {
-            super(new Path2D.Double());
-        }
-
-        /**
-         * Create a new empty path node with the specified stroke.
-         *
-         * @param stroke stroke
-         */
-        public Double(final Stroke stroke) {
-            super(new Path2D.Double(), stroke);
-        }
-
-        /**
-         * Create a new path node with the specified shape.
-         *
-         * @param shape shape, must not be null
-         * @throws NullPointerException if shape is null
-         */
-        public Double(final Shape shape) {
-            super(new Path2D.Double(shape));
-        }
-
-        /**
-         * Create a new path node with the specified shape and stroke.
-         *
-         * @param shape shape, must not be null
-         * @param stroke stroke
-         * @throws NullPointerException if shape is null
-         */
-        public Double(final Shape shape, final Stroke stroke) {
-            super(new Path2D.Double(shape), stroke);
-        }
-
-        /**
-         * Create a new path node with the specified path.
-         *
-         * @param path path, must not be null
-         * @throws NullPointerException if path is null
-         */
-        public Double(final Path2D.Double path) {
-            super(path);
-        }
-
-        /**
-         * Create a new path node with the specified path and stroke.
-         *
-         * @param path path, must not be null
-         * @param stroke stroke
-         * @throws NullPointerException if path is null
-         */
-        public Double(final Path2D.Double path, final Stroke stroke) {
-            super(path, stroke);
-        }
-    }
-
-
-    /**
-     * Create and return a new path node with the specified arc in single
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate of the upper-left corner of the arc's framing rectangle
-     * @param y y coordinate of the upper-left corner of the arc's framing rectangle
-     * @param width width of the full ellipse of which this arc is a partial section
-     * @param height height of the full ellipse of which this arc is a partial section
-     * @param start starting angle of the arc in degrees
-     * @param extent angular extent of the arc in degrees
-     * @param type closure type for the arc, one of {@link Arc2D#OPEN}, {@link Arc2D#CHORD},
-     *    or {@link Arc2D#PIE}
-     * @return a new path node with the specified arc in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createArc(final float x,
-                                        final float y,
-                                        final float width,
-                                        final float height,
-                                        final float start,
-                                        final float extent,
-                                        final int type) {
-        return new PPath.Float(new Arc2D.Float(x, y, width, height, start, extent, type));
-    }
-
-    /**
-     * Create and return a new path node with the specified cubic curve in single
-     * precision floating point coordinates.
-     *
-     * @param x1 x coordinate of the start point
-     * @param y1 y coordinate of the start point
-     * @param ctrlx1 x coordinate of the first control point
-     * @param ctrly1 y coordinate of the first control point
-     * @param ctrlx2 x coordinate of the second control point
-     * @param ctrly2 y coordinate of the second control point
-     * @param x2 x coordinate of the end point
-     * @param y2 y coordinate of the end point
-     * @return a new path node with the specified cubic curve in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createCubicCurve(final float x1,
-                                               final float y1,
-                                               final float ctrlx1,
-                                               final float ctrly1,
-                                               final float ctrlx2,
-                                               final float ctrly2,
-                                               final float x2,
-                                               final float y2) {
-        return new PPath.Float(new CubicCurve2D.Float(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
-    }
-
-    /**
-     * Create and return a new path node with the specified ellipse in single
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     * @param width width
-     * @param height height
-     * @return a new path node with the specified ellipse in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createEllipse(final float x, final float y, final float width, final float height) {
-        return new PPath.Float(new Ellipse2D.Float(x, y, width, height));
-    }
-
-    /**
-     * Create and return a new path node with the specified line in single
-     * precision floating point coordinates.
-     *
-     * @param x1 x coordinate of the start point
-     * @param y1 y coordinate of the start point
-     * @param x2 x coordinate of the end point
-     * @param y2 y coordinate of the end point
-     * @return a new path node with the specified line in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createLine(final float x1, final float y1, final float x2, final float y2) {
-        return new PPath.Float(new Line2D.Float(x1, y1, x2, y2));
-    }
-
-    /*
-      need setPathToPolyline
-    public static final PPath createPolyline(final float[] xp, final float[] yp) {
-    }
-
-    public static final PPath createPolyline(final Point2D.Float[] points) {
-    }
-    */
-
-    /**
-     * Create and return a new path node with the specified quadratic curve in single
-     * precision floating point coordinates.
-     *
-     * @param x1 x coordinate of the start point
-     * @param y1 y coordinate of the start point
-     * @param ctrlx x coordinate of the control point
-     * @param ctrly y coordinate of the control point
-     * @param x2 x coordinate of the end point
-     * @param y2 y coordinate of the end point
-     * @return a new path node with the specified quadratic curve in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createQuadCurve(final float x1,
-                                              final float y1,
-                                              final float ctrlx,
-                                              final float ctrly,
-                                              final float x2,
-                                              final float y2) {
-        return new PPath.Float(new QuadCurve2D.Float(x1, y1, ctrlx, ctrly, x2, y2));
-    }
-
-    /**
-     * Create and return a new path node with the specified rectangle in single
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     * @param width width
-     * @param height height
-     * @return a new path node with the specified rectangle in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createRectangle(final float x, final float y, final float width, final float height) {
-        return new PPath.Float(new Rectangle2D.Float(x, y, width, height));
-    }
-
-    /**
-     * Create and return a new path node with the specified round rectangle in single
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     * @param width width
-     * @param height height
-     * @param arcWidth width of the arc that rounds off the corners
-     * @param arcHeight height of the arc that rounds off the corners
-     * @return a new path node with the specified round rectangle in single
-     *    precision floating point coordinates
-     */
-    public static final PPath createRoundRectangle(final float x,
-                                                   final float y,
-                                                   final float width,
-                                                   final float height,
-                                                   final float arcWidth,
-                                                   final float arcHeight) {
-        return new PPath.Float(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
-    }
-
-    /**
-     * Create and return a new path node with the specified arc in double
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate of the upper-left corner of the arc's framing rectangle
-     * @param y y coordinate of the upper-left corner of the arc's framing rectangle
-     * @param width width of the full ellipse of which this arc is a partial section
-     * @param height height of the full ellipse of which this arc is a partial section
-     * @param start starting angle of the arc in degrees
-     * @param extent angular extent of the arc in degrees
-     * @param type closure type for the arc, one of {@link Arc2D#OPEN}, {@link Arc2D#CHORD},
-     *    or {@link Arc2D#PIE}
-     * @return a new path node with the specified arc in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createArc(final double x,
-                                        final double y,
-                                        final double width,
-                                        final double height,
-                                        final double start,
-                                        final double extent,
-                                        final int type) {
-        return new PPath.Double(new Arc2D.Double(x, y, width, height, start, extent, type));
-    }
-
-    /**
-     * Create and return a new path node with the specified cubic curve in double
-     * precision floating point coordinates.
-     *
-     * @param x1 x coordinate of the start point
-     * @param y1 y coordinate of the start point
-     * @param ctrlx1 x coordinate of the first control point
-     * @param ctrly1 y coordinate of the first control point
-     * @param ctrlx2 x coordinate of the second control point
-     * @param ctrly2 y coordinate of the second control point
-     * @param x2 x coordinate of the end point
-     * @param y2 y coordinate of the end point
-     * @return a new path node with the specified cubic curve in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createCubicCurve(final double x1,
-                                               final double y1,
-                                               final double ctrlx1,
-                                               final double ctrly1,
-                                               final double ctrlx2,
-                                               final double ctrly2,
-                                               final double x2,
-                                               final double y2) {
-        return new PPath.Double(new CubicCurve2D.Double(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
-    }
-
-    /**
-     * Create and return a new path node with the specified ellipse in double
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     * @param width width
-     * @param height height
-     * @return a new path node with the specified ellipse in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createEllipse(final double x, final double y, final double width, final double height) {
-        return new PPath.Double(new Ellipse2D.Double(x, y, width, height));
-    }
-
-    /**
-     * Create and return a new path node with the specified line in double
-     * precision floating point coordinates.
-     *
-     * @param x1 x coordinate of the start point
-     * @param y1 y coordinate of the start point
-     * @param x2 x coordinate of the end point
-     * @param y2 y coordinate of the end point
-     * @return a new path node with the specified line in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createLine(final double x1, final double y1, final double x2, final double y2) {
-        return new PPath.Double(new Line2D.Double(x1, y1, x2, y2));
-    }
-
-    /*
-    public static final PPath createPolyline(final double[] xp, final double[] yp) {
-    }
-
-    public static final PPath createPolyline(final Point2D.Double[] points) {
-    }
-    */
-
-    /**
-     * Create and return a new path node with the specified quadratic curve in double
-     * precision floating point coordinates.
-     *
-     * @param x1 x coordinate of the start point
-     * @param y1 y coordinate of the start point
-     * @param ctrlx x coordinate of the control point
-     * @param ctrly y coordinate of the control point
-     * @param x2 x coordinate of the end point
-     * @param y2 y coordinate of the end point
-     * @return a new path node with the specified quadratic curve in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createQuadCurve(final double x1,
-                                              final double y1,
-                                              final double ctrlx,
-                                              final double ctrly,
-                                              final double x2,
-                                              final double y2) {
-        return new PPath.Double(new QuadCurve2D.Double(x1, y1, ctrlx, ctrly, x2, y2));
-    }
-
-    /**
-     * Create and return a new path node with the specified rectangle in double
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     * @param width width
-     * @param height height
-     * @return a new path node with the specified rectangle in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createRectangle(final double x, final double y, final double width, final double height) {
-        return new PPath.Double(new Rectangle2D.Double(x, y, width, height));
-    }
-
-    /**
-     * Create and return a new path node with the specified round rectangle in double
-     * precision floating point coordinates.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     * @param width width
-     * @param height height
-     * @param arcWidth width of the arc that rounds off the corners
-     * @param arcHeight height of the arc that rounds off the corners
-     * @return a new path node with the specified round rectangle in double
-     *    precision floating point coordinates
-     */
-    public static final PPath createRoundRectangle(final double x,
-                                                   final double y,
-                                                   final double width,
-                                                   final double height,
-                                                   final double arcWidth,
-                                                   final double arcHeight) {
-        return new PPath.Double(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
-    }
-
-
-    /**
-     * Return a copy of the path backing this path node.
-     *
-     * @return a copy of the path backing this path node
-     */
-    public final Path2D getPath() {
-        return (Path2D) path.clone();
-    }
-
-    /**
-     * Return the path backing this node.  The returned path must not be
-     * modified or the bounds of this node may no longer be valid and any
-     * path property change listeners will not be notified.
-     *
-     * @return the path backing this path node
-     */
-    public final Path2D getPathReference() {
-        return path;
-    }
-
-    /**
-     * Append the geometry of the specified shape to this path node, 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 node.
-     *
-     * @param shape shape to append to this path node
-     * @param connect true to turn an initial moveTo segment into a
-     *    lineTo segment to connect the new geometry to the existing path
-     */
-    public final void append(final Shape shape, final boolean connect) {
-        Path2D oldPath = (Path2D) path.clone();
-        path.append(shape, connect);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Append the geometry of the specified path iterator to this path node, 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 path iterator 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.
-     *
-     * @param pathIterator path iterator to append to this path node
-     * @param connect true to turn an initial moveTo segment into a
-     *    lineTo segment to connect the new geometry to the existing path
-     */
-    public final void append(final PathIterator pathIterator, final boolean connect) {
-        Path2D oldPath = (Path2D) path.clone();
-        path.append(pathIterator, connect);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Add a curved segment, defined by three new points, to this path node by drawing
-     * a Bézier curve that intersects both the current coordinates and the specified
-     * coordinates (x3,y3), using the specified points (x1,y1)
-     * and (x2,y2) as Bézier control points. All coordinates are specified in
-     * double precision. 
-     *
-     * @param x1 x coordinate of the first Bézier control point
-     * @param y1 y coordinate of the first Bézier control point
-     * @param x2 x coordinate of the second Bézier control point
-     * @param y2 y coordinate of the second Bézier control point
-     * @param x3 x coordinate of the final end point
-     * @param y3 y coordinate of the final end point
-     */
-    public final void curveTo(final double x1,
-                              final double y1,
-                              final double x2,
-                              final double y2,
-                              final double x3,
-                              final double y3) {
-        Path2D oldPath = (Path2D) path.clone();
-        path.curveTo(x1, y1, x2, y2, x3, y3);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Add a point to this path node by drawing a straight line from the
-     * current coordinates to the new specified coordinates specified in double precision.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     */
-    public final void lineTo(final double x, final double y) {
-        Path2D oldPath = (Path2D) path.clone();
-        path.lineTo(x, y);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Add a point to this path node by moving to the specified coordinates
-     * specified in double precision.
-     *
-     * @param x x coordinate
-     * @param y y coordinate
-     */
-    public final void moveTo(final double x, final double y) {
-        Path2D oldPath = (Path2D) path.clone();
-        path.moveTo(x, y);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Add a curved segment, defined by two new points, to this path node by
-     * drawing a Quadratic curve that intersects both the current coordinates and
-     * the specified coordinates (x2,y2), using the specified point
-     * (x1,y1) as a quadratic parametric control point.  All coordinates
-     * are specified in double precision.
-     *
-     * @param x1 x coordinate of the quadratic control point
-     * @param y1 y coordinate of the quadratic control point
-     * @param x2 x coordinate of the final end point
-     * @param y2 y coordinate of the final end point
-     */
-    public final void quadTo(final double x1, final double y1, final double x2, final double y2) {
-        Path2D oldPath = (Path2D) path.clone();
-        path.quadTo(x1, y1, x2, y2);
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Reset the geometry for this path node to empty.
-     */
-    public final void reset() {
-        Path2D oldPath = (Path2D) path.clone();
-        path.reset();
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    /**
-     * Close 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. 
-     */
-    public final void closePath() {
-        Path2D oldPath = (Path2D) path.clone();
-        path.closePath();
-        updateBoundsFromShape();
-        firePropertyChange(-1, "path", oldPath, getPath());
-    }
-
-    // todo:  setPathTo...
-
-    /** {@inheritDoc} */
-    protected final Shape getShape() {
-        return path;
-    }
-
-    /** {@inheritDoc} */
-    protected final void transform(final AffineTransform transform) {
-        path.transform(transform);
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/PShape.java b/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/PShape.java
deleted file mode 100644
index 1dca8e0..0000000
--- a/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/PShape.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Paint;
-import java.awt.Shape;
-import java.awt.Stroke;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-
-import org.piccolo2d.PNode;
-
-import org.piccolo2d.util.PPaintContext;
-
-/**
- * Abstract shape node.
- */
-public abstract class PShape extends PNode {
-
-    /** Stroke for this shape node, defaults to {@link #DEFAULT_STROKE}. */
-    private transient Stroke stroke = DEFAULT_STROKE;
-
-    /** Stroke paint for this shape node, defaults to {@link #DEFAULT_STROKE_PAINT}. */
-    private Paint strokePaint = DEFAULT_STROKE_PAINT;
-
-    /** True if bounds are currently being updated to match the shape. */
-    private transient boolean updatingBoundsFromShape = false;
-
-    /** Default paint for this shape node, Color.WHITE. */
-    public static final Paint DEFAULT_PAINT = Color.WHITE;
-
-    /** Default stroke, a basic stroke of width 1.0f. */
-    public static final Stroke DEFAULT_STROKE = new BasicStroke(1.0f);
-
-    /** Default stroke paint, Color.BLACK. */
-    public static final Paint DEFAULT_STROKE_PAINT = Color.BLACK;
-
-
-    /**
-     * This is an abstract class that cannot be instantiated directly.
-     */
-    protected PShape() {
-        super();
-        setPaint(DEFAULT_PAINT);
-    }
-
-
-    /**
-     * Return the shape for this shape node.
-     *
-     * @return the shape for this shape node
-     */
-    protected abstract Shape getShape();
-
-    /**
-     * Apply the specified transform to the shape for this shape node.
-     *
-     * @param transform transform to apply to the shape for this shape node
-     */
-    protected abstract void transform(AffineTransform transform);
-
-
-    /**
-     * Return the stroke for this shape node.  Defaults to {@link #DEFAULT_STROKE}.
-     *
-     * @return the stroke for this shape node
-     */
-    public final Stroke getStroke() {
-        return stroke;
-    }
-
-    /**
-     * Set the stroke for this shape node to stroke.  This is
-     * a bound property.
-     *
-     * @param stroke stroke for this shape node
-     */
-    public final void setStroke(final Stroke stroke) {
-        Stroke oldStroke = this.stroke;
-        this.stroke = stroke;
-        updateBoundsFromShape();
-        invalidatePaint();
-        firePropertyChange(-1, "stroke", oldStroke, this.stroke);
-    }
-
-    /**
-     * Return the stroke paint for this shape node.  Defaults to {@link #DEFAULT_STROKE_PAINT}.
-     *
-     * @return the stroke paint for this shape node
-     */
-    public final Paint getStrokePaint() {
-        return strokePaint;
-    }
-
-    /**
-     * Set the stroke paint for this shape node to strokePaint.  This is
-     * a bound property.
-     *
-     * @param strokePaint stroke paint for this shape node
-     */
-    public final void setStrokePaint(final Paint strokePaint) {
-        Paint oldStrokePaint = this.strokePaint;
-        this.strokePaint = strokePaint;
-        invalidatePaint();
-        firePropertyChange(-1, "strokePaint", oldStrokePaint, this.strokePaint);
-    }
-
-    /**
-     * Update the bounds of this shape node from its shape.
-     */
-    protected final void updateBoundsFromShape() {
-        updatingBoundsFromShape = true;
-        final Rectangle2D b = getBoundsWithStroke();
-        setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight());
-        updatingBoundsFromShape = false;
-    }
-
-    /**
-     * Return the bounds of this node, taking the stroke into consideration if necessary.
-     *
-     * @return the bounds of this node, taking the stroke into consideration if necessary
-     */
-    protected final Rectangle2D getBoundsWithStroke() {
-        if (stroke != null) {
-            return stroke.createStrokedShape(getShape()).getBounds2D();
-        }
-        else {
-            return getShape().getBounds2D();
-        }
-    }
-
-    /** {@inheritDoc} */
-    protected final void internalUpdateBounds(final double x, final double y, final double width, final double height) {
-        if (updatingBoundsFromShape) {
-            return;
-        }
-
-        final Rectangle2D bounds = getShape().getBounds2D();
-        final Rectangle2D strokeBounds = getBoundsWithStroke();
-        final double strokeOutset = Math.max(strokeBounds.getWidth() - bounds.getWidth(),
-                                             strokeBounds.getHeight() - bounds.getHeight());
-
-        double adjustedX = x + strokeOutset / 2.0d;
-        double adjustedY = y + strokeOutset / 2.0d;
-        double adjustedWidth = width - strokeOutset;
-        double adjustedHeight = height - strokeOutset;
-
-        final double scaleX;
-        if (adjustedWidth == 0 || bounds.getWidth() == 0) {
-            scaleX = 1.0d;
-        }
-        else {
-            scaleX = adjustedWidth / bounds.getWidth();
-        }
-        final double scaleY;
-        if (adjustedHeight == 0 || bounds.getHeight() == 0) {
-            scaleY = 1.0d;
-        }
-        else {
-            scaleY = adjustedHeight / bounds.getHeight();
-        }
-
-        final AffineTransform transform = new AffineTransform();
-        transform.translate(adjustedX, adjustedY);
-        transform.scale(scaleX, scaleY);
-        transform.translate(-bounds.getX(), -bounds.getY());
-        transform(transform);
-    }
-
-    /** {@inheritDoc} */
-    public final boolean intersects(final Rectangle2D bounds) {
-        if (super.intersects(bounds)) {
-            if (getPaint() != null && getShape().intersects(bounds)) {
-                return true;
-            }
-            else if (stroke != null && strokePaint != null) {
-                return stroke.createStrokedShape(getShape()).intersects(bounds);
-            }
-        }
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    protected final void paint(final PPaintContext paintContext) {
-        final Paint p = getPaint();
-        final Graphics2D g2 = paintContext.getGraphics();
-
-        if (p != null) {
-            g2.setPaint(p);
-            g2.fill(getShape());
-        }
-
-        if (stroke != null && strokePaint != null) {
-            g2.setPaint(strokePaint);
-            g2.setStroke(stroke);
-            g2.draw(getShape());
-        }
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/package-info.java b/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/package-info.java
deleted file mode 100644
index 0e3bfdc..0000000
--- a/jdk16/src/main/java/org/piccolo2d/jdk16/nodes/package-info.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * Piccolo2D nodes that require a minimum JDK version of 1.6.
- */
-package org.piccolo2d.jdk16.nodes;
\ No newline at end of file
diff --git a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/AbstractPPathTest.java b/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/AbstractPPathTest.java
deleted file mode 100644
index 617e5d2..0000000
--- a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/AbstractPPathTest.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.Color;
-import java.awt.Shape;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-
-import org.piccolo2d.util.PBounds;
-import org.piccolo2d.util.PObjectOutputStream;
-
-/**
- * Abstract unit test for subclasses of PPath.
- */
-public abstract class AbstractPPathTest extends AbstractPShapeTest {
-
-    private static final double TOLERANCE = 0.0001d;
-    private static final double LOW_TOLERANCE = 1.0d;
-
-    /** {@inheritDoc} */
-    protected void setUp() {
-        super.setUp();
-    }
-
-    /** {@inheritDoc} */
-    protected PShape createShapeNode() {
-        return createPathNode();
-    }
-
-    /**
-     * Create a new instance of a subclass of PPath to test.
-     *
-     * @return a new instance of a subclass of PPath to test
-     */
-    protected abstract PPath createPathNode();
-
-    // todo:  rewrite in terms of createPathNode()
-
-    public void testClone() {
-        PPath p = PPath.createEllipse(0, 0, 100, 100);        
-        PPath cloned = (PPath) p.clone();
-        assertEquals(p.getBounds(), cloned.getBounds());
-        //assertEquals(p.getPathReference()., cloned.getPathReference());
-    }
-
-    public void testSerialization() throws IOException, ClassNotFoundException {
-        final PPath srcPath = PPath.createEllipse(0, 0, 100, 100);
-        final PBounds srcBounds = srcPath.getBounds();
-
-        final File file = File.createTempFile("test", "ser");
-
-        serializeToFile(srcPath, file);
-        final PPath resultPath = deserializeFromFile(srcBounds, file);
-        file.deleteOnExit();
-
-        assertEquals(resultPath.getBounds(), srcBounds);
-    }
-
-    private PPath deserializeFromFile(final PBounds b, final File file) throws FileNotFoundException, IOException,
-            ClassNotFoundException {
-        PPath path;
-        final FileInputStream fin = new FileInputStream(file);
-        final ObjectInputStream in = new ObjectInputStream(fin);
-        path = (PPath) in.readObject();
-
-        return path;
-    }
-
-    private void serializeToFile(final PPath p, final File file) throws FileNotFoundException, IOException {
-        final FileOutputStream fout = new FileOutputStream(file);
-        final PObjectOutputStream out = new PObjectOutputStream(fout);
-        out.writeObjectTree(p);
-        out.flush();
-        out.close();
-    }
-
-    public void testCreateArcFloat() {
-        assertNotNull(PPath.createArc(0.0f, 0.0f, 50.0f, 100.0f, 25.0f, 75.0f, Arc2D.OPEN));
-    }
-
-    public void testCreateCubicCurveFloat() {
-        assertNotNull(PPath.createCubicCurve(0.0f, 0.0f, 25.0f, 75.0f, 75.0f, 25.0f, 50.0f, 100.0f));
-    }
-
-    public void testCreateEllipseFloat() {
-        assertNotNull(PPath.createEllipse(0.0f, 0.0f, 50.0f, 100.0f));
-    }
-
-    public void testCreateLineFloat() {
-        assertNotNull(PPath.createLine(0.0f, 0.0f, 50.0f, 100.0f));
-    }
-
-    public void testCreateQuadCurveFloat() {
-        assertNotNull(PPath.createQuadCurve(0.0f, 0.0f, 25.0f, 75.0f, 50.0f, 100.0f));
-    }
-
-    public void testCreateRectangleFloat() {
-        assertNotNull(PPath.createRectangle(0.0f, 0.0f, 50.0f, 100.0f));
-    }
-
-    public void testCreateRoundRectangleFloat() {
-        assertNotNull(PPath.createRoundRectangle(0.0f, 0.0f, 50.0f, 100.0f, 4.0f, 8.0f));
-    }
-
-    public void testCreateArcDouble() {
-        assertNotNull(PPath.createArc(0.0d, 0.0d, 50.0d, 100.0d, 25.0d, 75.0d, Arc2D.OPEN));
-    }
-
-    public void testCreateCubicCurveDouble() {
-        assertNotNull(PPath.createCubicCurve(0.0d, 0.0d, 25.0d, 75.0d, 75.0d, 25.0d, 50.0d, 100.0d));
-    }
-
-    public void testCreateEllipseDouble() {
-        assertNotNull(PPath.createEllipse(0.0d, 0.0d, 50.0d, 100.0d));
-    }
-
-    public void testCreateLineDouble() {
-        assertNotNull(PPath.createLine(0.0d, 0.0d, 50.0d, 100.0d));
-    }
-
-    public void testCreateQuadCurveDouble() {
-        assertNotNull(PPath.createQuadCurve(0.0d, 0.0d, 25.0d, 75.0d, 50.0d, 100.0d));
-    }
-
-    public void testCreateRectangleDouble() {
-        assertNotNull(PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d));
-    }
-
-    public void testCreateRoundRectangleDouble() {
-        assertNotNull(PPath.createRoundRectangle(0.0d, 0.0d, 50.0d, 100.0d, 4.0d, 8.0d));
-    }
-
-    public void testAppendShape() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
-        path.append(rect, true);
-        // todo:  shouldn't this be width + 2 * strokeWidth?
-        assertEquals(101.0d, path.getWidth(), TOLERANCE);
-        assertEquals(201.0d, path.getHeight(), TOLERANCE);
-    }
-
-    public void testAppendShapeNullArgument() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        try {
-            path.append((Shape) null, true);
-            fail("append((Shape) null, true) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testAppendPathIterator() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
-        PathIterator pathIterator = rect.getPathIterator(new AffineTransform());
-        path.append(pathIterator, true);
-        assertEquals(101.0d, path.getWidth(), TOLERANCE);
-        assertEquals(201.0d, path.getHeight(), TOLERANCE);
-    }
-
-    public void testAppendPathIteratorNullArgument() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        try {
-            path.append((PathIterator) null, true);
-            fail("append((PathIterator) null, true) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testCurveTo() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.curveTo(70.0d, 140.0d, 80.0d, 140.0d, 100.0d, 200.0d);
-        assertEquals(101.0d, path.getWidth(), LOW_TOLERANCE);
-        assertEquals(201.0d, path.getHeight(), LOW_TOLERANCE);
-    }
-
-    public void testLineTo() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.lineTo(100.0d, 200.0d);
-        assertEquals(101.0d, path.getWidth(), LOW_TOLERANCE);
-        assertEquals(201.0d, path.getHeight(), LOW_TOLERANCE);
-    }
-
-    public void testMoveTo() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.moveTo(100.0d, 200.0d);
-        assertEquals(51.0d, path.getWidth(), TOLERANCE);
-        assertEquals(101.0d, path.getHeight(), TOLERANCE);
-    }
-
-    public void testQuadTo() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.quadTo(70.0d, 140.0d, 100.0d, 200.0d);
-        assertEquals(101.0d, path.getWidth(), LOW_TOLERANCE);
-        assertEquals(201.0d, path.getHeight(), LOW_TOLERANCE);
-    }
-
-    public void testClosePath() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.lineTo(100.0d, 200.0d);
-        path.closePath();
-    }
-
-    public void testClosePathAlreadyClosed() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.lineTo(100.0d, 200.0d);
-        path.closePath();
-        path.closePath();
-    }
-
-    public void testIntersects() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        assertTrue(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertTrue(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testIntersectsNullStroke() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.setStroke(null);
-        assertTrue(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertTrue(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testIntersectsNullPaint() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.setPaint(null);
-        assertTrue(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testIntersectsNullPaintNullStroke() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.setPaint(null);
-        path.setStroke(null);
-        assertFalse(path.intersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.intersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testFullIntersects() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testFullIntersectsNullStroke() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.setStroke(null);
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testFullIntersectsNullPaint() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.setPaint(null);
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    public void testFullIntersectsNullPaintNullStroke() {
-        PPath path = PPath.createRectangle(0.0d, 0.0d, 50.0d, 100.0d);
-        path.setPaint(null);
-        path.setStroke(null);
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(0.0d, 0.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(25.0d, 50.0d, 2.0d, 2.0d)));
-        assertTrue(path.fullIntersects(new Rectangle2D.Double(49.0d, 99.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(-10.0d, -10.0d, 2.0d, 2.0d)));
-        assertFalse(path.fullIntersects(new Rectangle2D.Double(100.0d, 200.0d, 2.0d, 2.0d)));
-    }
-
-    /*
-    public void testPath() {
-        PPath path = createPathNode();
-        assertNotNull(path.getPath()); // or (Path) getShape(), or getPathReference() ?
-        Path2D.Double rect = new Path2D.Double((new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
-        path.setPath(rect);
-        assertEquals(rect, path.getPath());
-    }
-
-    public void testPathNullArgument() {
-        PPath path = createPathNode();
-        try {
-            path.setPath(null);
-            fail("setPath(null) expected IllegalArgumentException");
-        }
-        catch (IllegalArgumentException e) { // or NPE?
-            // expected
-        }
-    }
-
-    public void testPathBoundProperty() {
-        PPath path = createPathNode();
-        path.addPropertyChangeListener("path", mockListener);
-        Path2D.Double rect = new Path2D.Double((new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
-        path.setPath(rect);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-    */
-
-    public void testAppendShapeFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.addPropertyChangeListener("path", mockListener);
-        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
-        path.append(rect, true);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testAppendPathIteratorFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.moveTo(0.0d, 0.0d);
-        path.addPropertyChangeListener("path", mockListener);
-        Rectangle2D rect = new Rectangle2D.Double(50.0d, 100.0d, 50.0d, 100.0d);
-        PathIterator pathIterator = rect.getPathIterator(new AffineTransform());
-        path.append(pathIterator, true);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testCurveToFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.moveTo(0.0d, 0.0d);
-        path.addPropertyChangeListener("path", mockListener);
-        path.curveTo(70.0d, 140.0d, 80.0d, 140.0d, 100.0d, 200.0d);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testLineToFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.moveTo(0.0d, 0.0d);
-        path.addPropertyChangeListener("path", mockListener);
-        path.lineTo(100.0d, 200.0d);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testMoveToFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.moveTo(0.0d, 0.0d);
-        path.addPropertyChangeListener("path", mockListener);
-        path.moveTo(100.0d, 200.0d);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testQuadToFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.moveTo(0.0d, 0.0d);
-        path.addPropertyChangeListener("path", mockListener);
-        path.quadTo(70.0d, 140.0d, 100.0d, 200.0d);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testClosePathFiresPropertyChangeEvent() {
-        PPath path = createPathNode();
-        path.moveTo(0.0d, 0.0d);
-        path.lineTo(100.0d, 200.0d);
-        path.addPropertyChangeListener("path", mockListener);
-        path.closePath();
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-}
diff --git a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/AbstractPShapeTest.java b/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/AbstractPShapeTest.java
deleted file mode 100644
index 8e2c51c..0000000
--- a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/AbstractPShapeTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Paint;
-import java.awt.Stroke;
-
-import junit.framework.TestCase;
-
-/**
- * Abstract unit test for subclasses of PShape.
- */
-public abstract class AbstractPShapeTest extends TestCase {
-
-    /** Mock property change listener. */
-    protected MockPropertyChangeListener mockListener;
-
-
-    /** {@inheritDoc} */
-    protected void setUp() {
-        mockListener = new MockPropertyChangeListener();
-    }
-
-    /**
-     * Create a new instance of a subclass of PShape to test.
-     *
-     * @return a new instance of a subclass of PShape to test
-     */
-    protected abstract PShape createShapeNode();
-
-    public void testCreateShapeNode() {
-        assertNotNull(createShapeNode());
-    }
-
-    public void testDefaultPaint() {
-        PShape shape = createShapeNode();
-        assertEquals(PShape.DEFAULT_PAINT, shape.getPaint());
-    }
-
-    public void testDefaultStroke() {
-        PShape shape = createShapeNode();
-        assertEquals(PShape.DEFAULT_STROKE, shape.getStroke());
-    }
-
-    public void testDefaultStrokePaint() {
-        PShape shape = createShapeNode();
-        assertEquals(PShape.DEFAULT_STROKE_PAINT, shape.getStrokePaint());
-    }
-
-    public void testStroke() {
-        PShape shape = createShapeNode();
-        Stroke stroke = new BasicStroke(2.0f);
-        shape.setStroke(stroke);
-        assertEquals(stroke, shape.getStroke());
-    }
-
-    public void testStrokeBoundProperty() {
-        PShape shape = createShapeNode();
-        shape.addPropertyChangeListener("stroke", mockListener);
-        Stroke stroke = new BasicStroke(2.0f);
-        shape.setStroke(stroke);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testStrokePaint() {
-        PShape shape = createShapeNode();
-        Paint strokePaint = Color.RED;
-        shape.setStrokePaint(strokePaint);
-        assertEquals(strokePaint, shape.getStrokePaint());
-    }
-
-    public void testStrokePaintBoundProperty() {
-        PShape shape = createShapeNode();
-        shape.addPropertyChangeListener("strokePaint", mockListener);
-        Paint strokePaint = Color.RED;
-        shape.setStrokePaint(strokePaint);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/MockPropertyChangeListener.java b/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/MockPropertyChangeListener.java
deleted file mode 100644
index 46572bf..0000000
--- a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/MockPropertyChangeListener.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Mock PropertyChangeListener.
- */
-public class MockPropertyChangeListener implements PropertyChangeListener {
-    private final List changes = new ArrayList();
-
-    public void propertyChange(final PropertyChangeEvent evt) {
-        changes.add(evt);
-    }
-
-    public int getPropertyChangeCount() {
-        return changes.size();
-    }
-
-    public PropertyChangeEvent getPropertyChange(final int index) {
-        return (PropertyChangeEvent) changes.get(index);
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PAreaTest.java b/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PAreaTest.java
deleted file mode 100644
index e808d90..0000000
--- a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PAreaTest.java
+++ /dev/null
@@ -1,632 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.Shape;
-
-import java.awt.geom.Area;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.Line2D;
-import java.awt.geom.Rectangle2D;
-
-/**
- * Unit test for PArea.
- */
-public class PAreaTest extends AbstractPShapeTest {
-
-    private static final double TOLERANCE = 0.0001d;
-    private static final Rectangle2D FIRST = new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d);
-    private static final Rectangle2D SECOND = new Rectangle2D.Double(50.0, 50.0d, 100.0d, 100.0d);
-    private static final Rectangle2D FIRST_INTERIOR = new Rectangle2D.Double(25.0d, 25.0d, 2.0d, 2.0d);
-    private static final Rectangle2D FIRST_PATH = new Rectangle2D.Double(25.0d, 100.0d, 1.0d, 1.0d);
-    private static final Rectangle2D SECOND_INTERIOR = new Rectangle2D.Double(125.0d, 125.0d, 2.0d, 2.0d);
-    private static final Rectangle2D SECOND_PATH = new Rectangle2D.Double(125.0d, 150.0d, 1.0d, 1.0d);
-    private static final Rectangle2D INTERSECTION_INTERIOR = new Rectangle2D.Double(75.0, 75.0d, 2.0d, 2.0d);
-    private static final Rectangle2D INTERSECTION_PATH = new Rectangle2D.Double(75.0, 100.0d, 1.0d, 1.0d);
-    private static final Rectangle2D EXTERIOR = new Rectangle2D.Double(200.0, 200.0d, 2.0d, 2.0d);
-
-    /** {@inheritDoc} */
-    protected void setUp() {
-        super.setUp();
-    }
-
-    /** {@inheritDoc} */
-    protected PShape createShapeNode() {
-        return new PArea();
-    }
-
-    public void testNoArgConstructor() {
-        assertNotNull(new PArea());
-    }
-
-    public void testShapeConstructor() {
-        assertNotNull(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
-    }
-
-    public void testShapeConstructorNullArgument() {
-        try {
-            new PArea((Shape) null);
-            fail("ctr((Shape) null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testAreaConstructor() {
-        assertNotNull(new PArea(new Area()));
-    }
-
-    public void testAreaConstructorNullArgument() {
-        try {
-            new PArea((Area) null);
-            fail("ctr((Area) null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testAdd() {
-        PArea area = new PArea();
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.add(rect1);
-
-        // todo:  shouldn't this be width + 2 * strokeWidth?
-        assertEquals(151.0d, area.getWidth(), TOLERANCE);
-        assertEquals(151.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertTrue(area.intersects(FIRST_PATH));
-        assertTrue(area.intersects(SECOND_INTERIOR));
-        assertTrue(area.intersects(SECOND_PATH));
-        assertTrue(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testAddNullPaint() {
-        PArea area = new PArea();
-        area.setPaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.add(rect1);
-
-        assertEquals(151.0d, area.getWidth(), TOLERANCE);
-        assertEquals(151.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertTrue(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertTrue(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testAddNullStroke() {
-        PArea area = new PArea();
-        area.setStroke(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.add(rect1);
-
-        assertEquals(150.0d, area.getWidth(), TOLERANCE);
-        assertEquals(150.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertTrue(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertTrue(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testAddNullStrokePaint() {
-        PArea area = new PArea();
-        area.setStrokePaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.add(rect1);
-
-        assertEquals(151.0d, area.getWidth(), TOLERANCE);
-        assertEquals(151.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertTrue(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertTrue(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testAddNullArgument() {
-        PArea area = new PArea();
-        try {
-            area.add(null);
-            fail("add(null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testExclusiveOr() {
-        PArea area = new PArea();
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.exclusiveOr(rect1);
-
-        assertEquals(151.0d, area.getWidth(), TOLERANCE);
-        assertEquals(151.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertTrue(area.intersects(FIRST_PATH));
-        assertTrue(area.intersects(SECOND_INTERIOR));
-        assertTrue(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testExclusiveOrNullPaint() {
-        PArea area = new PArea();
-        area.setPaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.exclusiveOr(rect1);
-
-        assertEquals(151.0d, area.getWidth(), TOLERANCE);
-        assertEquals(151.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertTrue(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertTrue(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testExclusiveOrNullStroke() {
-        PArea area = new PArea();
-        area.setStroke(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.exclusiveOr(rect1);
-
-        assertEquals(150.0d, area.getWidth(), TOLERANCE);
-        assertEquals(150.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertTrue(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testExclusiveOrNullStrokePaint() {
-        PArea area = new PArea();
-        area.setStrokePaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.exclusiveOr(rect1);
-
-        assertEquals(151.0d, area.getWidth(), TOLERANCE);
-        assertEquals(151.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertTrue(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testExclusiveOrNullArgument() {
-        PArea area = new PArea();
-        try {
-            area.exclusiveOr(null);
-            fail("exclusiveOr(null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testIntersect() {
-        PArea area = new PArea();
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.intersect(rect1);        
-
-        assertEquals(51.0d, area.getWidth(), TOLERANCE);
-        assertEquals(51.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertTrue(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testIntersectNullPaint() {
-        PArea area = new PArea();
-        area.setPaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.intersect(rect1);        
-
-        assertEquals(51.0d, area.getWidth(), TOLERANCE);
-        assertEquals(51.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertTrue(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testIntersectNullStroke() {
-        PArea area = new PArea();
-        area.setStroke(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.intersect(rect1);        
-
-        assertEquals(50.0d, area.getWidth(), TOLERANCE);
-        assertEquals(50.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertTrue(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testIntersectNullStrokePaint() {
-        PArea area = new PArea();
-        area.setStrokePaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.intersect(rect1);        
-
-        assertEquals(51.0d, area.getWidth(), TOLERANCE);
-        assertEquals(51.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertTrue(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testIntersectNullArgument() {
-        PArea area = new PArea();
-        try {
-            area.intersect(null);
-            fail("intersect(null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testSubtract() {
-        PArea area = new PArea();
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.subtract(rect1);        
-
-        assertEquals(101.0d, area.getWidth(), TOLERANCE);
-        assertEquals(101.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertTrue(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testSubtractNullPaint() {
-        PArea area = new PArea();
-        area.setPaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.subtract(rect1);        
-
-        assertEquals(101.0d, area.getWidth(), TOLERANCE);
-        assertEquals(101.0d, area.getHeight(), TOLERANCE);
-
-        assertFalse(area.intersects(FIRST_INTERIOR));
-        assertTrue(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testSubtractNullStroke() {
-        PArea area = new PArea();
-        area.setStroke(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.subtract(rect1);        
-
-        assertEquals(100.0d, area.getWidth(), TOLERANCE);
-        assertEquals(100.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testSubtractNullStrokePaint() {
-        PArea area = new PArea();
-        area.setStrokePaint(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(FIRST);
-        area.add(rect0);
-        Area rect1 = new Area(SECOND);
-        area.subtract(rect1);        
-
-        assertEquals(101.0d, area.getWidth(), TOLERANCE);
-        assertEquals(101.0d, area.getHeight(), TOLERANCE);
-
-        assertTrue(area.intersects(FIRST_INTERIOR));
-        assertFalse(area.intersects(FIRST_PATH));
-        assertFalse(area.intersects(SECOND_INTERIOR));
-        assertFalse(area.intersects(SECOND_PATH));
-        assertFalse(area.intersects(INTERSECTION_INTERIOR));
-        assertFalse(area.intersects(INTERSECTION_PATH));
-        assertFalse(area.intersects(EXTERIOR));
-    }
-
-    public void testSubtractNullArgument() {
-        PArea area = new PArea();
-        try {
-            area.subtract(null);
-            fail("subtract(null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testReset() {
-        PArea area = new PArea();
-        area.setStroke(null);
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-
-        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect0);
-        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect1);
-
-        assertEquals(150.0d, area.getWidth(), TOLERANCE);
-        assertEquals(100.0, area.getHeight(), TOLERANCE);
-
-        area.reset();
-        assertEquals(0.0d, area.getWidth(), TOLERANCE);
-        assertEquals(0.0d, area.getHeight(), TOLERANCE);
-    }
-
-    public void testIsEmpty() {
-        assertTrue(new PArea().isEmpty());
-        assertFalse(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isEmpty());
-        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isEmpty());
-        assertFalse(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isEmpty());
-    }
-
-    public void testIsPolygonal() {
-        assertTrue(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isPolygonal());
-        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isPolygonal());
-        assertFalse(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isPolygonal());
-    }
-
-    public void testIsRectangular() {
-        assertTrue(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isRectangular());
-        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isRectangular());
-        assertFalse(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isRectangular());
-    }
-
-    public void testIsSingular() {
-        assertTrue(new PArea(new Rectangle2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isSingular());
-        assertTrue(new PArea(new Line2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isSingular());
-        assertTrue(new PArea(new Ellipse2D.Double(0.0d, 0.0d, 50.0d, 100.0d)).isSingular());
-
-        PArea exclusiveOr = new PArea();
-        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        exclusiveOr.add(rect0);
-        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
-        exclusiveOr.exclusiveOr(rect1);
-
-        assertFalse(exclusiveOr.isSingular());
-    }
-
-    /*
-    public void testArea() {
-        PArea area = new PArea();
-        assertNotNull(area.getArea()); // or (Area) getShape(), or getAreaReference() ?
-        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.setArea(rect);
-        assertEquals(rect, area.getArea());
-    }
-
-    public void testAreaNullArgument() {
-        PArea area = new PArea();
-        try {
-            area.setArea(null);
-            fail("setArea(null) expected IllegalArgumentException");
-        }
-        catch (IllegalArgumentException e) { // or NPE?
-            // expected
-        }
-    }
-
-    public void testAreaBoundProperty() {
-        PArea area = new PArea();
-        area.addPropertyChangeListener("area", mockListener);
-        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.setArea(rect);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-    */
-
-    public void testAddFiresPropertyChangeEvent() {
-        PArea area = new PArea();
-        area.addPropertyChangeListener("area", mockListener);
-        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testExclusiveOrFiresPropertyChangeEvent() {
-        PArea area = new PArea();
-        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect0);
-        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
-        area.addPropertyChangeListener("area", mockListener);
-        area.exclusiveOr(rect1);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testIntersectFiresPropertyChangeEvent() {
-        PArea area = new PArea();
-        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect0);
-        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
-        area.addPropertyChangeListener("area", mockListener);
-        area.intersect(rect1);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testSubtractFiresPropertyChangeEvent() {
-        PArea area = new PArea();
-        Area rect0 = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect0);
-        Area rect1 = new Area(new Rectangle2D.Double(50.0d, 0.0d, 100.0d, 100.0d));
-        area.addPropertyChangeListener("area", mockListener);
-        area.subtract(rect1);
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-
-    public void testResetFiresPropertyChangeEvent() {
-        PArea area = new PArea();
-        Area rect = new Area(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d));
-        area.add(rect);
-        area.addPropertyChangeListener("area", mockListener);
-        area.reset();
-        assertEquals(1, mockListener.getPropertyChangeCount());
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PPathDoubleTest.java b/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PPathDoubleTest.java
deleted file mode 100644
index 006aa7f..0000000
--- a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PPathDoubleTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.BasicStroke;
-import java.awt.Shape;
-import java.awt.Stroke;
-
-import java.awt.geom.Path2D;
-import java.awt.geom.Rectangle2D;
-
-/**
- * Unit test for PPath.Double.
- */
-public class PPathDoubleTest extends AbstractPPathTest {
-
-    /** {@inheritDoc} */
-    protected PPath createPathNode() {
-        return new PPath.Double();
-    }
-
-    public void testNoArgConstructor() {
-        assertNotNull(new PPath.Double());
-    }
-
-    public void testStrokeConstructor() {
-        assertNotNull(new PPath.Double((Stroke) null));
-        assertNotNull(new PPath.Double(new BasicStroke(2.0f)));
-    }
-
-    public void testShapeConstructor() {
-        assertNotNull(new PPath.Double(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d)));
-    }
-
-    public void testShapeStrokeConstructor() {
-        assertNotNull(new PPath.Double(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d), null));
-        assertNotNull(new PPath.Double(new Rectangle2D.Double(0.0d, 0.0d, 100.0d, 100.0d), new BasicStroke(2.0f)));
-    }
-
-    public void testShapeConstructorNullArgument() {
-        try {
-            new PPath.Double((Shape) null);
-            fail("ctr((Shape) null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testShapeStrokeConstructorNullArgument() {
-        try {
-            new PPath.Double((Shape) null, null);
-            fail("ctr((Shape) null, ) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testPathConstructor() {
-        assertNotNull(new PPath.Double(new Path2D.Double()));
-    }
-
-    public void testPathStrokeConstructor() {
-        assertNotNull(new PPath.Double(new Path2D.Double(), null));
-        assertNotNull(new PPath.Double(new Path2D.Double(), new BasicStroke(2.0f)));
-    }
-
-    public void testPathConstructorNullArgument() {
-        try {
-            new PPath.Double((Path2D) null);
-            fail("ctr((Path2D) null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testPathStrokeConstructorNullArgument() {
-        try {
-            new PPath.Double((Path2D) null, null);
-            fail("ctr((Path2D) null, ) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-}
\ No newline at end of file
diff --git a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PPathFloatTest.java b/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PPathFloatTest.java
deleted file mode 100644
index b43549b..0000000
--- a/jdk16/src/test/java/org/piccolo2d/jdk16/nodes/PPathFloatTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d.jdk16.nodes;
-
-import java.awt.BasicStroke;
-import java.awt.Shape;
-import java.awt.Stroke;
-
-import java.awt.geom.Path2D;
-import java.awt.geom.Rectangle2D;
-
-/**
- * Unit test for PPath.Float.
- */
-public class PPathFloatTest extends AbstractPPathTest {
-
-    /** {@inheritDoc} */
-    protected PPath createPathNode() {
-        return new PPath.Float();
-    }
-
-    public void testNoArgConstructor() {
-        assertNotNull(new PPath.Float());
-    }
-
-    public void testStrokeConstructor() {
-        assertNotNull(new PPath.Float((Stroke) null));
-        assertNotNull(new PPath.Float(new BasicStroke(2.0f)));
-    }
-
-    public void testShapeConstructor() {
-        assertNotNull(new PPath.Float(new Rectangle2D.Float(0.0f, 0.0f, 100.0f, 100.0f)));
-    }
-
-    public void testShapeStrokeConstructor() {
-        assertNotNull(new PPath.Float(new Rectangle2D.Float(0.0f, 0.0f, 100.0f, 100.0f), null));
-        assertNotNull(new PPath.Float(new Rectangle2D.Float(0.0f, 0.0f, 100.0f, 100.0f), new BasicStroke(2.0f)));
-    }
-
-    public void testShapeConstructorNullArgument() {
-        try {
-            new PPath.Float((Shape) null);
-            fail("ctr((Shape) null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testShapeStrokeConstructorNullArgument() {
-        try {
-            new PPath.Float((Shape) null, null);
-            fail("ctr((Shape) null, ) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testPathConstructor() {
-        assertNotNull(new PPath.Float(new Path2D.Float()));
-    }
-
-    public void testPathStrokeConstructor() {
-        assertNotNull(new PPath.Float(new Path2D.Float(), null));
-        assertNotNull(new PPath.Float(new Path2D.Float(), new BasicStroke(2.0f)));
-    }
-
-    public void testPathConstructorNullArgument() {
-        try {
-            new PPath.Float((Path2D) null);
-            fail("ctr((Path2D) null) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testStrokePathConstructorNullArgument() {
-        try {
-            new PPath.Float((Path2D) null, null);
-            fail("ctr((Path2D) null, ) expected NullPointerException");
-        }
-        catch (NullPointerException e) {
-            // expected
-        }
-    }
-}
\ No newline at end of file
diff --git a/license-piccolo.txt b/license-piccolo.txt
index 656a864..946459e 100644
--- a/license-piccolo.txt
+++ b/license-piccolo.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 2008-2013, Piccolo2D project, http://piccolo2d.org
  * Copyright (c) 1998-2008, University of Maryland
  * All rights reserved.
  *
@@ -25,4 +25,4 @@
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
\ No newline at end of file
+ */
diff --git a/pom.xml b/pom.xml
index 12627e8..ebda629 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,7 +39,7 @@