edu.umd.cs.piccolox.activities.PPositionPathActivity Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
* Copyright (c) 1998-2008, University of Maryland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
* contributors may be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package edu.umd.cs.piccolox.activities;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import edu.umd.cs.piccolo.activities.PInterpolatingActivity;
/**
* PPositionPathActivity animates through a sequence of points.
*
* @version 1.0
* @author Jesse Grosjean
*/
public class PPositionPathActivity extends PPathActivity {
/** Points that define the animation's path. */
protected Point2D[] positions;
/** An abstract representation of the thing being positioned. */
protected Target target;
/**
* Interface that objects must conform to in order to have their position
* animated.
*/
public interface Target {
/**
* Set's the target's position to the coordinate provided.
*
* @param x the x component of the new position
* @param y the y component of the new position
*/
void setPosition(double x, double y);
}
/**
* Constructs a position activity that acts on the given target for the
* duration provided and will update it's position at the given stepRate.
*
* @param duration milliseconds of animation
* @param stepRate milliseconds between successive position updates
* @param target abstract representation of thing being animated
*/
public PPositionPathActivity(final long duration, final long stepRate, final Target target) {
this(duration, stepRate, target, null, new Point2D[0]);
}
/**
* Constructs a position activity that acts on the given target for the
* duration provided and will update it's position at the given stepRate. It
* will follow the path defined by the knots and positions arguments.
*
* @param duration milliseconds of animation
* @param stepRate milliseconds between successive position updates
* @param target abstract representation of thing being animated
* @param knots timing to use when animating
* @param positions points along the path
*/
public PPositionPathActivity(final long duration, final long stepRate, final Target target, final float[] knots,
final Point2D[] positions) {
this(duration, stepRate, 1, PInterpolatingActivity.SOURCE_TO_DESTINATION, target, knots, positions);
}
/**
* Constructs a position activity that will repeat the number of times
* specified. It will act on the given target for the duration provided and
* will update it's position at the given stepRate. It will follow the path
* defined by the knots and positions arguments.
*
* @param duration milliseconds of animation
* @param stepRate milliseconds between successive position updates
* @param loopCount number of times this activity should repeat
* @param mode how easing is handled on this activity
* @param target abstract representation of thing being animated
* @param knots timing to use when animating
* @param positions points along the path
*/
public PPositionPathActivity(final long duration, final long stepRate, final int loopCount, final int mode,
final Target target, final float[] knots, final Point2D[] positions) {
super(duration, stepRate, loopCount, mode, knots);
this.target = target;
this.positions = (Point2D[]) positions.clone();
}
/**
* Returns true since this activity modifies the view and so cause a
* repaint.
*
* @return always true
*/
protected boolean isAnimation() {
return true;
}
/**
* Returns a copy of the path's points.
*
* @return array of points on the path
*/
public Point2D[] getPositions() {
return (Point2D[]) positions.clone();
}
/**
* Returns the point at the given index.
*
* @param index desired position index
* @return point at the given index
*/
public Point2D getPosition(final int index) {
return positions[index];
}
/**
* Changes all positions that define where along the target is being
* positioned during the animation.
*
* @param positions new animation positions
*/
public void setPositions(final Point2D[] positions) {
this.positions = (Point2D[]) positions.clone();
}
/**
* Sets the position of the point at the given index.
*
* @param index index of the point to change
* @param position point defining the new position
*/
public void setPosition(final int index, final Point2D position) {
positions[index] = position;
}
/**
* Extracts positions from a GeneralPath and uses them to define this
* activity's animation points.
*
* @param path source of points
*/
public void setPositions(final GeneralPath path) {
final PathIterator pi = path.getPathIterator(null, 1);
final ArrayList points = new ArrayList();
final float[] point = new float[6];
float distanceSum = 0;
float lastMoveToX = 0;
float lastMoveToY = 0;
while (!pi.isDone()) {
final int type = pi.currentSegment(point);
switch (type) {
case PathIterator.SEG_MOVETO:
points.add(new Point2D.Float(point[0], point[1]));
lastMoveToX = point[0];
lastMoveToY = point[1];
break;
case PathIterator.SEG_LINETO:
points.add(new Point2D.Float(point[0], point[1]));
break;
case PathIterator.SEG_CLOSE:
points.add(new Point2D.Float(lastMoveToX, lastMoveToY));
break;
case PathIterator.SEG_QUADTO:
case PathIterator.SEG_CUBICTO:
throw new RuntimeException();
default:
// ok to do nothing it'll just be skipped
}
if (points.size() > 1) {
final Point2D last = (Point2D) points.get(points.size() - 2);
final Point2D current = (Point2D) points.get(points.size() - 1);
distanceSum += last.distance(current);
}
pi.next();
}
final int size = points.size();
final Point2D[] newPositions = new Point2D[size];
final float[] newKnots = new float[size];
for (int i = 0; i < size; i++) {
newPositions[i] = (Point2D) points.get(i);
if (i > 0) {
final float dist = (float) newPositions[i - 1].distance(newPositions[i]);
newKnots[i] = newKnots[i - 1] + dist / distanceSum;
}
}
setPositions(newPositions);
setKnots(newKnots);
}
/**
* Overridden to interpret position at correct point along animation.
*
* TODO: improve these comments
*
* @param zeroToOne how far along the activity we are
* @param startKnot the index of the startKnot
* @param endKnot the index of the endKnot
*/
public void setRelativeTargetValue(final float zeroToOne, final int startKnot, final int endKnot) {
final Point2D start = getPosition(startKnot);
final Point2D end = getPosition(endKnot);
target.setPosition(start.getX() + zeroToOne * (end.getX() - start.getX()), start.getY() + zeroToOne
* (end.getY() - start.getY()));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy