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é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();
+ 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