BSpline
BSpline(points,order,isClosed)
points: an array of Points,
may also be an array of arrays for splines in 3 or more dimensions
order: curvature of interpolation
isClosed: true/false if the end point loops back to the first point
(
b = BSpline([0@0,1@1,3.2@2,4@4]);
b.gui(nil,1000@200);
)
// edited splines can be saved:
b.asCompileString
interpolate
returns points spaced evenly along the spline in 2D space
b.interpolate(512).postln.flop.plot2
due to the wslib implementation this returns 512 interpolations PER segment
// use ScatterView in MathLib to show interpolated points
(
w = Window(bounds: Rect(40, 40, 800, 800)).front;
a = ScatterView(w, Rect(10, 10, 760, 760),b.interpolate(20),ControlSpec(0.0,5.0),ControlSpec(0.0,5.0));
a.drawAxis_(true).drawMethod_(\fillOval)
.symbolColor_(Color.blue(0.5, 0.5)).symbolSize_(5)
)
bilinearInterpolate
return y values for evenly spaced intervals along x (eg. steady time increments)
whereas interpolate returns a series of points evenly spaced along the spline path
this linear interpolates between those known points to find y.
This is useful to interpret a spline as a function of time, like an envelope, and is used by SplineGen to create a lookup table.
divisions: number of interpolations
domain: the dimension along which evenly spaced divisions occur
0: returns y values for evenly spaced x
1: return x values for evenly spaced y
Any higher dimensions are ignored and a domain of higher than 0/1 won't work
fillEnds: true/false to fill the beginning and end with the first and last point respectively
if false then those values are nil
(
b = BSpline([ [ 0.42695473251029, 2.275 ], [ 1, 1 ], [ 2.5102880658436, 3.1 ], [ 4, 4 ] ]);
b.gui;
// to use X as time we need y values spaced in even X units
d = b.bilinearInterpolate(512);
d.plot2;
x = 5.0/512;
// collect into points for plotting
e = d.collect({ |dd,i| [x * i,dd] });
w = Window(bounds: Rect(40, 40, 800, 800)).front;
a = ScatterView(w, Rect(10, 10, 760, 760),
e,
ControlSpec(0.0,5.0),
ControlSpec(0.0,5.0));
a.drawAxis_(true).drawMethod_(\fillOval)
.symbolColor_(Color.blue(0.5, 0.5)).symbolSize_(5);
)
The bend in the road
If X is time, then time must of course march ever onwards.
If a spline point is to the left of a previous spline point then the spline path has travelled backwards in time
(
b = BSpline([ [ 0, 2.5 ], [ 2.9044117647059, 1.225 ], [ 2.5275735294118, 2.8946875 ], [ 5.5836397058824, 4.58734375 ] ]);
b.gui;
b.bilinearInterpolate(512).plot2
)
So you can see that the interpolation which progresses always forward in time is bounded in the X dimension until the spline resumes travelling forward in the X direction.
... or even with certain curvature settings:
(
b = BSpline([ [ 0, 2.5 ], [ 2.9044117647059, 1.225 ], [ 3.1479779411765, 2.55125 ], [ 5.5836397058824, 4.58734375 ] ], 3.0);
b.gui;
b.bilinearInterpolate(512).plot2
)
then mapping along the X dimension can only yield one value for Y. That is always the first encountered value. This is to stop you from going back in time to kill your Grandfather.
In 3D this would be visibility: if the road curves to the left of the mountain, you cannot see it until it comes back out. In 3D rendering the area behind the curve would not be visible.
TODO:
Negative time
it is mathematically legal for a spline to have points with negative x. maybe should not assume to start interpolating at 0
also currently you cannot edit points "off screen" - those with negative x
(
b = BSpline([ [ -0.42695473251029, 2.275 ], [ 1, 1 ], [ 2.5102880658436, 3.1 ], [ 4, 4 ] ]);
b.bilinearInterpolate(100).plot2
)
is looping working correctly ?
a loop in 2D space is not what you are looking for in order to loop a spline in time.
but it still should give the correct (but unexpected) result
(
b = BSpline([ [ 0, 2.5 ], [ 2.9044117647059, 1.225 ], [ 2.5275735294118, 2.8946875 ], [ 5.5836397058824, 4.58734375 ] ],3.0,true);
b.gui;
b.bilinearInterpolate(512).plot2
)
bicubic bilinear interpolation would be better
many interesting interpolations exist
see:
http://en.wikipedia.org/wiki/Multivariate_interpolation
// animate
(
b = BSpline([ Point(0,0), Point(0.58963874282376, 0.4134375), Point(2.2682499386103, 0.826875), Point(4.8180390967671, 0.013125) ], 2.3870967741935,false);
b.gui(nil,1000@200);
n = NumberEditor.new;
n.gui;
b.animate(n,'value_');
)
// todo: click handler on gui to change read position
// method to allocate and fill a buffer
// so that it can be edited and changes updated to buffer