SplineCurve3 class
Spline 3D curve
class SplineCurve3 extends Curve3D {
List<Vector3> points;
SplineCurve3( [this.points] ) : super() {
if (points == null) points = [];
}
Vector3 getPoint( t ) {
var v = new Vector3.zero();
var c = new List<int>(4);
var point = ( points.length - 1 ) * t,
intPoint = point.floor().toInt(),
weight = point - intPoint;
c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
c[ 1 ] = intPoint;
c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1;
c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2;
var pt0 = points[ c[0] ],
pt1 = points[ c[1] ],
pt2 = points[ c[2] ],
pt3 = points[ c[3] ];
v.x = CurveUtils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight);
v.y = CurveUtils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight);
v.z = CurveUtils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight);
return v;
}
}
Extends
Curve<Vector3> > Curve3D > SplineCurve3
Properties
Methods
List getLengths({num divisions: null}) #
inherited from Curve
List getLengths( {num divisions: null} ) {
if (divisions == null) divisions = (_arcLengthDivisions != null) ? (_arcLengthDivisions): 200;
if ( cacheArcLengths != null
&& ( cacheArcLengths.length == divisions + 1 )
&& !needsUpdate) {
//console.log( "cached", this.cacheArcLengths );
return cacheArcLengths;
}
needsUpdate = false;
var cache = [];
var current;
var last = getPoint( 0.0 );
var sum = 0;
cache.add( 0 );
for ( var p = 1; p <= divisions; p ++ ) {
current = getPoint ( p / divisions );
var distance;
// TODO(nelsonsilva) - Must move distanceTo to IVector interface os create a new IHasDistance
if (current is Vector3) {
distance = (current as Vector3).absoluteError( last as Vector3 );
} else {
distance = (current as Vector2).absoluteError( last as Vector2);
}
sum += distance;
cache.add( sum );
last = current;
}
cacheArcLengths = cache;
return cache; // { sums: cache, sum:sum }; Sum is in the last element.
}
Vector3 getPoint(t) #
Vector3 getPoint( t ) {
var v = new Vector3.zero();
var c = new List<int>(4);
var point = ( points.length - 1 ) * t,
intPoint = point.floor().toInt(),
weight = point - intPoint;
c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
c[ 1 ] = intPoint;
c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1;
c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2;
var pt0 = points[ c[0] ],
pt1 = points[ c[1] ],
pt2 = points[ c[2] ],
pt3 = points[ c[3] ];
v.x = CurveUtils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight);
v.y = CurveUtils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight);
v.z = CurveUtils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight);
return v;
}
V getPointAt(u) #
inherited from Curve
V getPointAt( u ) {
var t = getUtoTmapping( u );
return getPoint( t );
}
List<V> getPoints([num divisions = null, closedPath = false]) #
inherited from Curve
List<V> getPoints( [num divisions = null, closedPath = false] ) {
if (divisions == null) divisions = 5;
var d, pts = [];
for ( d = 0; d <= divisions; d ++ ) {
pts.add( this.getPoint( d / divisions ) );
}
return pts;
}
List<V> getSpacedPoints([num divisions = 5, closedPath = false]) #
inherited from Curve
List<V> getSpacedPoints( [num divisions = 5, closedPath = false] ) {
var d, pts = [];
for ( d = 0; d <= divisions; d ++ ) {
pts.add( this.getPointAt( d / divisions ) );
}
return pts;
}
V getTangent(t) #
inherited from Curve
V getTangent( t ) {
var delta = 0.0001;
var t1 = t - delta;
var t2 = t + delta;
// Capping in case of danger
if ( t1 < 0 ) t1 = 0;
if ( t2 > 1 ) t2 = 1;
var pt1 = getPoint( t1 );
var pt2 = getPoint( t2 );
var vec = pt2 - pt1;
return vec.normalize();
}
V getTangentAt(u) #
inherited from Curve
V getTangentAt( u ) {
var t = getUtoTmapping( u );
return getTangent( t );
}
List<V> getUPoints([List uList, closedPath = false]) #
inherited from Curve
List<V> getUPoints( [List uList , closedPath = false] ) {
var pts = [];
for ( var u in uList ) {
pts.add( this.getPointAt( u ) );
}
return pts;
}
dynamic getUtoTmapping(u, {distance: null}) #
inherited from Curve
getUtoTmapping( u, {distance: null} ) {
var arcLengths = getLengths();
int i = 0, il = arcLengths.length;
var targetArcLength; // The targeted u distance value to get
if (distance != null) {
targetArcLength = distance;
} else {
targetArcLength = u * arcLengths[ il - 1 ];
}
//var time = Date.now();
// binary search for the index with largest value smaller than target u distance
var low = 0, high = il - 1, comparison;
while ( low <= high ) {
i = ( low + ( high - low ) / 2 ).floor().toInt(); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
comparison = arcLengths[ i ] - targetArcLength;
if ( comparison < 0 ) {
low = i + 1;
continue;
} else if ( comparison > 0 ) {
high = i - 1;
continue;
} else {
high = i;
break;
// DONE
}
}
i = high;
//console.log('b' , i, low, high, Date.now()- time);
if ( arcLengths[ i ] == targetArcLength ) {
var t = i / ( il - 1 );
return t;
}
// we could get finer grain at lengths, or use simple interpolatation between two points
var lengthBefore = arcLengths[ i ];
var lengthAfter = arcLengths[ i + 1 ];
var segmentLength = lengthAfter - lengthBefore;
// determine where we are between the 'before' and 'after' points
var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
// add that fractional amount to t
var t = ( i + segmentFraction ) / ( il -1 );
return t;
}