Revision: 1027
Author: heuermh
Date: Fri Jul 23 11:55:49 2010
Log: adding PShape and PArea, refactoring PPath; two tests fail, two test methods do not compile
http://code.google.com/p/piccolo2d/source/detail?r=1027

Added:
/piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PArea.java /piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PShape.java
Modified:
/piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PPath.java /piccolo2d.java/branches/ppath-refactoring/core/src/test/java/org/piccolo2d/SerializationTest.java /piccolo2d.java/branches/ppath-refactoring/core/src/test/java/org/piccolo2d/nodes/PPathTest.java

=======================================
--- /dev/null
+++ /piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PArea.java Fri Jul 23 11:55:49 2010
@@ -0,0 +1,110 @@
+/*
+ * 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.nodes;
+
+import java.awt.Shape;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+
+/**
+ * Area node.
+ */
+public class PArea extends PShape
+{
+    private Area area;
+
+
+    public PArea() {
+        super();
+        area = new Area();
+    }
+
+    public PArea(final Shape shape) {
+        if (shape == null) {
+            throw new IllegalArgumentException("shape must not be null");
+        }
+        this.area = new Area(shape);
+    }
+
+    public PArea(final Area area) {
+        if (area == null) {
+            throw new IllegalArgumentException("area must not be null");
+        }
+        this.area = new Area();
+        this.area.add(area);
+    }
+
+
+    public void add(final Area area) {
+        this.area.add(area);
+        updateBounds();
+    }
+
+    public void exclusiveOr(final Area area) {
+        this.area.exclusiveOr(area);
+        updateBounds();
+    }
+
+    public void intersect(final Area area) {
+        this.area.intersect(area);
+        updateBounds();
+    }
+
+    public void subtract(final Area area) {
+        this.area.subtract(area);
+        updateBounds();
+    }
+
+    public boolean isPolygonal() {
+        return area.isPolygonal();
+    }
+
+    public boolean isRectangular() {
+        return area.isRectangular();
+    }
+
+    public boolean isSingular() {
+        return area.isSingular();
+    }
+
+    // todo:
+    //    area property change events?
+    //    static methods
+
+    /** {...@inheritdoc} */
+    protected Shape getShape() {
+        return area;
+    }
+
+    /** {...@inheritdoc} */
+    protected void transform(final AffineTransform transform) {
+        area.transform(transform);
+    }
+}
=======================================
--- /dev/null
+++ /piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PShape.java Fri Jul 23 11:55:49 2010
@@ -0,0 +1,164 @@
+/*
+ * 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.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 {
+    private transient Stroke stroke = DEFAULT_STROKE;
+    private Paint strokePaint = DEFAULT_STROKE_PAINT;
+    public static final Stroke DEFAULT_STROKE = new BasicStroke(1.0f);
+    public static final Paint DEFAULT_STROKE_PAINT = Color.BLACK;
+
+    protected abstract Shape getShape();
+    protected abstract void transform(AffineTransform transform);
+
+    public final Stroke getStroke() {
+        return stroke;
+    }
+
+    public final void setStroke(final Stroke stroke) {
+        Stroke oldStroke = this.stroke;
+        this.stroke = stroke;
+        updateBoundsFromShape();
+        invalidatePaint();
+        firePropertyChange(-1, "stroke", oldStroke, this.stroke);
+    }
+
+    public final Paint getStrokePaint() {
+        return strokePaint;
+    }
+
+    public final void setStrokePaint(final Paint strokePaint) {
+        Paint oldStrokePaint = this.strokePaint;
+        this.strokePaint = strokePaint;
+        invalidatePaint();
+ firePropertyChange(-1, "strokePaint", oldStrokePaint, this.strokePaint);
+    }
+
+    protected final void updateBoundsFromShape() {
+        if (getShape() == null) {
+            resetBounds();
+        }
+        else {
+            final Rectangle2D b = getBoundsWithStroke();
+            setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight());
+        }
+    }
+
+    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) {
+        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;
+        double adjustedY = y + strokeOutset / 2;
+        double adjustedWidth = width - strokeOutset;
+        double adjustedHeight = height - strokeOutset;
+
+        final double scaleX;
+        if (adjustedWidth == 0 || bounds.getWidth() == 0) {
+            scaleX = 1;
+        }
+        else {
+            scaleX = adjustedWidth / bounds.getWidth();
+        }
+        final double scaleY;
+        if (adjustedHeight == 0 || bounds.getHeight() == 0) {
+            scaleY = 1;
+        }
+        else {
+            scaleY = adjustedHeight / bounds.getHeight();
+        }
+
+        // todo: cache instance as static?
+        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());
+        }
+    }
+}
=======================================
--- /piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PPath.java Mon May 10 19:42:46 2010 +++ /piccolo2d.java/branches/ppath-refactoring/core/src/main/java/org/piccolo2d/nodes/PPath.java Fri Jul 23 11:55:49 2010
@@ -28,639 +28,175 @@
  */
 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.CubicCurve2D;
 import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Point2D;
