tuo-verb
Version:
A CAD library for the web
1,592 lines (1,109 loc) • 127 kB
JavaScript
var should = require('should')
, verb = require('../build/js/verb.js');
// necessary for multi-threading
verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/";
// some testing utilities
function vecShouldBe( expected, test, tol ){
if (tol === undefined) tol = verb.core.Constants.TOLERANCE;
test.length.should.be.equal( expected.length );
for (var i = 0; i < test.length; i++){
test[i].should.be.approximately( expected[i], tol );
}
}
function last(a){
return a[a.length-1];
}
describe("verb.eval.Eval.knotSpanGivenN",function(){
it('returns correct result', function(){
var n = 7
, degree = 2
, knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5];
should.equal( 4, verb.eval.Eval.knotSpanGivenN( n, degree, 2.5, knots ) );
should.equal( 3, verb.eval.Eval.knotSpanGivenN( n, degree, 1, knots ) );
should.equal( 3, verb.eval.Eval.knotSpanGivenN( n, degree, 1.5, knots ) );
should.equal( 7, verb.eval.Eval.knotSpanGivenN( n, degree, 4.9, knots ) );
should.equal( 7, verb.eval.Eval.knotSpanGivenN( n, degree, 10, knots ) );
should.equal( 7, verb.eval.Eval.knotSpanGivenN( n, degree, 5, knots ) );
should.equal( 2, verb.eval.Eval.knotSpanGivenN( n, degree, 0, knots ) );
should.equal( 2, verb.eval.Eval.knotSpanGivenN( n, degree, -1, knots ) );
});
});
describe("verb.eval.Eval.knotSpan",function(){
it('returns correct result for degree 2 curve', function(){
var degree = 2
, knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5];
should.equal( 4, verb.eval.Eval.knotSpan( degree, 2.5, knots ) );
should.equal( 3, verb.eval.Eval.knotSpan( degree, 1, knots ) );
should.equal( 3, verb.eval.Eval.knotSpan( degree, 1.5, knots ) );
should.equal( 7, verb.eval.Eval.knotSpan( degree, 4.9, knots ) );
should.equal( 7, verb.eval.Eval.knotSpan( degree, 10, knots ) ); // above span
should.equal( 7, verb.eval.Eval.knotSpan( degree, 5, knots ) ); // top of span
should.equal( 2, verb.eval.Eval.knotSpan( degree, 0, knots ) ); // bottom span
});
});
describe("verb.eval.Eval.basisFunctions, basisFunctionsGivenKnotSpanIndex",function(){
it('return correct results', function(){
var degree = 2
, span = 4
, knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5];
var N1 = verb.eval.Eval.basisFunctionsGivenKnotSpanIndex( 4, 2.5, degree, knots );
should.equal( 3, N1.length );
should.equal( 0.125, N1[0] );
should.equal( 0.75, N1[1] );
should.equal( 0.125, N1[2] );
var N2 = verb.eval.Eval.basisFunctions( 2.5, degree, knots );
should.equal( 3, N2.length );
should.equal( 0.125, N2[0] );
should.equal( 0.75, N2[1] );
should.equal( 0.125, N2[2] );
});
});
describe("verb.eval.Eval.curvePoint",function(){
it('returns correct result for simple curve', function(){
var degree = 2
, n = 6
, knots = [0, 0, 0, 1, 2, 3, 4, 5, 5, 5]
, controlPoints = [ [10, 0], [20, 10], [30, 20], [40, 30], [50, 40], [60, 30], [70, 80]]
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Eval.curvePointGivenN( n, crv, 2.5);
should.equal( p[0], 40 );
should.equal( p[1], 30 );
var p_start = verb.eval.Eval.curvePointGivenN( n, crv, 0);
should.equal( p_start[0], 10 );
should.equal( p_start[1], 0 );
var p_end = verb.eval.Eval.curvePointGivenN( n, crv, 5);
should.equal( p_end[0], 70 );
should.equal( p_end[1], 80 );
});
});
describe("verb.eval.Eval.curvePointGivenN",function(){
it('returns correct result for simple curve', function(){
var degree = 3
, n = 4
, u = 0
, knots = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ]
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Eval.curvePoint( crv, u);
should.equal( p[0], 10 );
should.equal( p[1], 0 );
var p2 = verb.eval.Eval.curvePoint( crv, 1.0);
should.equal( p2[0], 50 );
should.equal( p2[1], 50 );
});
});
describe("verb.eval.Eval.areValidRelations",function(){
it('returns correct result for two cases', function(){
should.equal( false, verb.eval.Eval.areValidRelations( 0, 0, 0 ) );
should.equal( true, verb.eval.Eval.areValidRelations( 2, 2, 5 ) );
});
});
describe("verb.eval.Eval.derivativeBasisFunctionsGivenNI",function(){
it('returns correct results', function(){
// This needs to be tested better
var degree = 2
, n = 7
, span = 4
, knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5];
var N1 = verb.eval.Eval.derivativeBasisFunctionsGivenNI( span, 2.5, degree, n, knots );
// weights
should.equal( 0.125, N1[0][0] );
should.equal( 0.75, N1[0][1] );
should.equal( 0.125, N1[0][2] );
// derivatives
should.equal( -0.5, N1[1][0] );
should.equal( 1, N1[2][0] );
should.equal( 0, N1[1][1] );
should.equal( -2, N1[2][1] );
should.equal( 0.5, N1[1][2] );
should.equal( 1, N1[2][2] );
// length
should.equal( n + 1, N1.length );
should.equal( degree + 1, N1[0].length );
});
});
describe("verb.eval.Eval.curveDerivativesGivenN",function(){
it('returns correct result for simple curve', function(){
var degree = 3
, n = 3
, u = 0
, knots = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ]
, num_derivs = 2
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Eval.curveDerivativesGivenN( n, crv, u, num_derivs ) ;
should.equal( p[0][0], 10 );
should.equal( p[0][1], 0 );
should.equal( p[1][0] / p[1][1], 1 );
});
});
describe("verb.eval.Eval.curveDerivatives",function(){
it('returns correct result for simple curve', function(){
// This needs to be tested better
var degree = 3
, u = 0
, knots = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ]
, num_derivs = 2
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Eval.curveDerivatives( crv, u, num_derivs ) ;
should.equal( p[0][0], 10 );
should.equal( p[0][1], 0 );
should.equal( p[1][0] / p[1][1], 1 );
});
});
describe("verb.eval.Eval.surfacePointGivenNM",function(){
it('returns correct result for simple surface', function(){
// This needs to be tested better
var degreeU = 3
, degreeV = 3
, knotsU = [0, 0, 0, 0, 1, 1, 1, 1]
, knotsV = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints )
, n = 3
, m = 3;
var p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 0, 0 );
should.equal( p[0], 0 );
should.equal( p[1], 0 );
should.equal( p[2], 50 );
p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 1, 1 );
should.equal( p[0], 30 );
should.equal( p[1], -30 );
should.equal( p[2], 0 );
});
});
describe("verb.eval.Eval.surfacePoint",function(){
it('returns correct result for simple surface', function(){
// This needs to be tested better
var degreeU = 3
, degreeV = 3
, knotsU = [0, 0, 0, 0, 1, 1, 1, 1]
, knotsV = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints );
var p = verb.eval.Eval.surfacePoint( surface, 0, 0 );
should.equal( p[0], 0 );
should.equal( p[1], 0 );
should.equal( p[2], 50 );
p = verb.eval.Eval.surfacePoint( surface, 1, 1 );
should.equal( p[0], 30 );
should.equal( p[1], -30 );
should.equal( p[2], 0 );
});
it('returns correct result for another simple surface', function(){
var degreeU = 1
, degreeV = 3
, knotsU = [0, 0, 1, 1 ]
, knotsV = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ] ]
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints );
var p = verb.eval.Eval.surfacePoint( surface, 0, 0 );
should.equal( p[0], 0 );
should.equal( p[1], 0 );
should.equal( p[2], 50 );
});
});
describe("verb.eval.Eval.surfaceDerivativesGivenNM",function(){
it('returns correct derivatives for simple surface', function(){
var degreeU = 3
, degreeV = 3
, u = 0.0
, v = 0.0
, knotsU = [0, 0, 0, 0, 1, 1, 1, 1]
, knotsV = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [ [0, 0, 0], [10, 10, 0], [20, 10, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]
, n = 3
, m = 3
, num_derivatives = 1
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints );
var p = verb.eval.Eval.surfaceDerivativesGivenNM( n, m, surface, 0, 0, num_derivatives );
// 0th derivative with respect to u & v
should.equal( p[0][0][0], 0 );
should.equal( p[0][0][1], 0 );
should.equal( p[0][0][2], 0 );
// d/du
should.equal( p[0][1][0] / p[0][1][0], 1 );
should.equal( p[0][1][2], 0 );
// d/dv
should.equal( p[1][0][0] , 0 );
should.equal( p[1][0][1] , -30 );
should.equal( p[1][0][2] , 0 );
// dd/dudv
should.equal( p[1][1][0] , 0 );
should.equal( p[1][1][1] , 0 );
should.equal( p[1][1][2] , 0 );
});
});
describe("verb.eval.Eval.surfaceDerivatives",function(){
it('returns correct derivatives for simple surface', function(){
var degreeU = 3
, degreeV = 3
, u = 0.0
, v = 0.0
, knotsU = [0, 0, 0, 0, 1, 1, 1, 1]
, knotsV = [0, 0, 0, 0, 1, 1, 1, 1]
, controlPoints = [ [ [0, 0, 0], [10, 10, 0], [20, 10, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]
, n = 3
, m = 3
, num_derivatives = 1
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints );
var p = verb.eval.Eval.surfaceDerivatives( surface, 0, 0, num_derivatives );
// 0th derivative with respect to u & v
should.equal( p[0][0][0], 0 );
should.equal( p[0][0][1], 0 );
should.equal( p[0][0][2], 0 );
// d/du
should.equal( p[0][1][0] / p[0][1][0], 1 );
should.equal( p[0][1][2], 0 );
// d/dv
should.equal( p[1][0][0] , 0 );
should.equal( p[1][0][1] , -30 );
should.equal( p[1][0][2] , 0 );
// dd/dudv
should.equal( p[1][1][0] , 0 );
should.equal( p[1][1][1] , 0 );
should.equal( p[1][1][2] , 0 );
});
});
describe("verb.eval.Eval.homogenize1d",function(){
it('returns correct results', function(){
var weights = [1, 2, 3, 4]
, controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ]
, homo_controlPoints = verb.eval.Eval.homogenize1d( controlPoints, weights);
for (var i = 0; i < controlPoints.length; i++)
{
should.equal( homo_controlPoints[i][0], weights[i] * controlPoints[i][0] );
should.equal( homo_controlPoints[i][1], weights[i] * controlPoints[i][1] );
should.equal( homo_controlPoints[i][2], weights[i] );
}
weights = [1, 2, 3, 4];
controlPoints = [ [10, 0, 4], [20, 10, 3], [30, 20, 0], [50, 50, 10] ];
homo_controlPoints = verb.eval.Eval.homogenize1d( controlPoints, weights);
for (var i = 0; i < controlPoints.length; i++)
{
should.equal( homo_controlPoints[i][0], weights[i] * controlPoints[i][0] );
should.equal( homo_controlPoints[i][1], weights[i] * controlPoints[i][1] );
should.equal( homo_controlPoints[i][2], weights[i] * controlPoints[i][2] );
should.equal( homo_controlPoints[i][3], weights[i] );
}
});
});
describe("verb.eval.Eval.homogenize2d",function(){
it('homogenize2d', function(){
var weights = [ [ 1, -2, 3, 5 ],
[ 2, 1, 5, 2 ],
[ -3, 4, 7, 2 ],
[ 1, 6, -2, 12 ] ]
, controlPoints = [ [ [0, 0, 0], [10, 10, 0], [20, 10, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]
, homo_controlPoints = verb.eval.Eval.homogenize2d( controlPoints, weights)
, j = 0;
for (var i = 0; i < controlPoints.length; i++)
{
for (j = 0; j < controlPoints[i].length; j++)
{
should.equal( homo_controlPoints[i][j][0], weights[i][j] * controlPoints[i][j][0] );
should.equal( homo_controlPoints[i][j][1], weights[i][j] * controlPoints[i][j][1] );
should.equal( homo_controlPoints[i][j][2], weights[i][j] * controlPoints[i][j][2] );
should.equal( homo_controlPoints[i][j][3], weights[i][j] );
}
}
});
});
describe("verb.eval.Eval.dehomogenize",function(){
it('returns correct result', function(){
var weights = [ [ 1, -2, 3, 5 ],
[ 2, 1, 5, 2 ],
[ -3, 4, 7, 2 ],
[ 1, 6, -2, 12 ] ]
, controlPoints = [ [ [0, 0, 0], [10, 10, 0], [20, 10, 0], [30, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]
, homo_controlPoints = verb.eval.Eval.homogenize2d( controlPoints, weights)
, j = 0
, dehomo_pt = [];
for (var i = 0; i < controlPoints.length; i++)
{
for (j = 0; j < controlPoints[i].length; j++)
{
dehomo_pt = verb.eval.Eval.dehomogenize( homo_controlPoints[i][j] );
should.equal( dehomo_pt.length, controlPoints[i][j].length );
should.equal( dehomo_pt[0], controlPoints[i][j][0] );
should.equal( dehomo_pt[1], controlPoints[i][j][1] );
should.equal( dehomo_pt[2], controlPoints[i][j][2] );
}
}
});
});
describe("verb.eval.Eval.rationalCurvePoint",function(){
it('returns correct result for quarter circle', function(){
// this represents a single quarter arc, using a rational bezier curve
var degree = 2
, knots = [0, 0, 0, 1, 1, 1 ]
, controlPoints = [ [1, 0, 1], [1,1,1], [0,2,2] ]
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Eval.rationalCurvePoint( crv, 0);
should.equal( p[0], 1 );
should.equal( p[1], 0 );
p = verb.eval.Eval.rationalCurvePoint( crv, 0.5);
should.equal( p[0], 0.6 );
should.equal( p[1], 0.8 );
p = verb.eval.Eval.rationalCurvePoint( crv, 1);
should.equal( p[0], 0 );
should.equal( p[1], 1 );
});
});
describe("verb.eval.Eval.rationalSurfacePoint",function(){
it('returns correct result for cylinder patch', function(){
// quarter cylinder patch
var degreeU = 1
, degreeV = 2
, knotsU = [0, 0, 1, 1 ]
, knotsV = [0, 0, 0, 1, 1, 1 ]
, controlPoints = [ [ [1, 1, 0, 1], [1, 1, 1, 1], [2, 0, 2, 2] ],
[ [-1, 1, 0, 1], [-1, 1, 1, 1], [-2, 0, 2, 2] ] ]
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints );
var p = verb.eval.Eval.rationalSurfacePoint( surface, 0, 0 );
should.equal( p[0], 1 );
should.equal( p[1], 1 );
should.equal( p[2], 0 );
p = verb.eval.Eval.rationalSurfacePoint( surface, 0.5, 0.5 );
should.equal( p[0], 0 );
should.equal( p[1], 0.6 );
should.equal( p[2], 0.8 );
p = verb.eval.Eval.rationalSurfacePoint( surface, 1, 1 );
should.equal( p[0], -1 );
should.equal( p[1], 0 );
should.equal( p[2], 1 );
});
});
describe("verb.eval.Eval.rationalCurveDerivatives",function(){
// this represents a single quarter arc, using a rational bezier curve
var degree = 2
, knots = [0, 0, 0, 1, 1, 1 ]
, controlPoints = [ [1,0,1], [1,1,1], [0,2,2] ]
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
it('returns expected results with 2 derivatives', function(){
var num_derivatives = 2;
var p = verb.eval.Eval.rationalCurveDerivatives( crv, 0, num_derivatives);
should.equal( p[0][0], 1 );
should.equal( p[0][1], 0 );
should.equal( p[1][0], 0 );
should.equal( p[1][1], 2 );
should.equal( p[2][0], -4 );
should.equal( p[2][1], 0 );
p = verb.eval.Eval.rationalCurveDerivatives( crv, 1, num_derivatives);
should.equal( p[0][0], 0 );
should.equal( p[0][1], 1 );
should.equal( p[1][0], -1 );
should.equal( p[1][1], 0 );
should.equal( p[2][0], 1 );
should.equal( p[2][1], -1 );
});
it('returns expected results with 3 derivatives', function(){
var num_derivatives = 3;
var p = verb.eval.Eval.rationalCurveDerivatives( crv, 0, num_derivatives);
should.equal( p[3][0], 0 );
should.equal( p[3][1], -12 );
p = verb.eval.Eval.rationalCurveDerivatives( crv, 1, num_derivatives);
should.equal( p[3][0], 0 );
should.equal( p[3][1], 3 );
});
});
describe("verb.eval.Eval.rationalSurfaceDerivatives",function(){
// quarter cylinder patch, axis aligned with x axis, radius: 1
var degreeU = 1
, degreeV = 2
, knotsU = [0, 0, 1, 1 ]
, knotsV = [0, 0, 0, 1, 1, 1 ]
, controlPoints = [ [ [1, 1, 0, 1], [1, 1, 1, 1], [2, 0, 2, 2] ],
[ [-1, 1, 0, 1], [-1, 1, 1, 1], [-2, 0, 2, 2] ] ]
, surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints );
it('returns expected results with 1 derivative', function(){
var num_derivatives = 1;
var p = verb.eval.Eval.rationalSurfaceDerivatives( surface, 0, 0, num_derivatives );
should.equal( p[0][0][0], 1 );
should.equal( p[0][0][1], 1 );
should.equal( p[0][0][2], 0 );
should.equal( p[0][1][0], 0 );
should.equal( p[0][1][1], 0 );
should.equal( p[0][1][2], 2 );
should.equal( p[1][0][0], -2 );
should.equal( p[1][0][1], 0 );
should.equal( p[1][0][2], 0 );
p = verb.eval.Eval.rationalSurfaceDerivatives( surface, 1, 1, num_derivatives);
should.equal( p[0][0][0], -1 );
should.equal( p[0][0][1], 0 );
should.equal( p[0][0][2], 1 );
should.equal( p[0][1][0], 0 );
should.equal( p[0][1][1], -1 );
should.equal( p[0][1][2], 0 );
should.equal( p[1][0][0], -2 );
should.equal( p[1][0][1], 0 );
should.equal( p[1][0][2], 0 );
});
it('returns expected results with 2 derivatives', function(){
var num_derivatives = 2;
var p = verb.eval.Eval.rationalSurfaceDerivatives( surface, 0, 0, num_derivatives );
should.equal( p[0][2][0], 0 );
should.equal( p[0][2][1], -4 );
should.equal( p[0][2][2], 0 );
should.equal( p[1][1][0], 0 );
should.equal( p[1][1][1], 0 );
should.equal( p[1][1][2], 0 );
should.equal( p[2][0][0], 0 );
should.equal( p[2][0][1], 0 );
should.equal( p[2][0][2], 0 );
p = verb.eval.Eval.rationalSurfaceDerivatives( surface, 1, 1, num_derivatives);
should.equal( p[0][2][0], 0 );
should.equal( p[0][2][1], 1 );
should.equal( p[0][2][2], -1 );
should.equal( p[1][1][0], 0 );
should.equal( p[1][1][1], 0 );
should.equal( p[1][1][2], 0 );
should.equal( p[2][0][0], 0 );
should.equal( p[2][0][1], 0 );
should.equal( p[2][0][2], 0 );
});
});
describe("verb.eval.Eval.rationalCurvePoint",function(){
it('returns correct results for a line', function(){
var degree = 1
, knots = [0, 0, 1, 1]
, controlPoints = [ [0, 0, 0, 1], [10, 0, 0, 1] ]
, weights = [1, 1]
, u1 = 0.0
, u2 = 0.5
, u3 = 1.0
, crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p1 = verb.eval.Eval.rationalCurvePoint( crv, u1);
var p2 = verb.eval.Eval.rationalCurvePoint( crv, u2);
var p3 = verb.eval.Eval.rationalCurvePoint( crv, u3);
should.equal(p1[0], 0);
should.equal(p2[0], 5);
should.equal(p3[0], 10);
});
});
describe("verb.eval.Modify.curveKnotInsert",function(){
it('returns expected results when inserting 1 knot in the middle of a non-rational, cubic b-spline', function(){
var degree = 3
, u = 2.5
, knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]
, r = 1;
var controlPoints = [];
for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0]);
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var after = verb.eval.Modify.curveKnotInsert( crv, u, r );
after.controlPoints.forEach(function(cp){ should.exist(cp); });
after.knots.forEach(function(cp){ should.exist(cp); });
should.equal(knots.length + r, after.knots.length);
should.equal(controlPoints.length + r, after.controlPoints.length);
after.controlPoints[3][0].should.be.approximately( 2.8333333333, verb.core.Constants.TOLERANCE );
after.controlPoints[4][0].should.be.approximately( 3.5, verb.core.Constants.TOLERANCE );
after.controlPoints[5][0].should.be.approximately( 4.1666666666, verb.core.Constants.TOLERANCE );
var p0 = verb.eval.Eval.curvePoint( crv, 2.5);
var p1 = verb.eval.Eval.curvePoint( after, 2.5);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
it('returns expected results when inserting 3 knots at the middle of a non-rational, cubic b-spline', function(){
var degree = 3
, u = 2.5
, knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]
, r = 3;
var controlPoints = [];
for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0]);
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var after = verb.eval.Modify.curveKnotInsert( crv, u, r );
after.controlPoints.forEach(function(cp){ should.exist(cp); });
after.knots.forEach(function(cp){ should.exist(cp); });
should.equal(knots.length + r, after.knots.length);
should.equal(controlPoints.length + r, after.controlPoints.length);
var p0 = verb.eval.Eval.curvePoint( crv, 2.5);
var p1 = verb.eval.Eval.curvePoint( after, 2.5);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
it('returns expected results when inserting 1 knots at the beginning of a non-rational, cubic b-spline', function(){
var degree = 3
, u = 0.5
, knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]
, r = 1;
var controlPoints = [];
for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0]);
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var after = verb.eval.Modify.curveKnotInsert( crv, u, r );
after.controlPoints.forEach(function(cp){ should.exist(cp); });
after.knots.forEach(function(cp){ should.exist(cp); });
should.equal(knots.length + r, after.knots.length);
should.equal(controlPoints.length + r, after.controlPoints.length);
var p0 = verb.eval.Eval.curvePoint( crv, 2.5);
var p1 = verb.eval.Eval.curvePoint( after, 2.5);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
it('returns expected results when inserting 1 knot at the middle of a non-rational, linear b-spline', function(){
var degree = 1
, u = 0.5
, knots = [ 0, 0, 1, 2, 3, 4, 5, 5 ]
, r = 1;
var controlPoints = [];
for (var i = 0; i < 6; i++) controlPoints.push([i, 0, 0]);
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var after = verb.eval.Modify.curveKnotInsert( crv, u, r );
after.controlPoints.forEach(function(cp){ should.exist(cp); });
after.knots.forEach(function(cp){ should.exist(cp); });
should.equal(knots.length + r, after.knots.length);
should.equal(controlPoints.length + r, after.controlPoints.length);
var p0 = verb.eval.Eval.curvePoint( crv, 2.5);
var p1 = verb.eval.Eval.curvePoint( after, 2.5);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
});
describe("verb.eval.Eval.curveKnotRefine",function(){
function cubicInsert(u, r){
var degree = 3
, knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]
, new_knots = [];
for (var i = 0; i < r; i++){
new_knots.push(u);
}
var controlPoints = [];
for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0]);
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var after = verb.eval.Modify.curveKnotRefine( crv, new_knots );
after.controlPoints.forEach(function(cp){ should.exist(cp); });
after.knots.forEach(function(cp){ should.exist(cp); });
should.equal(knots.length + r, after.knots.length);
should.equal(controlPoints.length + r, after.controlPoints.length);
var p0 = verb.eval.Eval.curvePoint( crv, 2.5);
var p1 = verb.eval.Eval.curvePoint( after, 2.5);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
}
it('returns expected results when inserting multiple knots in the middle of a non-rational, cubic b-spline', function(){
cubicInsert(2.5, 1);
cubicInsert(2.5, 2);
cubicInsert(2.5, 3);
cubicInsert(2.5, 4);
cubicInsert(0.5, 1);
cubicInsert(0.5, 2);
cubicInsert(0.5, 3);
cubicInsert(0.5, 4);
cubicInsert(3, 1);
cubicInsert(3, 2);
});
});
describe("verb.eval.Divide.curveSplit",function(){
function cubicSplit(u){
var degree = 3
, knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ];
var controlPoints = [];
for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0, 1]);
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var after = verb.eval.Divide.curveSplit( crv, u );
for (var i = 0; i < degree + 1; i++ ){
var d = after[0].knots.length - (degree+1);
after[0].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE);
}
for (var i = 0; i < degree + 1; i++){
var d = 0;
after[1].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE);
}
// a point evaluated on each curve is the same
var p0 = verb.eval.Eval.curvePoint( after[0], after[0].knots[ after[0].knots.length-1] );
var p1 = verb.eval.Eval.curvePoint( after[1], after[1].knots[ 0] );
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
}
it('returns expected results when splitting a non-rational, cubic b-spline', function(){
cubicSplit( 0.5 );
cubicSplit( 3.5 );
});
});
describe("verb.eval.Analyze.knotMultiplicities",function(){
it('is correct for a basic example', function(){
var res = verb.eval.Analyze.knotMultiplicities( [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3] );
res.length.should.be.equal( 5 );
res[0].knot.should.be.equal( 0 );
res[0].mult.should.be.equal( 4 );
res[1].knot.should.be.equal( 1 );
res[1].mult.should.be.equal( 2 );
res[2].knot.should.be.equal( 2 );
res[2].mult.should.be.equal( 3 );
res[3].knot.should.be.equal( 3 );
res[3].mult.should.be.equal( 1 );
res[4].knot.should.be.equal( 3.3 );
res[4].mult.should.be.equal( 1 );
});
});
describe("verb.eval.Modify.decomposeCurveIntoBeziers",function(){
it('is correct for a basic example', function(){
var degree = 3
, knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ];
var controlPoints = [];
for (var i = 0; i < 8; i++) {
controlPoints.push([i, 0, 0]);
}
var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var res = verb.eval.Modify.decomposeCurveIntoBeziers( crv );
res.length.should.be.equal( 5 );
res.forEach(function(x){
var u0 = x.knots[0];
var pt0 = verb.eval.Eval.curvePoint( x, u0);
var pt1 = verb.eval.Eval.curvePoint( crv, u0);
( verb.core.Vec.norm(verb.core.Vec.sub(pt0, pt1))).should.be.approximately(0, verb.core.Constants.TOLERANCE );
});
});
});
describe("verb.core.Mat.transpose",function(){
it('is correct for a basic example', function(){
var a = [ [6,5,4], [1,2,3] ];
verb.core.Mat.transpose(a).should.eql( [[6,1], [5,2], [4,3]])
});
it('is correct for empty array', function(){
verb.core.Mat.transpose([]).should.eql( [] );
});
});
describe("verb.eval.Modify.surfaceKnotRefine",function(){
var degree = 3
, knotsV = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]
, knotsU = [0, 0, 0, 0, 0.5, 1, 1, 1, 1]
, controlPoints = [
[ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ],
[ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ] ]
, surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints );
it('can add knots into a surface in the u direction', function(){
var r = 1;
var u = 0.2;
var new_knots = [];
for (var i = 0; i < r; i++){
new_knots.push(u);
}
var res = verb.eval.Modify.surfaceKnotRefine( surface, new_knots, false );
res.controlPoints.forEach(function(cp){ should.exist(cp); });
res.knotsU.forEach(function(cp){ should.exist(cp); });
res.knotsV.forEach(function(cp){ should.exist(cp); });
should.equal(knotsU.length + r, res.knotsU.length);
should.equal(controlPoints.length + r, res.controlPoints.length);
var p0 = verb.eval.Eval.surfacePoint( surface, 0.5, 0.25 );
var p1 = verb.eval.Eval.surfacePoint( res, 0.5, 0.25);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
it('can add knots into a surface in the v direction', function(){
var r = 1;
var u = 0.2;
var new_knots = [];
for (var i = 0; i < r; i++){
new_knots.push(u);
}
var res = verb.eval.Modify.surfaceKnotRefine( surface, new_knots, true );
res.controlPoints.forEach(function(cp){ should.exist(cp); });
res.knotsU.forEach(function(cp){ should.exist(cp); });
res.knotsV.forEach(function(cp){ should.exist(cp); });
should.equal(knotsV.length + r, res.knotsV.length);
should.equal(controlPoints[0].length + r, res.controlPoints[0].length);
var p0 = verb.eval.Eval.surfacePoint( surface, 0.5, 0.25 );
var p1 = verb.eval.Eval.surfacePoint( res, 0.5, 0.25);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
});
describe("verb.eval.Divide.surfaceSplit", function(){
var degree = 3
, knotsV = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]
, knotsU = [0, 0, 0, 0, 0.5, 1, 1, 1, 1]
, controlPoints = [
[ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ],
[ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ] ]
, surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints );
it('can split a surface in the u direction', function(){
var u = 0.2;
var res = verb.eval.Divide.surfaceSplit( surface, u, false );
res[0].controlPoints.forEach(function(cp){ should.exist(cp); });
res[0].knotsU.forEach(function(cp){ should.exist(cp); });
res[0].knotsV.forEach(function(cp){ should.exist(cp); });
should.exist( res[0].degreeU );
should.exist( res[0].degreeV );
res[1].controlPoints.forEach(function(cp){ should.exist(cp); });
res[1].knotsU.forEach(function(cp){ should.exist(cp); });
res[1].knotsV.forEach(function(cp){ should.exist(cp); });
should.exist( res[1].degreeU );
should.exist( res[1].degreeV );
var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 );
var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
p0 = verb.eval.Eval.surfacePoint( surface, 0.8, 0.8 );
p1 = verb.eval.Eval.surfacePoint( res[1], 0.8, 0.8);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
it('can split a surface in the v direction', function(){
var u = 0.2;
var res = verb.eval.Divide.surfaceSplit( surface, u, true );
res[0].controlPoints.forEach(function(cp){ should.exist(cp); });
res[0].knotsU.forEach(function(cp){ should.exist(cp); });
res[0].knotsV.forEach(function(cp){ should.exist(cp); });
should.exist( res[0].degreeU );
should.exist( res[0].degreeV );
res[1].controlPoints.forEach(function(cp){ should.exist(cp); });
res[1].knotsU.forEach(function(cp){ should.exist(cp); });
res[1].knotsV.forEach(function(cp){ should.exist(cp); });
should.exist( res[1].degreeU );
should.exist( res[1].degreeV );
var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 );
var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
p0 = verb.eval.Eval.surfacePoint( surface, 0.8, 0.8 );
p1 = verb.eval.Eval.surfacePoint( res[1], 0.8, 0.8);
p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE);
p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE);
p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE);
});
});
describe("verb.eval.Eval.rationalCurveRegularSample",function(){
it('should return 10 samples when asked to', function(){
var degree = 2
, knots = [0, 0, 0, 1, 1, 1 ]
, controlPoints = [ [1, 0, 0, 1], [1, 1, 0, 1], [0, 2, 0, 2] ]
, numSamples = 10
, curve = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Tess.rationalCurveRegularSample( curve, numSamples);
should.equal(p.length, 10);
p.map( function(e){ e.length.should.be.equal(3); });
});
});
describe("verb.eval.Eval.threePointsAreFlat",function(){
it('should identify flat line by returning true', function(){
// this represents a single quarter arc, using a rational bezier curve
var p1 = [0,0,0],
p2 = [0,2,0],
p3 = [0,4,0];
should.equal(true, verb.core.Trig.threePointsAreFlat(p1,p2,p3,1e-5));
});
});
describe("verb.eval.Tess.rationalCurveAdaptiveSample",function(){
it('returns two end points for a line', function(){
var degree = 1
, knots = [0, 0, 1, 1]
, controlPoints = [ [0, 0, 0, 1], [10, 0, 0, 1] ]
, curve = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5);
should.equal(p[0][0], 0);
should.equal(p[1][0], 10);
p.map( function(e){ e.length.should.be.equal(3); });
});
it('returns all the control points for a degree 1 curve', function(){
var degree = 1
, knots = [0, 0, 0.25, 0.5, 0.75, 1, 1]
, controlPoints = [ [0, 0, 0, 1], [10, 10, 0, 1], [14, 20, 0, 1], [10, 32, 4, 1], [12, 16, 22, 1]]
, curve = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5);
p.should.be.instanceof(Array).and.have.lengthOf(5);
p[0].should.be.instanceof(Array).and.have.lengthOf(3);
p[0].should.eql([0,0,0]);
p[4].should.eql([12,16,22]);
p.map( function(e){ e.length.should.be.equal(3); });
});
it('makes more points for an arc', function(){
var degree = 2
, knots = [0, 0, 0, 1, 1, 1 ]
, v = Math.sqrt(2) / 2
, controlPoints = [ [1, 0, 0, 1], [v, v, 0, v], [0, 1, 0, 1] ]
, curve = new verb.core.NurbsCurveData( degree, knots, controlPoints );
var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-8, true);
var p2 = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-4, true);
var prev = - 1e-8;
for (var i = 0; i < p.length; i++){
p[i][0].should.be.above(prev);
p[i][0].should.be.within(-1e-8, 1 + 1e-8);
prev = p[i][0];
}
p.should.be.instanceof(Array).and.not.have.lengthOf(0);
p2.should.be.instanceof(Array).and.not.have.lengthOf(0);
p.should.be.instanceof(Array).and.not.have.lengthOf(p2.length);
should.equal(p[p.length-1][0], 1.0);
should.equal(p2[p2.length-1][0], 1.0);
p.map( function(e){ e.length.should.be.equal(4); });
p2.map( function(e){ e.length.should.be.equal(4); });
});
});
describe("verb.eval.Tess.rationalSurfaceAdaptive",function(){
function getComplexSurface(){
var degree = 3
, knots = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]
, pts = [ [ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ],
[ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ],
[ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ],
[ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ],
[ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ],
[ [0, -50, 12], [10, -50, 0], [20, -50, 0], [30, -50, 0] , [50, -50, 0], [50, -50, -15] ], ]
, wts = [ [ 1, 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1] ];
pts = verb.eval.Eval.homogenize2d(pts, wts);
var srfObj = {
degreeU : degree,
degreeV : degree,
knotsU : knots,
knotsV : knots,
controlPoints : pts
};
return srfObj;
}
it('produces a mesh from a divided surface', function(){
var srf = getComplexSurface();
var mesh = verb.eval.Tess.rationalSurfaceAdaptive( srf, { minDivsU: 1, minDivsV: 4 } );
mesh.faces.length.should.be.greaterThan( 8 );
mesh.points.forEach(function(x){ x.length.should.be.equal( 3 ); })
mesh.points.length.should.be.equal( mesh.normals.length );
mesh.uvs.length.should.be.equal( mesh.normals.length );
});
});
describe("verb.eval.Make.ellipseArc",function(){
it('returns correct result for unit arc from 0 to 90 deg', function(){
var center = [0,0,0]
, rx = 5
, ry = 1
, x = [rx,0,0]
, y = [0,ry,0]
, start = 0
, end = Math.PI/2;
var ellipse = verb.eval.Make.ellipseArc(center, x, y, start, end);
// the typical parametric rep of an ellipse
var xmid = rx * Math.cos( Math.PI / 4 )
, ymid = ry * Math.sin( Math.PI / 4 );
var p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5);
p[0].should.be.approximately( xmid, verb.core.Constants.EPSILON );
p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
p = verb.eval.Eval.rationalCurvePoint( ellipse, 1);
p[0].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[1].should.be.approximately( ry, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
p = verb.eval.Eval.rationalCurvePoint( ellipse, 0);
p[0].should.be.approximately( rx, verb.core.Constants.EPSILON );
p[1].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
});
it('returns correct result for unit arc from 0 to 90 deg', function(){
var center = [0,0,0]
, rx = 5
, ry = 1
, x = [rx,0,0]
, y = [0,ry,0]
, start = 0
, end = Math.PI / 2;
var arc = verb.eval.Make.ellipseArc(center, x, y, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 1);
p[0].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[1].should.be.approximately( ry, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
});
it('returns correct result for unit arc from 45 to 135 deg', function(){
var center = [0,0,0]
, rx = 1
, ry = 10
, x = [rx,0,0]
, y = [0,ry,0]
, start = Math.PI/4
, end = 3 * Math.PI/4;
var arc = verb.eval.Make.ellipseArc(center, x, y, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 1);
// the typical parametric rep of an ellipse
var xmid = rx * Math.cos( 3 * Math.PI / 4 )
, ymid = ry * Math.sin( 3 * Math.PI / 4 );
p[0].should.be.approximately( xmid, verb.core.Constants.EPSILON );
p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
});
it('returns correct result for complete ellipse', function(){
var center = [0,0,0]
, rx = 1
, ry = 10
, x = [rx,0,0]
, y = [0,ry,0]
, start = 0
, end = Math.PI * 2;
var ellipse = verb.eval.Make.ellipseArc(center, x, y, start, end);
// the typical parametric rep of an ellipse
var xmid = rx * Math.cos( Math.PI / 4 )
, ymid = ry * Math.sin( Math.PI / 4 );
var p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.125);
p[0].should.be.approximately( xmid, verb.core.Constants.EPSILON );
p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.25);
p[0].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[1].should.be.approximately( ry, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5);
p[0].should.be.approximately( -rx, verb.core.Constants.EPSILON );
p[1].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
p = verb.eval.Eval.rationalCurvePoint( ellipse, 0);
p[0].should.be.approximately( rx, verb.core.Constants.EPSILON );
p[1].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
});
});
describe("verb.eval.Make.extrudedSurface",function(){
it('can extrude a line into a plane', function(){
var axis = [0,0,1]
, length = 5
, prof_degree = 1
, prof_ctrl_pts = [[0,1,0,1], [1,0,0,1]]
, prof_knots = [0,0,1,1]
, profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts );
var comps = verb.eval.Make.extrudedSurface(axis, length, profile);
// the first row are the profile control pts
should.equal( 0, comps.controlPoints[2][0][0] );
should.equal( 1, comps.controlPoints[2][0][1] );
should.equal( 0, comps.controlPoints[2][0][2] );
should.equal( 1, comps.controlPoints[2][1][0] );
should.equal( 0, comps.controlPoints[2][1][1] );
should.equal( 0, comps.controlPoints[2][1][2] );
// sample at the center
var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5);
should.equal( Math.abs( 0.5 - p[0]) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( 0.5 - p[1]) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( 2.5 - p[2]) < verb.core.Constants.EPSILON, true );
});
it('can extrude a 90 deg quadratic arc bezier curve', function(){
var axis = [0,0,1]
, length = 5
, prof_degree = 2
, prof_ctrl_pts = [[0,1,0], [1,1,0], [1,0,0]]
, prof_knots = [0,0,0,1,1,1]
, prof_weights = [1, Math.sqrt(2) / 2, 1]
, profile = new verb.core.NurbsCurveData( prof_degree, prof_knots,
verb.eval.Eval.homogenize1d(prof_ctrl_pts, prof_weights) );
var comps = verb.eval.Make.extrudedSurface(axis, length, profile);
// the first row are the profile control pts
should.equal( 0, comps.controlPoints[2][0][0] );
should.equal( 1, comps.controlPoints[2][0][1] );
should.equal( 0, comps.controlPoints[2][0][2] );
should.equal( 1, comps.controlPoints[2][0][3] );
should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][0] );
should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][1] );
should.equal( 0, comps.controlPoints[2][1][2] );
should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][3] );
should.equal( 1, comps.controlPoints[2][2][0] );
should.equal( 0, comps.controlPoints[2][2][1] );
should.equal( 0, comps.controlPoints[2][2][2] );
should.equal( 1, comps.controlPoints[2][2][3] );
// sample at the center
var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5);
should.equal( Math.abs( Math.sqrt(2)/2 - p[0]) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( Math.sqrt(2)/2 - p[1]) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( 2.5 - p[2]) < verb.core.Constants.EPSILON, true );
});
});
describe("verb.eval.Make.arc",function(){
it('returns correct result for unit arc from 0 to 90 deg', function(){
var center = [0,0,0]
, x = [1,0,0]
, y = [0,1,0]
, r = 1
, start = 0
, end = Math.PI/2;
var arc = verb.eval.Make.arc(center, x, y, 1, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5);
should.equal( Math.abs( p[0] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( p[1] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true );
should.equal( p[2], 0 );
});
it('returns correct result for unit arc from 0 to 45 deg', function(){
var center = [0,0,0]
, x = [1,0,0]
, y = [0,1,0]
, r = 1
, start = 0
, end = Math.PI/4;
var arc = verb.eval.Make.arc(center, x, y, 1, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 1);
should.equal( Math.abs( p[0] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( p[1] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true );
should.equal( p[2], 0 );
});
it('returns correct result for unit arc from 45 to 135 deg', function(){
var center = [0,0,0]
, x = [1,0,0]
, y = [0,1,0]
, r = 1
, start = Math.PI/4
, end = 3 * Math.PI/4;
var arc = verb.eval.Make.arc(center, x, y, 1, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5);
should.equal( Math.abs( p[0] ) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( p[1] - 1 ) < verb.core.Constants.EPSILON, true );
should.equal( p[2], 0 );
});
it('returns correct result for unit circle', function(){
var center = [0,0,0]
, x = [1,0,0]
, y = [0,1,0]
, r = 5
, start = 0
, end = Math.PI;
var arc = verb.eval.Make.arc(center, x, y, r, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5);
p[0].should.be.approximately( 0, verb.core.Constants.EPSILON );
p[1].should.be.approximately( 5 , verb.core.Constants.EPSILON);
p[2].should.be.approximately( 0, verb.core.Constants.EPSILON );
});
it('returns correct result for unit circle', function(){
var center = [0,0,0]
, x = [1,0,0]
, y = [0,1,0]
, r = 1
, start = 0
, end = Math.PI * 2;
var arc = verb.eval.Make.arc(center, x, y, 1, start, end);
var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5);
should.equal( Math.abs( p[0] + 1) < verb.core.Constants.EPSILON, true );
should.equal( Math.abs( p[1] ) < verb.core.Constants.EPSILON, true );
should.equal( p[2], 0 );
});
});