A simple interpolating cubic spline path that assumes that all the
points on either the x or y axis are equal and will interpolate the z values. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@38 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -0,0 +1,188 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.jme.sprite;
|
||||||
|
|
||||||
|
import com.jme.math.Vector3f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a sprite along an interpolated spline based on a series of control
|
||||||
|
* points.
|
||||||
|
*/
|
||||||
|
public class CubicSplinePath extends Path
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a path for the supplied sprite traversing the supplied
|
||||||
|
* series of points with the specified duration between points. The
|
||||||
|
* path assumes that all the control points exist on either the same
|
||||||
|
* x or y axis. The non-fixed x/y axis must be in order (either ascending
|
||||||
|
* or descending), and the z values will be interpolated.
|
||||||
|
*
|
||||||
|
* @param points a list of points to interpolate between. Currently
|
||||||
|
* all the points along one dimension must be equal.
|
||||||
|
* @param durations defines the elapsed time between each successive
|
||||||
|
* traversal. This will as a result be shorter by one element than the
|
||||||
|
* points array.
|
||||||
|
*/
|
||||||
|
public CubicSplinePath (
|
||||||
|
Sprite sprite, Vector3f[] points, float[] durations)
|
||||||
|
{
|
||||||
|
super(sprite);
|
||||||
|
_isX = (points[0].x != points[1].x);
|
||||||
|
_x = new float[points.length];
|
||||||
|
_y = new float[points.length];
|
||||||
|
_z = (_isX ? points[0].y : points[0].x);
|
||||||
|
for (int ii = 0; ii < points.length; ii++) {
|
||||||
|
_x[ii] = (_isX ? points[ii].x : points[ii].y);
|
||||||
|
_y[ii] = points[ii].z;
|
||||||
|
}
|
||||||
|
_end = points[points.length - 1];
|
||||||
|
_durations = durations;
|
||||||
|
calculateDerivatives();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public void update (float time)
|
||||||
|
{
|
||||||
|
// note the accumulated time
|
||||||
|
_accum += time;
|
||||||
|
|
||||||
|
// if we have surpassed the time for this segment, subtract the
|
||||||
|
// segment time and move on to the next segment
|
||||||
|
while (_current < _durations.length && _accum > _durations[_current]) {
|
||||||
|
_accum -= _durations[_current];
|
||||||
|
_current++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have completed out path, move the sprite to the final
|
||||||
|
// position and wrap everything up
|
||||||
|
if (_current >= _durations.length) {
|
||||||
|
_sprite.setLocalTranslation(_end);
|
||||||
|
_sprite.pathCompleted();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move the sprite to the appropriate position between points
|
||||||
|
_sprite.getLocalTranslation().set(interpolate(0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the second derivative values for all the control points
|
||||||
|
* along the path.
|
||||||
|
*/
|
||||||
|
protected void calculateDerivatives ()
|
||||||
|
{
|
||||||
|
float[] u = new float[_x.length];
|
||||||
|
_y2 = new float[_x.length];
|
||||||
|
for (int ii = 1; ii < _x.length - 1; ii++) {
|
||||||
|
float sig = (_x[ii] - _x[ii-1])/(_x[ii+1] - _x[ii-1]);
|
||||||
|
float p = sig * _y2[ii-1] + 2;
|
||||||
|
_y2[ii] = (sig - 1f) / p;
|
||||||
|
u[ii] = (6f * ((_y[ii+1] - _y[ii]) / (_x[ii+1] - _x[ii]) -
|
||||||
|
(_y[ii] - _y[ii-1]) / (_x[ii] - _x[ii-1])) /
|
||||||
|
(_x[ii+1] - _x[ii-1]) - sig * u[ii-1]) / p;
|
||||||
|
}
|
||||||
|
for (int ii = _x.length - 2; ii >= 0; ii--) {
|
||||||
|
_y2[ii] = _y2[ii] * _y2[ii + 1] + u[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolates the z value based on the current time point on the path.
|
||||||
|
*
|
||||||
|
* @param delta is the difference from the current time point to
|
||||||
|
* interpolate the point.
|
||||||
|
*/
|
||||||
|
protected Vector3f interpolate (float delta)
|
||||||
|
{
|
||||||
|
int idx = _current;
|
||||||
|
// no change, just use the current value
|
||||||
|
if (delta == 0f) {
|
||||||
|
delta = _accum;
|
||||||
|
|
||||||
|
// find the control point after the current one for interpolating
|
||||||
|
} else if (delta + _accum > _durations[idx]) {
|
||||||
|
delta -= _durations[idx] - _accum;
|
||||||
|
while (idx < _durations.length - 1) {
|
||||||
|
idx++;
|
||||||
|
if (delta < _durations[idx]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delta -= _durations[idx];
|
||||||
|
}
|
||||||
|
if (delta > _durations[idx] || idx == _durations.length - 1) {
|
||||||
|
return _end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the control point before the current one for interpolating
|
||||||
|
} else if (_accum + delta < 0) {
|
||||||
|
delta += _accum;
|
||||||
|
while (idx > 0) {
|
||||||
|
idx--;
|
||||||
|
delta += _durations[idx];
|
||||||
|
if (delta > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta < 0) {
|
||||||
|
delta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're using the same control point, simply adjust the time point
|
||||||
|
} else {
|
||||||
|
delta += _accum;
|
||||||
|
}
|
||||||
|
|
||||||
|
float h = _x[idx + 1] - _x[idx];
|
||||||
|
// no different between these points, just return the current value
|
||||||
|
if (h == 0) {
|
||||||
|
if (_sprite != null) {
|
||||||
|
return new Vector3f(_sprite.getLocalTranslation());
|
||||||
|
}
|
||||||
|
return new Vector3f();
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = _x[idx] + h * (delta / _durations[idx]);
|
||||||
|
float a = (_x[idx + 1] - x) / h;
|
||||||
|
float b = (x - _x[idx]) / h;
|
||||||
|
float a3 = a * a * a, b3 = b * b * b;
|
||||||
|
float y = a * _y[idx] + b * _y[idx + 1] +
|
||||||
|
((a3 - a) * _y2[idx] + (b3 - b) * _y2[idx + 1]) *
|
||||||
|
(h * h) / 6;
|
||||||
|
float z = y;
|
||||||
|
if (_isX) {
|
||||||
|
y = _z;
|
||||||
|
} else {
|
||||||
|
y = x;
|
||||||
|
x = _z;
|
||||||
|
}
|
||||||
|
return new Vector3f(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The final path point */
|
||||||
|
protected Vector3f _end;
|
||||||
|
/** The array of control points, derivatives and durations. */
|
||||||
|
protected float[] _x, _y, _y2, _durations;
|
||||||
|
|
||||||
|
protected float _accum, _z;
|
||||||
|
protected int _current;
|
||||||
|
protected boolean _isX;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user