+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.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;
-
+import java.awt.geom.PathIterator;

 /**
- * <b>PPath</b> 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.
- * <P>
- * One option that applications have is to call <code>startResizeBounds</code>
- * before starting an interaction that may make the bounds very small, and
- * calling <code>endResizeBounds</code> 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.
- * <P>
- * This class also provides methods for constructing common shapes using a
- * general path.
- * <P>
- *
- * @version 1.0
- * @author Jesse Grosjean
+ * Path node.
  */
-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;
+public abstract class PPath extends PShape
+{
+    private Path2D path;
+
+    // todo: ctr with stroke?
+
+    PPath(final Path2D path) {
+        if (path == null) {
+            throw new IllegalArgumentException("path must not be null");
+        }
+        this.path = (Path2D) path.clone();
+        // todo:
+ // not sure why this call is required for this class, it is not present in original PPath
+        updateBoundsFromShape();
+    }
+
+
+    public static class Float extends PPath {
+        public Float() {
+            super(new Path2D.Float());
+        }
+        public Float(final Shape shape) {
+            super(new Path2D.Float(shape));
+        }
+        public Float(final Path2D.Float path) {
+            super(path);
+        }
+    }
+
+    public static class Double extends PPath {
+        public Double() {
+            super(new Path2D.Double());
+        }
+        public Double(final Shape shape) {
+            super(new Path2D.Double(shape));
+        }
+        public Double(final Path2D.Double path) {
+            super(path);
+        }
+    }
+
+
+ public static 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));
     }

-    /**
-     * 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;
+        return new PPath.Float(new Ellipse2D.Float(x, y, width, height));
     }

-    /**
-     * 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;
+        return new PPath.Float(new Line2D.Float(x1, y1, x2, y2));
     }

-    /**
-     * 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
-     */
+    /*
+      need setPathToPolyline
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);
+    public static PPath createPolyline(final Point2D.Float[] points) {
+    }
+    */
+
+ public static 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));
     }

-    /**
- * 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);
-        }
+ public static 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));
     }

-    /**
-     * Returns the stroke paint of the PPath.
-     *
-     * @return stroke paint of the PPath
-     */
-    public Paint getStrokePaint() {
-        return strokePaint;
+ public static 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));
     }

-    /**
-     * 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;
+
+ public static 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));
     }

-    /**
-     * 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); + public static 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));
     }

-    /** Stores the original size of the path before resizing started. */
-    public void startResizeBounds() {
-        resizePath = new GeneralPath(path);
+ public static 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));
     }

-    /** Clears the size of the path before resizing. */
-    public void endResizeBounds() {
-        resizePath = null;
+    /*
+ public static PPath createPolyline(final double[] xp, final double[] yp) {
     }

-    /**
- * 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;
+    public static PPath createPolyline(final Point2D.Double[] points) {
+    }
+    */
+
+ public static 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));
     }

