Revision: 963
Author: allain.lalonde
Date: Mon Feb 1 11:30:02 2010
Log: Fixing error with rounding error bug when calculating inverseTransform
repeatedly during globalToLocal.
Fixes Issue 159
http://code.google.com/p/piccolo2d/source/detail?r=963
Modified:
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PNode.java
=======================================
--- /piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PNode.java
Mon Jan 18 16:07:38 2010
+++ /piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PNode.java
Mon Feb 1 11:30:02 2010
@@ -95,3663 +95,3902 @@
* @author Jesse Grosjean
*/
public class PNode implements Cloneable, Serializable, Printable {
- /**
- * The minimum difference in transparency required before the
transparency
- * is allowed to change. Done for efficiency reasons. I doubt very
much that
- * the human eye could tell the difference between 0.01 and 0.02
- * transparency.
- */
- private static final float TRANSPARENCY_RESOLUTION = 0.01f;
-
- /**
- * Allows for future serialization code to understand versioned binary
- * formats.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The property name that identifies a change in this node's client
- * propertie (see {...@link #getClientProperty getClientProperty}). In an
- * property change event the new value will be a reference to the map
of
- * client properties but old value will always be null.
- */
- public static final String PROPERTY_CLIENT_PROPERTIES
= "clientProperties";
-
- /**
- * The property code that identifies a change in this node's client
- * propertie (see {...@link #getClientProperty getClientProperty}). In an
- * property change event the new value will be a reference to the map
of
- * client properties but old value will always be null.
- */
- public static final int PROPERTY_CODE_CLIENT_PROPERTIES = 1 << 0;
-
- /**
- * The property name that identifies a change of this node's bounds
(see
- * {...@link #getBounds getBounds}, {...@link #getBoundsReference
- * getBoundsReference}). In any property change event the new value
will be
- * a reference to this node's bounds, but old value will always be
null.
- */
- public static final String PROPERTY_BOUNDS = "bounds";
-
- /**
- * The property code that identifies a change of this node's bounds
(see
- * {...@link #getBounds getBounds}, {...@link #getBoundsReference
- * getBoundsReference}). In any property change event the new value
will be
- * a reference to this node's bounds, but old value will always be
null.
- */
- public static final int PROPERTY_CODE_BOUNDS = 1 << 1;
-
- /**
- * The property name that identifies a change of this node's full
bounds
- * (see {...@link #getFullBounds getFullBounds},
- * {...@link #getFullBoundsReference getFullBoundsReference}). In any
property
- * change event the new value will be a reference to this node's full
bounds
- * cache, but old value will always be null.
- */
- public static final String PROPERTY_FULL_BOUNDS = "fullBounds";
-
- /**
- * The property code that identifies a change of this node's full
bounds
- * (see {...@link #getFullBounds getFullBounds},
- * {...@link #getFullBoundsReference getFullBoundsReference}). In any
property
- * change event the new value will be a reference to this node's full
bounds
- * cache, but old value will always be null.
- */
- public static final int PROPERTY_CODE_FULL_BOUNDS = 1 << 2;
-
- /**
- * The property name that identifies a change of this node's transform
(see
- * {...@link #getTransform getTransform}, {...@link #getTransformReference
- * getTransformReference}). In any property change event the new value
will
- * be a reference to this node's transform, but old value will always
be
- * null.
- */
- public static final String PROPERTY_TRANSFORM = "transform";
-
- /**
- * The property code that identifies a change of this node's transform
(see
- * {...@link #getTransform getTransform}, {...@link #getTransformReference
- * getTransformReference}). In any property change event the new value
will
- * be a reference to this node's transform, but old value will always
be
- * null.
- */
- public static final int PROPERTY_CODE_TRANSFORM = 1 << 3;
-
- /**
- * The property name that identifies a change of this node's
visibility (see
- * {...@link #getVisible getVisible}). Both old value and new value will
be
- * null in any property change event.
- */
- public static final String PROPERTY_VISIBLE = "visible";
-
- /**
- * The property code that identifies a change of this node's
visibility (see
- * {...@link #getVisible getVisible}). Both old value and new value will
be
- * null in any property change event.
- */
- public static final int PROPERTY_CODE_VISIBLE = 1 << 4;
-
- /**
- * The property name that identifies a change of this node's paint (see
- * {...@link #getPaint getPaint}). Both old value and new value will be
set
- * correctly in any property change event.
- */
- public static final String PROPERTY_PAINT = "paint";
-
- /**
- * The property code that identifies a change of this node's paint (see
- * {...@link #getPaint getPaint}). Both old value and new value will be
set
- * correctly in any property change event.
- */
- public static final int PROPERTY_CODE_PAINT = 1 << 5;
-
- /**
- * The property name that identifies a change of this node's
transparency
- * (see {...@link #getTransparency getTransparency}). Both old value and
new
- * value will be null in any property change event.
- */
- public static final String PROPERTY_TRANSPARENCY = "transparency";
-
- /**
- * The property code that identifies a change of this node's
transparency
- * (see {...@link #getTransparency getTransparency}). Both old value and
new
- * value will be null in any property change event.
- */
- public static final int PROPERTY_CODE_TRANSPARENCY = 1 << 6;
-
- /**
- * The property name that identifies a change of this node's pickable
status
- * (see {...@link #getPickable getPickable}). Both old value and new
value will
- * be null in any property change event.
- */
- public static final String PROPERTY_PICKABLE = "pickable";
- /**
- * The property code that identifies a change of this node's pickable
status
- * (see {...@link #getPickable getPickable}). Both old value and new
value will
- * be null in any property change event.
- */
- public static final int PROPERTY_CODE_PICKABLE = 1 << 7;
-
- /**
- * The property name that identifies a change of this node's children
- * pickable status (see {...@link #getChildrenPickable
getChildrenPickable}).
- * Both old value and new value will be null in any property change
event.
- */
- public static final String PROPERTY_CHILDREN_PICKABLE
= "childrenPickable";
-
- /**
- * The property code that identifies a change of this node's children
- * pickable status (see {...@link #getChildrenPickable
getChildrenPickable}).
- * Both old value and new value will be null in any property change
event.
- */
- public static final int PROPERTY_CODE_CHILDREN_PICKABLE = 1 << 8;
-
- /**
- * The property name that identifies a change in the set of this node's
- * direct children (see {...@link #getChildrenReference
getChildrenReference},
- * {...@link #getChildrenIterator getChildrenIterator}). In any property
change
- * event the new value will be a reference to this node's children,
but old
- * value will always be null.
- */
- public static final String PROPERTY_CHILDREN = "children";
-
- /**
- * The property code that identifies a change in the set of this node's
- * direct children (see {...@link #getChildrenReference
getChildrenReference},
- * {...@link #getChildrenIterator getChildrenIterator}). In any property
change
- * event the new value will be a reference to this node's children,
but old
- * value will always be null.
- */
- public static final int PROPERTY_CODE_CHILDREN = 1 << 9;
-
- /**
- * The property name that identifies a change of this node's parent
(see
- * {...@link #getParent getParent}). Both old value and new value will be
set
- * correctly in any property change event.
- */
- public static final String PROPERTY_PARENT = "parent";
-
- /**
- * The property code that identifies a change of this node's parent
(see
- * {...@link #getParent getParent}). Both old value and new value will be
set
- * correctly in any property change event.
- */
- public static final int PROPERTY_CODE_PARENT = 1 << 10;
-
- /** Is an optimization for use during repaints. */
- private static final PBounds TEMP_REPAINT_BOUNDS = new PBounds();
-
- /** The single scene graph delegate that receives low level node
events. */
- public static PSceneGraphDelegate SCENE_GRAPH_DELEGATE = null;
-
- /** Tracks the parent of this node, may be null. */
- private transient PNode parent;
-
- /** Tracks all immediate child nodes. */
- private List children;
-
- /** Bounds of the PNode. */
- private final PBounds bounds;
-
- /** Transform that applies to this node in relation to its parent. */
- private PAffineTransform transform;
-
- /** The paint to use for the background of this node. */
- private Paint paint;
-
- /**
- * How Opaque this node should be 1f = fully opaque, 0f = completely
- * transparent.
- */
- private float transparency;
-
- /** A modifiable set of client properties. */
- private MutableAttributeSet clientProperties;
-
- /**
- * An optimization that remembers the full bounds of a node rather than
- * computing it every time.
- */
- private PBounds fullBoundsCache;
-
- /**
- * Mask used when deciding whether to bubble up property change events
to
- * parents.
- */
- private int propertyChangeParentMask = 0;
-
- /** Used to handle property change listeners. */
- private transient SwingPropertyChangeSupport changeSupport;
-
- /** List of event listeners. */
- private transient EventListenerList listenerList;
-
- /** Whether this node is pickable or not. */
- private boolean pickable;
-
- /**
- * Whether to stop processing pick at this node and not bother
drilling down
- * into children.
- */
- private boolean childrenPickable;
-
- /** Whether this node will be rendered. */
- private boolean visible;
-
- private boolean childBoundsVolatile;
-
- /** Whether this node needs to be repainted. */
- private boolean paintInvalid;
-
- /** Whether children need to be repainted. */
- private boolean childPaintInvalid;
-
- /** Whether this node's bounds have changed, and so needs to be relaid
out. */
- private boolean boundsChanged;
-
- /** Whether this node's full bounds need to be recomputed. */
- private boolean fullBoundsInvalid;
-
- /** Whether this node's child bounds need to be recomputed. */
- private boolean childBoundsInvalid;
-
- private boolean occluded;
-
- /** Stores the name associated to this node. */
- private String name;
-
- /**
- * toImage fill strategy that stretches the node be as large as
possible
- * while still retaining its aspect ratio.
- *
- * @since 1.3
- */
- public static final int FILL_STRATEGY_ASPECT_FIT = 1;
-
- /**
- * toImage fill strategy that stretches the node be large enough to
cover
- * the image, and centers it.
- *
- * @since 1.3
- */
- public static final int FILL_STRATEGY_ASPECT_COVER = 2;
-
- /**
- * toImage fill strategy that stretches the node to be exactly the
- * dimensions of the image. Will result in distortion if the aspect
ratios
- * are different.
- *
- * @since 1.3
- */
- public static final int FILL_STRATEGY_EXACT_FIT = 4;
-
- /**
- * Creates a new PNode with the given name.
- *
- * @since 1.3
- * @param newName name to assign to node
- */
- public PNode(final String newName) {
- this();
- setName(newName);
- }
-
- /**
- * Constructs a new PNode.
- * <P>
- * By default a node's paint is null, and bounds are empty. These
values
- * must be set for the node to show up on the screen once it's added
to a
- * scene graph.
- */
- public PNode() {
- bounds = new PBounds();
- fullBoundsCache = new PBounds();
- transparency = 1.0f;
- pickable = true;
- childrenPickable = true;
- visible = true;
- }
-
- // ****************************************************************
- // Animation - Methods to animate this node.
- //
- // Note that animation is implemented by activities (PActivity),
- // so if you need more control over your animation look at the
- // activities package. Each animate method creates an animation that
- // will animate the node from its current state to the new state
- // specified over the given duration. These methods will try to
- // automatically schedule the new activity, but if the node does not
- // descend from the root node when the method is called then the
- // activity will not be scheduled and you must schedule it manually.
- // ****************************************************************
-
- /**
- * Animate this node's bounds from their current location when the
activity
- * starts to the specified bounds. If this node descends from the root
then
- * the activity will be scheduled, else the returned activity should be
- * scheduled manually. If two different transform activities are
scheduled
- * for the same node at the same time, they will both be applied to the
- * node, but the last one scheduled will be applied last on each
frame, so
- * it will appear to have replaced the original. Generally you will
not want
- * to do that. Note this method animates the node's bounds, but does
not
- * change the node's transform. Use animateTransformToBounds() to
animate
- * the node's transform instead.
- *
- * @param x left of target bounds
- * @param y top of target bounds
- * @param width width of target bounds
- * @param height height of target bounds
- * @param duration amount of time that the animation should take
- * @return the newly scheduled activity
- */
- public PInterpolatingActivity animateToBounds(final double x, final
double y, final double width,
- final double height, final long duration) {
- if (duration == 0) {
- setBounds(x, y, width, height);
- return null;
- }
-
- final PBounds dst = new PBounds(x, y, width, height);
-
- final PInterpolatingActivity interpolatingActivity = new
PInterpolatingActivity(duration,
- PUtil.DEFAULT_ACTIVITY_STEP_RATE) {
- private PBounds src;
-
- protected void activityStarted() {
- src = getBounds();
- startResizeBounds();
- super.activityStarted();
- }
-
- public void setRelativeTargetValue(final float zeroToOne) {
- PNode.this.setBounds(src.x + zeroToOne * (dst.x - src.x),
src.y + zeroToOne * (dst.y - src.y),
- src.width + zeroToOne * (dst.width - src.width),
src.height + zeroToOne
- * (dst.height - src.height));
- }
-
- protected void activityFinished() {
- super.activityFinished();
- endResizeBounds();
- }
- };
-
- addActivity(interpolatingActivity);
- return interpolatingActivity;
- }
-
- /**
- * Animate this node from it's current transform when the activity
starts a
- * new transform that will fit the node into the given bounds. If this
node
- * descends from the root then the activity will be scheduled, else the
- * returned activity should be scheduled manually. If two different
- * transform activities are scheduled for the same node at the same
time,
- * they will both be applied to the node, but the last one scheduled
will be
- * applied last on each frame, so it will appear to have replaced the
- * original. Generally you will not want to do that. Note this method
- * animates the node's transform, but does not directly change the
node's
- * bounds rectangle. Use animateToBounds() to animate the node's bounds
- * rectangle instead.
- *
- * @param x left of target bounds
- * @param y top of target bounds
- * @param width width of target bounds
- * @param height height of target bounds
- * @param duration amount of time that the animation should take
- * @return the newly scheduled activity
- */
- public PTransformActivity animateTransformToBounds(final double x,
final double y, final double width,
- final double height, final long duration) {
- final PAffineTransform t = new PAffineTransform();
- t.setToScale(width / getWidth(), height / getHeight());
- final double scale = t.getScale();
- t.setOffset(x - getX() * scale, y - getY() * scale);
- return animateToTransform(t, duration);
- }
-
- /**
- * Animate this node's transform from its current location when the
activity
- * starts to the specified location, scale, and rotation. If this node
- * descends from the root then the activity will be scheduled, else the
- * returned activity should be scheduled manually. If two different
- * transform activities are scheduled for the same node at the same
time,
- * they will both be applied to the node, but the last one scheduled
will be
- * applied last on each frame, so it will appear to have replaced the
- * original. Generally you will not want to do that.
- *
- * @param x the final target x position of node
- * @param y the final target y position of node
- * @param duration amount of time that the animation should take
- * @param scale the final scale for the duration
- * @param theta final theta value (in radians) for the animation
- * @return the newly scheduled activity
- */
- public PTransformActivity animateToPositionScaleRotation(final double
x, final double y, final double scale,
- final double theta, final long duration) {
- final PAffineTransform t = getTransform();
- t.setOffset(x, y);
- t.setScale(scale);
- t.setRotation(theta);
- return animateToTransform(t, duration);
- }
-
- /**
- * Animate this node's transform from its current values when the
activity
- * starts to the new values specified in the given transform. If this
node
- * descends from the root then the activity will be scheduled, else the
- * returned activity should be scheduled manually. If two different
- * transform activities are scheduled for the same node at the same
time,
- * they will both be applied to the node, but the last one scheduled
will be
- * applied last on each frame, so it will appear to have replaced the
- * original. Generally you will not want to do that.
- *
- * @param destTransform the final transform value
- * @param duration amount of time that the animation should take
- * @return the newly scheduled activity
- */
- public PTransformActivity animateToTransform(final AffineTransform
destTransform, final long duration) {
- if (duration == 0) {
- setTransform(destTransform);
- return null;
- }
- else {
- final PTransformActivity.Target t = new
PTransformActivity.Target() {
- public void setTransform(final AffineTransform aTransform)
{
- PNode.this.setTransform(aTransform);
- }
-
- public void getSourceMatrix(final double[] aSource) {
-
PNode.this.getTransformReference(true).getMatrix(aSource);
- }
- };
-
- final PTransformActivity ta = new PTransformActivity(duration,
PUtil.DEFAULT_ACTIVITY_STEP_RATE, t,
- destTransform);
- addActivity(ta);
- return ta;
- }
- }
-
- /**
- * Animate this node's color from its current value to the new value
- * specified. This meathod assumes that this nodes paint property is
of type
- * color. If this node descends from the root then the activity will be
- * scheduled, else the returned activity should be scheduled manually.
If
- * two different color activities are scheduled for the same node at
the
- * same time, they will both be applied to the node, but the last one
- * scheduled will be applied last on each frame, so it will appear to
have
- * replaced the original. Generally you will not want to do that.
- *
- * @param destColor final color value.
- * @param duration amount of time that the animation should take
- * @return the newly scheduled activity
- */
- public PInterpolatingActivity animateToColor(final Color destColor,
final long duration) {
- if (duration == 0) {
- setPaint(destColor);
- return null;
- }
- else {
- final PColorActivity.Target t = new PColorActivity.Target() {
- public Color getColor() {
- return (Color) getPaint();
- }
-
- public void setColor(final Color color) {
- setPaint(color);
- }
- };
-
- final PColorActivity ca = new PColorActivity(duration,
PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destColor);
- addActivity(ca);
- return ca;
- }
- }
-
- /**
- * Animate this node's transparency from its current value to the new
value
- * specified. Transparency values must range from zero to one. If this
node
- * descends from the root then the activity will be scheduled, else the
- * returned activity should be scheduled manually. If two different
- * transparency activities are scheduled for the same node at the same
time,
- * they will both be applied to the node, but the last one scheduled
will be
- * applied last on each frame, so it will appear to have replaced the
- * original. Generally you will not want to do that.
- *
- * @param zeroToOne final transparency value.
- * @param duration amount of time that the animation should take
- * @return the newly scheduled activity
- */
- public PInterpolatingActivity animateToTransparency(final float
zeroToOne, final long duration) {
- if (duration == 0) {
- setTransparency(zeroToOne);
- return null;
- }
- else {
- final float dest = zeroToOne;
-
- final PInterpolatingActivity ta = new
PInterpolatingActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE) {
- private float source;
-
- protected void activityStarted() {
- source = getTransparency();
- super.activityStarted();
- }
-
- public void setRelativeTargetValue(final float zeroToOne) {
- PNode.this.setTransparency(source + zeroToOne * (dest
- source));
- }
- };
-
- addActivity(ta);
- return ta;
- }
- }
-
- /**
- * Schedule the given activity with the root, note that only scheduled
- * activities will be stepped. If the activity is successfully added
true is
- * returned, else false.
- *
- * @param activity new activity to schedule
- * @return true if the activity is successfully scheduled.
- */
- public boolean addActivity(final PActivity activity) {
- final PRoot r = getRoot();
- if (r != null) {
- return r.addActivity(activity);
- }
- return false;
- }
-
- // ****************************************************************
- // Client Properties - Methods for managing client properties for
- // this node.
- //
- // Client properties provide a way for programmers to attach
- // extra information to a node without having to subclass it and
- // add new instance variables.
- // ****************************************************************
-
- /**
- * Return mutable attributed set of client properties associated with
this
- * node.
- *
- * @return the client properties associated to this node
- */
- public MutableAttributeSet getClientProperties() {
- if (clientProperties == null) {
- clientProperties = new SimpleAttributeSet();
- }
- return clientProperties;
- }
-
- /**
- * Returns the value of the client attribute with the specified key.
Only
- * attributes added with <code>addAttribute</code> will return a
non-null
- * value.
- *
- * @param key key to use while fetching client attribute
- *
- * @return the value of this attribute or null
- */
- public Object getAttribute(final Object key) {
- if (clientProperties == null || key == null) {
- return null;
- }
- else {
- return clientProperties.getAttribute(key);
- }
- }
-
- /**
- * Add an arbitrary key/value to this node.
- * <p>
- * The <code>get/add attribute</code> methods provide access to a small
- * per-instance attribute set. Callers can use get/add attribute to
annotate
- * nodes that were created by another module.
- * <p>
- * If value is null this method will remove the attribute.
- *
- * @param key to use when adding the attribute
- * @param value value to associate to the new attribute
- */
- public void addAttribute(final Object key, final Object value) {
- if (value == null && clientProperties == null) {
- return;
- }
-
- final Object oldValue = getAttribute(key);
-
- if (value != oldValue) {
- if (clientProperties == null) {
- clientProperties = new SimpleAttributeSet();
- }
-
- if (value == null) {
- clientProperties.removeAttribute(key);
- }
- else {
- clientProperties.addAttribute(key, value);
- }
-
- if (clientProperties.getAttributeCount() == 0 &&
clientProperties.getResolveParent() == null) {
- clientProperties = null;
- }
-
- firePropertyChange(PROPERTY_CODE_CLIENT_PROPERTIES,
PROPERTY_CLIENT_PROPERTIES, null, clientProperties);
- firePropertyChange(PROPERTY_CODE_CLIENT_PROPERTIES,
key.toString(), oldValue, value);
- }
- }
-
- /**
- * Returns an enumeration of all keys maped to attribute values values.
- *
- * @return an Enumeration over attribute keys
- */
- public Enumeration getClientPropertyKeysEnumeration() {
- if (clientProperties == null) {
- return PUtil.NULL_ENUMERATION;
- }
- else {
- return clientProperties.getAttributeNames();
- }
- }
-
- // convenience methods for attributes
-
- /**
- * Fetches the value of the requested attribute, returning
defaultValue is
- * not found.
- *
- * @param key attribute to search for
- * @param defaultValue value to return if attribute is not found
- *
- * @return value of attribute or defaultValue if not found
- */
- public Object getAttribute(final Object key, final Object
defaultValue) {
- final Object value = getAttribute(key);
- if (value == null) {
- return defaultValue;
- }
-
- return value;
- }
-
- /**
- * Fetches the boolean value of the requested attribute, returning
- * defaultValue is not found.
- *
- * @param key attribute to search for
- * @param defaultValue value to return if attribute is not found
- *
- * @return value of attribute or defaultValue if not found
- */
- public boolean getBooleanAttribute(final Object key, final boolean
defaultValue) {
- final Boolean value = (Boolean) getAttribute(key);
- if (value == null) {
- return defaultValue;
- }
-
- return value.booleanValue();
- }
-
- /**
- * Fetches the integer value of the requested attribute, returning
- * defaultValue is not found.
- *
- * @param key attribute to search for
- * @param defaultValue value to return if attribute is not found
- *
- * @return value of attribute or defaultValue if not found
- */
- public int getIntegerAttribute(final Object key, final int
defaultValue) {
- final Number value = (Number) getAttribute(key);
- if (value == null) {
- return defaultValue;
- }
-
- return value.intValue();
- }
-
- /**
- * Fetches the double value of the requested attribute, returning
- * defaultValue is not found.
- *
- * @param key attribute to search for
- * @param defaultValue value to return if attribute is not found
- *
- * @return value of attribute or defaultValue if not found
- */
- public double getDoubleAttribute(final Object key, final double
defaultValue) {
- final Number value = (Number) getAttribute(key);
- if (value == null) {
- return defaultValue;
- }
-
- return value.doubleValue();
- }
-
- /**
- * @deprecated use getAttribute(Object key)instead.
- *
- * @param key name of property to search for
- * @return value of matching client property
- */
- public Object getClientProperty(final Object key) {
- return getAttribute(key);
- }
-
- /**
- * @deprecated use addAttribute(Object key, Object value)instead.
- *
- * @param key name of property to add
- * @param value value or new attribute
- */
- public void addClientProperty(final Object key, final Object value) {
- addAttribute(key, value);
- }
-
- /**
- * @deprecated use getClientPropertyKeysEnumerator() instead.
- *
- * @return iterator for client property keys
- */
- public Iterator getClientPropertyKeysIterator() {
- final Enumeration enumeration = getClientPropertyKeysEnumeration();
-
- return new ClientPropertyKeyIterator(enumeration);
- }
-
- // ****************************************************************
- // Copying - Methods for copying this node and its descendants.
- // Copying is implemented in terms of serialization.
- // ****************************************************************
-
- /**
- * The copy method copies this node and all of its descendants. Note
that
- * copying is implemented in terms of java serialization. See the
- * serialization notes for more information.
- *
- * @return new copy of this node or null if the node was not
serializable
- */
- public Object clone() {
- try {
- final byte[] ser = PObjectOutputStream.toByteArray(this);
- return new ObjectInputStream(new
ByteArrayInputStream(ser)).readObject();
- }
- catch (final IOException e) {
- return null;
- }
- catch (final ClassNotFoundException e) {
- return null;
- }
- }
-
- // ****************************************************************
- // Coordinate System Conversions - Methods for converting
- // geometry between this nodes local coordinates and the other
- // major coordinate systems.
- //
- // Each nodes has an affine transform that it uses to define its
- // own coordinate system. For example if you create a new node and
- // add it to the canvas it will appear in the upper right corner. Its
- // coordinate system matches the coordinate system of its parent
- // (the root node) at this point. But if you move this node by calling
- // node.translate() the nodes affine transform will be modified and the
- // node will appear at a different location on the screen. The node
- // coordinate system no longer matches the coordinate system of its
- // parent.
- //
- // This is useful because it means that the node's methods for
- // rendering and picking don't need to worry about the fact that
- // the node has been moved to another position on the screen, they
- // keep working just like they did when it was in the upper right
- // hand corner of the screen.
- //
- // The problem is now that each node defines its own coordinate
- // system it is difficult to compare the positions of two node with
- // each other. These methods are all meant to help solve that problem.
- //
- // The terms used in the methods are as follows:
- //
- // local - The local or base coordinate system of a node.
- // parent - The coordinate system of a node's parent
- // global - The topmost coordinate system, above the root node.
- //
- // Normally when comparing the positions of two nodes you will
- // convert the local position of each node to the global coordinate
- // system, and then compare the positions in that common coordinate
- // system.
- // ***************************************************************
-
- /**
- * Transform the given point from this node's local coordinate system
to its
- * parent's local coordinate system. Note that this will modify the
point
- * parameter.
- *
- * @param localPoint point in local coordinate system to be
transformed.
- * @return point in parent's local coordinate system
- */
- public Point2D localToParent(final Point2D localPoint) {
- if (transform == null) {
- return localPoint;
- }
- return transform.transform(localPoint, localPoint);
- }
-
- /**
- * Transform the given dimension from this node's local coordinate
system to
- * its parent's local coordinate system. Note that this will modify the
- * dimension parameter.
- *
- * @param localDimension dimension in local coordinate system to be
- * transformed.
- * @return dimension in parent's local coordinate system
- */
- public Dimension2D localToParent(final Dimension2D localDimension) {
- if (transform == null) {
- return localDimension;
- }
- return transform.transform(localDimension, localDimension);
- }
-
- /**
- * Transform the given rectangle from this node's local coordinate
system to
- * its parent's local coordinate system. Note that this will modify the
- * rectangle parameter.
- *
- * @param localRectangle rectangle in local coordinate system to be
- * transformed.
- * @return rectangle in parent's local coordinate system
- */
- public Rectangle2D localToParent(final Rectangle2D localRectangle) {
- if (transform == null) {
- return localRectangle;
- }
- return transform.transform(localRectangle, localRectangle);
- }
-
- /**
- * Transform the given point from this node's parent's local coordinate
- * system to the local coordinate system of this node. Note that this
will
- * modify the point parameter.
- *
- * @param parentPoint point in parent's coordinate system to be
transformed.
- * @return point in this node's local coordinate system
- */
- public Point2D parentToLocal(final Point2D parentPoint) {
- if (transform == null) {
- return parentPoint;
- }
-
- return transform.inverseTransform(parentPoint, parentPoint);
- }
-
- /**
- * Transform the given dimension from this node's parent's local
coordinate
- * system to the local coordinate system of this node. Note that this
will
- * modify the dimension parameter.
- *
- * @param parentDimension dimension in parent's coordinate system to be
- * transformed.
- * @return dimension in this node's local coordinate system
- */
- public Dimension2D parentToLocal(final Dimension2D parentDimension) {
- if (transform == null) {
- return parentDimension;
- }
- return transform.inverseTransform(parentDimension,
parentDimension);
- }
-
- /**
- * Transform the given rectangle from this node's parent's local
coordinate
- * system to the local coordinate system of this node. Note that this
will
- * modify the rectangle parameter.
- *
- * @param parentRectangle rectangle in parent's coordinate system to be
- * transformed.
- * @return rectangle in this node's local coordinate system
- */
- public Rectangle2D parentToLocal(final Rectangle2D parentRectangle) {
- if (transform == null) {
- return parentRectangle;
- }
- return transform.inverseTransform(parentRectangle,
parentRectangle);
- }
-
- /**
- * Transform the given point from this node's local coordinate system
to the
- * global coordinate system. Note that this will modify the point
parameter.
- *
- * @param localPoint point in local coordinate system to be
transformed.
- * @return point in global coordinates
- */
- public Point2D localToGlobal(final Point2D localPoint) {
- PNode n = this;
- while (n != null) {
- n.localToParent(localPoint);
- n = n.parent;
- }
- return localPoint;
- }
-
- /**
- * Transform the given dimension from this node's local coordinate
system to
- * the global coordinate system. Note that this will modify the
dimension
- * parameter.
- *
- * @param localDimension dimension in local coordinate system to be
- * transformed.
- * @return dimension in global coordinates
- */
- public Dimension2D localToGlobal(final Dimension2D localDimension) {
- PNode n = this;
- while (n != null) {
- n.localToParent(localDimension);
- n = n.parent;
- }
- return localDimension;
- }
-
- /**
- * Transform the given rectangle from this node's local coordinate
system to
- * the global coordinate system. Note that this will modify the
rectangle
- * parameter.
- *
- * @param localRectangle rectangle in local coordinate system to be
- * transformed.
- * @return rectangle in global coordinates
- */
- public Rectangle2D localToGlobal(final Rectangle2D localRectangle) {
- PNode n = this;
- while (n != null) {
- n.localToParent(localRectangle);
- n = n.parent;
- }
- return localRectangle;
- }
-
- /**
- * Transform the given point from global coordinates to this node's
local
- * coordinate system. Note that this will modify the point parameter.
- *
- * @param globalPoint point in global coordinates to be transformed.
- * @return point in this node's local coordinate system.
- */
- public Point2D globalToLocal(final Point2D globalPoint) {
- if (parent != null) {
- parent.globalToLocal(globalPoint);
- }
- return parentToLocal(globalPoint);
- }
-
- /**
- * Transform the given dimension from global coordinates to this node's
- * local coordinate system. Note that this will modify the dimension
- * parameter.
- *
***The diff for this file has been truncated for email.***
--
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en