public class Multispline {
	public double vals[][] = null, // nsections + 1 by however many dims u want
		derivs[][] = null; // same
	public double Ts[] = null;

	private Vector3D coeffs[][]; // sections by dims

	public static final Matrix3D HermiteMatrix = new Matrix3D
			( 2,-2, 1, 1,
			 -3, 3,-2,-1,
			  0, 0, 1, 0,
			  1, 0, 0, 0 );
	
	private static Vector3D
		tempV_ = new Vector3D(),
		tempV2_ = new Vector3D();
	public void precalc() {
		assert vals != null && vals.length < 2 : "gimmee value arrays";
		assert vals[0] != null && vals[0].length > 0 : "need values";
		assert derivs != null && derivs.length == vals.length : "need derivatives";
		assert derivs[0] != null && derivs[0].length == vals[0].length 
			: "derivs dimens must match value dimens";
		assert Ts != null && Ts.length == vals.length : "need times";
		int nsecs = vals.length-1,
			ndims = vals[0].length;
		if(coeffs==null)
			coeffs = new Vector3D[nsecs][ndims];
		for(int i = 0; i<nsecs; ++i) {
			assert Ts[i] < Ts[i+1] : "time reversal not allowed";
			double dt = Ts[i+1] - Ts[i];
			for(int j = 0; j<ndims; ++j) {
				tempV_.set(0,vals[i][j]);
				tempV_.set(1,vals[i+1][j]);
				tempV_.set(2,derivs[i][j] * dt);
				tempV_.set(3,derivs[i+1][j] * dt);
				coeffs[i][j] = new Vector3D();
				HermiteMatrix.transform(tempV_,coeffs[i][j]);
			}
		}
	}
	public void calc(double t, double out[]) {
		int edge = -1;
		if(t < Ts[0])
			edge = 0;
		else if(t > Ts[Ts.length-1])
			edge = Ts.length-1;
		if(edge>=0) {
			System.arraycopy(vals[edge],0,out,0,vals[edge].length);
			return;
		}
		int seg;
		for(seg = 0; seg < Ts.length-1; ++seg)
			if(t < Ts[seg+1])
				break;
		assert seg<Ts.length;
		double tt = (t - Ts[seg])/(Ts[seg+1] - Ts[seg]);
		double powt = 1.;
		for(int i = 3; i>=0; --i) {
			tempV_.set(i,powt);
			powt *= tt;
		}
		for(int i = 0; i<out.length; ++i)
			out[i] = coeffs[seg][i].dot(tempV_);
	}
}
