interpolate
SCView extensions
part of wslib
a number of interpolation functions.
there are a number of types of interpolation available, and a number of ways to do it.
interpolation types
cubic interpolation:
'spline' : basic spline interpolation with automatic control points; extra argument: amt for the control points.
amt = 0 will result in sine-like interpolation.
the default amt is ( 0.75 / (1.9**0.5) ), for 2D circle approximation
'hermite' : simplified spline interpolation with fixed amt = 1/3, as used by many UGens ( DelayC, PlayBuf etc)
'bspline' : better curves but higher cpu. bspline also has an amt argument, which defines the order.
the default amt is 4.
other interpolation:
'quad' : not correct yet
'sine' : wraps s-shaped sine curves between steps
'linear' : linear interpolation
'step' : step interpolation
There is also the possibility of entering your own control points for the cubic interpolation.
methods
Array:intAt( index, type, loop, extra )
returns an interpolated value from the array at index with type interpolation. if loop == true the curve after the last point will bend towards the first. extra contains the extra arguments for specific types.
[0,1,5,2].intAt( 2.5 );
[0,1,5,2].intAt( 2.5, \hermite );
[0,1,5,2].intAt( 2.5, \bspline );
Array:atL ( index, loop ), atH ( index, loop ), atS ( index, loop, extra ),
atB ( index, loop, extra ), atSin ( index, loop )
shortcuts for all intAt types
Array:resize ( newSize, type, loop, extra )
resizes the array to newSize with type interpolation.
[0,1,5,2].resize( 100, \hermite ).plot;
(
a = { 1.0.rand2 } ! 10;
({ |i| a.resize( 200, [\linear, \step, \hermite, \spline, \bspline][i] ) } ! 5)
.flop.flat.plot(numChannels: 5);
)
Array:interpolate ( division, type, loop, extra )
expands the array to division values per input value with type interpolation.
[0,1,5,2].interpolate( 10, \hermite ).size;
[0,1,5,2].interpolate( 10, \hermite ).plot;
Array:splineIntFunction ( i, x1, x2 )
the basic cubic interpolation function with user given control points. The input aray should be of size = 2.
If you use an array for i, the function will run optimized ( calculates controls only once ).
[0,1].splineIntFunction( (0,0.01..1), 0.125, 1.75 ).plot;
examples
(
// hands on interpolation
// move the points around..
w = SCWindow( "y-axis interpolation" ).front;
u = SCUserView( w, w.view.bounds ).resize_(5);
w.decorate;
w.view.background_( Color.white );
m = SCPopUpMenu( w, 160@20 ).items_([
"cubic with controls",
"bspline",
"spline",
"hermite",
"linear",
"sine",
"step" ])
.action_({ |pu|
if( (pu.value == 2) or: (pu.value == 1) )
{ c.visible = true }
{ c.visible = false };
w.refresh; });
c = SCSlider( w, 200@20 )
.value_( (0.75 / (1.9**0.5)) )
.action_({ w.refresh })
.visible_( false );
p = [ 12@200, 138@50, 262@50, 388@200 ];
j = nil;
r = 7;
u.drawFunc_({ |uvw|
Color.black.alpha_(0.5).set;
Pen.line( 0@200, 400@200 ).stroke;
p[[0,3]].do({ |point, i| Pen.addArc( point, r, 0, 2pi ).stroke; });
if( m.value == 0 )
{ Color.red.set;
Pen.line( p[0], p[1] ).stroke;
Pen.line( p[2], p[3] ).stroke;
};
p[[1,2]].do({ |point, i| Pen.addArc( point, r, 0, 2pi ).stroke; });
Color.blue.set;
Pen.moveTo( p[0] );
switch( m.value,
0, { p[[0,3]].collect( _.y )
.splineIntFunction( (0,1/50..1), p[1].y, p[2].y )
.do({ |item, i|
Pen.lineTo(
i.linlin( 0, 50, p[0].x, p[3].x, \none )@item )
});
},
1, { p.collect(_.y).interpolate(15, 'bspline', false, c.value.linlin( 0,1,2,8 ).asInt )
.do({ |item, i| Pen.lineTo( i.linlin( 0, 59, p[0].x, p[3].x, \none )@item ) });
},
2, { p.collect(_.y).interpolate(15, 'spline', false, c.value )
.do({ |item, i| Pen.lineTo( i.linlin( 0, 59, p[0].x, p[3].x, \none )@item ) });
},
3, { p.collect(_.y).interpolate(15, 'hermite', false)
.do({ |item, i| Pen.lineTo( i.linlin( 0, 59, p[0].x, p[3].x, \none )@item ) });
},
4, { p.collect(_.y).interpolate(10, 'linear', false)
.do({ |item, i| Pen.lineTo( i.linlin( 0, 39, p[0].x, p[3].x, \none )@item ) });
},
5, { p.collect(_.y).interpolate(15, 'sine', false)
.do({ |item, i| Pen.lineTo( i.linlin( 0, 59, p[0].x, p[3].x, \none )@item ) });
},
6, { p.collect(_.y).interpolate(15, 'step', false)
.do({ |item, i| Pen.lineTo( i.linlin( 0, 59, p[0].x, p[3].x, \none )@item ) });
}
);
Pen.stroke;
});
u.mouseBeginTrackFunc_({ |uvw, x, y|
var distances;
distances = p.collect({ |pt| pt.dist( x@y ) });
j = distances.detectIndex( _ < (r+1) );
//j.postln;
});
u.mouseTrackFunc_({ |uvw, x,y| if( j.notNil ) { p[j] = (p[j].x)@(y.max(0)); w.refresh; }; });
)
///////////////////
(
// 2 dimensional interpolation
w = SCWindow( "2D interpolation" ).front;
u = SCUserView( w, w.view.bounds ).resize_(5);
w.decorate;
m = SCPopUpMenu( w, 160@20 ).items_([
"cubic with controls",
"bspline",
"spline",
"hermite",
"linear" ])
.action_({ |pu|
if( (pu.value == 2) or: (pu.value == 1) )
{ c.visible = true }
{ c.visible = false };
w.refresh; });
c = SCSlider( w, 200@20 )
.value_( (0.75 / (1.9**0.5)) )
.action_({ w.refresh })
.visible_( false );
p = [ 10@200, 100@50, 300@50, 390@200 ];
j = nil;
r = 7;
u.drawFunc_({ |uvw|
Color.black.alpha_(0.5).set;
p[[0,3]].do({ |point, i| Pen.addArc( point, r, 0, 2pi ).stroke; });
if( m.value == 0 )
{ Color.red.set;
Pen.line( p[0], p[1] ).stroke;
Pen.line( p[2], p[3] ).stroke;
};
p[[1,2]].do({ |point, i| Pen.addArc( point, r, 0, 2pi ).stroke; });
Color.blue.set;
Pen.moveTo( p[0] );
switch( m.value,
0, { p[[0,3]].collect( _.asArray )
.flop.collect({ |item,i|
item.splineIntFunction( (0,1/50..1), p[1].asArray[i], p[2].asArray[i] )
}).flop
.do({ |item| Pen.lineTo( item.asPoint ) });
},
/*
0, { 50.do({ |i| Pen.lineTo( p[[0,3]].collect( _.asArray )
.splineIntFunction( i/49, p[1].asArray, p[2].asArray ).asPoint )
}); },
*/
1, { p.collect(_.asArray).interpolate(15, 'bspline', false, c.value.linlin( 0,1,2,8) )
.do({ |item, i| Pen.lineTo( item.asPoint ) });
},
2, { p.collect(_.asArray).interpolate(15, 'spline', false, c.value )
.do({ |item, i| Pen.lineTo( item.asPoint ) });
},
3, { p.collect(_.asArray).interpolate(15, 'hermite', false, c.value )
.do({ |item, i| Pen.lineTo( item.asPoint ) });
},
4, { p.collect(_.asArray).interpolate(10, 'linear', false)
.do({ |item, i| Pen.lineTo( item.asPoint ) });
}
);
Pen.stroke;
});
u.mouseBeginTrackFunc_({ |uvw, x, y|
var distances;
distances = p.collect({ |pt| pt.dist( x@y ) });
j = distances.detectIndex( _ < (r+1) );
//j.postln;
});
u.mouseTrackFunc_({ |uvw, x,y| if( j.notNil ) { p[j] = x@y; w.refresh; }; });
)