-    /**
-     * 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();
-        }
+ public static 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));
     }

-    /**
-     * 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;
+ public static 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));
     }

-    /**
-     * 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);
-        }
+
+    public void append(final Shape shape, final boolean connect) {
+        path.append(shape, connect);
+        updateBoundsFromShape();
     }

-    /**
-     * Provides direct access to the underlying GeneralPath object.
-     *
-     * @return underlying GeneralPath
-     */
-    public GeneralPath getPathReference() {
-        return path;
+ public void append(final PathIterator pathIterator, final boolean connect) {
+        path.append(pathIterator, connect);
+        updateBoundsFromShape();
     }

-    /**
-     * 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();
+ public void curveTo(final double x1, final double y1, final double x2, final double y2, final double x3, final double y3) {
+        path.curveTo(x1, y1, x2, y2, x3, y3);
+        updateBoundsFromShape();
     }

-    /**
-     * 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) {
+    public void lineTo(final double x, final double y) {
         path.lineTo(x, y);
-        firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, path);
-        updateBoundsFromPath();
-        invalidatePaint();
+        updateBoundsFromShape();
     }

-    /**
- * 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();
+    public void moveTo(final double x, final double y) {
+        path.moveTo(x, y);
+        updateBoundsFromShape();
     }

-    /**
-     * Adds a curved segment, defined by three new points, to the path by
- * drawing a B&#233;zier curve that intersects both the current coordinates and - * the coordinates (x3, y3), using the specified points (x1, y1) and (x2,
-     * y2) as B&#233;zier control points.
-     *
-     * @param x1 x component of first B&#233;zier control point
-     * @param y1 y component of first B&#233;zier control point
-     * @param x2 x component of second B&#233;zier control point
-     * @param y2 y component of second B&#233;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();
+ public void quadTo(final double x1, final double y1, final double x2, final double y2) {
+        path.quadTo(x1, y1, x2, y2);
+        updateBoundsFromShape();
     }

-    /**
- * 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();
+        updateBoundsFromShape();
     }

-    /**
-     * 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);
+    // todo:  setPathTo...
+    //    path property change events
+
+    /** {...@inheritdoc} */
+    protected Shape getShape() {
+        return path;
     }

-    /**
- * 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);
+    /** {...@inheritdoc} */
+    protected void transform(final AffineTransform transform) {
+        path.transform(transform);
     }
 }
=======================================
--- /piccolo2d.java/branches/ppath-refactoring/core/src/test/java/org/piccolo2d/SerializationTest.java Mon May 10 19:42:46 2010 +++ /piccolo2d.java/branches/ppath-refactoring/core/src/test/java/org/piccolo2d/SerializationTest.java Fri Jul 23 11:55:49 2010
@@ -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.Double());
         }

         l = (PNode) l.clone(); // copy uses serialization internally
=======================================
--- /piccolo2d.java/branches/ppath-refactoring/core/src/test/java/org/piccolo2d/nodes/PPathTest.java Mon May 10 19:42:46 2010 +++ /piccolo2d.java/branches/ppath-refactoring/core/src/test/java/org/piccolo2d/nodes/PPathTest.java Fri Jul 23 11:55:49 2010
@@ -58,12 +58,12 @@
     }

     public void testStrokeIsNotNullByDefault() {
-        final PPath path = new PPath();
+        final PPath path = new PPath.Double();
         assertNotNull(path.getStroke());
     }

     public void testStrokePaintIsBlackByDefault() {
-        final PPath path = new PPath();
+        final PPath path = new PPath.Double();
         assertEquals(Color.BLACK, path.getStrokePaint());
     }

@@ -137,6 +137,7 @@
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) });
@@ -153,23 +154,25 @@
         // 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();
+        final PPath path = new PPath.Double();
         path.setStrokePaint(Color.RED);
         assertEquals(Color.RED, path.getStrokePaint());
     }

+    // move these to PShape test, add stroke
     public void testSetStrokeFiresPropertyChangeEvent() {
-        final PPath path = new PPath();
- path.addPropertyChangeListener(PPath.PROPERTY_STROKE_PAINT, mockListener);
+        final PPath path = new PPath.Double();
+        path.addPropertyChangeListener("strokePaint", mockListener);
         path.setStrokePaint(Color.RED);
         assertEquals(1, mockListener.getPropertyChangeCount());
     }

     public void testChangingPathFiresPropertyChangeEvent() {
-        final PPath path = new PPath();
-        path.addPropertyChangeListener(PPath.PROPERTY_PATH, mockListener);
+        final PPath path = new PPath.Double();
+        path.addPropertyChangeListener("path", mockListener); // "shape"
         path.append(new Rectangle2D.Double(0, 0, 100, 50), true);
         assertEquals(1, mockListener.getPropertyChangeCount());
     }

--
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en

Reply via email to