tuo-verb
Version:
A CAD library for the web
828 lines (547 loc) • 23.9 kB
JavaScript
var should = require('should')
, verb = require('../build/js/verb.js');
console.log(verb);
// 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.core.BoundingBox.init",function(){
it('should allow array of point arguments', function(){
var bb1 = new verb.core.BoundingBox([[5,5,5], [10,10,10]]);
should.equal( bb1.min[0], 5 );
should.equal( bb1.min[1], 5 );
should.equal( bb1.min[2], 5 );
should.equal( bb1.max[0], 10 );
should.equal( bb1.max[1], 10 );
should.equal( bb1.max[2], 10 );
});
});
describe("verb.core.BoundingBox.intersects",function(){
it('returns expected results', function(){
var bb1 = new verb.core.BoundingBox([ [5,5,5], [10,10,10] ])
, bb2 = new verb.core.BoundingBox([ [0,0,0], [10,10,10] ])
, bb3 = new verb.core.BoundingBox([ [-2,-2,-2], [-1,-1,-1] ]);
should.equal( bb1.intersects(bb2), true );
should.equal( bb1.intersects(bb3), false );
should.equal( bb2.intersects(bb3), false );
});
});
describe("verb.core.BoundingBox.intersect",function(){
it('returns expected results', function(){
// initialize a bounding box
var bb1 = new verb.core.BoundingBox([ [5,5,5], [10,10,10] ])
, bb2 = new verb.core.BoundingBox([ [0,0,0], [10,10,10] ])
, bb3 = new verb.core.BoundingBox([ [-2,-2,-2], [-1,-1,-1] ]);
// intersect bounding boxes
var int_bb1_bb2 = bb1.intersect(bb2)
, int_bb1_bb3 = bb1.intersect(bb3);
should.equal( int_bb1_bb2.min[0], 5 );
should.equal( int_bb1_bb2.min[1], 5 );
should.equal( int_bb1_bb2.min[2], 5 );
should.equal( int_bb1_bb2.max[0], 10 );
should.equal( int_bb1_bb2.max[1], 10 );
should.equal( int_bb1_bb2.max[2], 10 );
should.equal( int_bb1_bb3, null ); //non-intersect is null
});
});
describe("verb.core.BoundingBox.intervalsOverlap",function(){
it('returns expected results', function(){
should.equal( verb.core.BoundingBox.intervalsOverlap( 0, 1, 0, 10 ), true );
should.equal( verb.core.BoundingBox.intervalsOverlap( 0, 1, 1, 10 ), true );
should.equal( verb.core.BoundingBox.intervalsOverlap( 0, 1, 1+1e-3, 10 ), false );
should.equal( verb.core.BoundingBox.intervalsOverlap( 0, 1, 2, 10 ), false );
});
});
describe("verb.core.BoundingBox.contains",function(){
it('returns expected results', function(){
var bb4 = new verb.core.BoundingBox([ [0,0,0], [1,1,1] ])
, bb5 = new verb.core.BoundingBox();
should.equal( bb4.contains( [0,0,0] ), true );
should.equal( bb4.contains( [1,1,1] ), true );
should.equal( bb4.contains( [1,1,1+1e-3] ), false );
should.equal( bb4.contains( [1,1,1-1e-3] ), true );
should.equal( bb5.contains( [0,0,0] ), false );
});
});
describe("verb.core.BoundingBox.contains",function(){
it('BoundingBox.clear', function(){
var bb1 = new verb.core.BoundingBox([ [5,5,5], [10,10,10] ]);
bb1.clear();
should.equal( bb1.initialized, false );
});
});
describe("verb.core.BoundingBox.getAxisLength",function(){
it('should return correct value', function(){
var bb1 = new verb.core.BoundingBox([ [-1,2,3], [10,10,10] ]);
should.equal( bb1.getAxisLength(0), 11 );
should.equal( bb1.getAxisLength(1), 8 );
should.equal( bb1.getAxisLength(2), 7 );
});
});
describe("verb.core.BoundingBox.getLongestAxis",function(){
it('should return correct value', function(){
var bb1 = new verb.core.BoundingBox([ [-1,2,3], [10,10,10] ]);
should.equal( bb1.getLongestAxis(0), 0 );
});
});
describe("verb.core.BoundingBox.getAxisLength",function(){
it('should return 0 when given out of bounds index', function(){
var bb1 = new verb.core.BoundingBox([ [-1,2,3], [10,10,10] ]);
should.equal( bb1.getAxisLength(8), 0 );
should.equal( bb1.getAxisLength(-1), 0 );
should.equal( bb1.getAxisLength(4), 0 );
should.equal( bb1.getAxisLength(3), 0 );
});
});
describe("verb.core.BoundingBox.getAxisLength",function(){
it('should return 0 when given out of bounds index', function(){
var bb1 = new verb.core.BoundingBox([ [-1,2,3], [10,10,10] ]);
should.equal( bb1.getAxisLength(8), 0 );
should.equal( bb1.getAxisLength(-1), 0 );
should.equal( bb1.getAxisLength(4), 0 );
should.equal( bb1.getAxisLength(3), 0 );
});
});
describe("verb.core.BoundingBox.clear",function(){
it('should set initialized to false', function(){
var bb1 = new verb.core.BoundingBox([ [5,5,5], [10,10,10] ]);
bb1.clear();
should.equal( bb1.initialized, false );
});
});
function getFlatSurface(){
var p1 = [0,0,0]
, p2 = [1,0,0]
, p3 = [1,1,0]
, p4 = [0,1,0];
var p1p4 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p1, p4 ));
var p2p3 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p2, p3 ));
var p3p4 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p3, p4 ));
var p1p2 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p1, p2 ));
var p1p4p2p3 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p1p4, p2p3 ));
var cpts = [ [p1, p1p4, p4],
[p1p2, p1p4p2p3, p3p4],
[p2, p2p3, p3] ];
var wts = [[1,1,1], [1,1,1], [1,1,1]];
cpts = verb.eval.Eval.homogenize2d(cpts, wts);
return {"knotsU": [0,0,0,1,1,1],
"knotsV": [0,0,0,1,1,1],
"controlPoints": cpts,
"degreeU": 2,
"degreeV": 2 };
}
describe("verb.core.AdaptiveRefinementNode.constructor",function(){
it('can be instantiated', function(){
var f = new verb.core.AdaptiveRefinementNode( getFlatSurface() );
f.corners[0].uv[0].should.be.equal(0);
f.corners[2].uv[0].should.be.equal(1);
f.corners[0].uv[1].should.be.equal(0);
f.corners[2].uv[1].should.be.equal(1);
f.corners.length.should.be.equal(4);
});
});
function extractUv(x){ return x.uv; }
describe("verb.core.AdaptiveRefinementNode.getEdgeCorners",function(){
it('returns expected result for node without children', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.getEdgeCorners( 0 ).map(extractUv).should.be.eql( [[0,0]] );
f.getEdgeCorners( 1 ).map(extractUv).should.be.eql( [[1,0]] );
f.getEdgeCorners( 2 ).map(extractUv).should.be.eql( [[1,1]] );
f.getEdgeCorners( 3 ).map(extractUv).should.be.eql( [[0,1]] );
});
it('returns expected result for node with children', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.divide({ minDepth : 1 });
f.children.length.should.be.equal( 2 );
// split horizontally
f.getEdgeCorners(0).map(extractUv).should.be.eql( [ [ 0, 0 ] ] );
f.getEdgeCorners(1).map(extractUv).should.be.eql( [ [ 1, 0 ], [ 1, 0.5 ] ] );
f.getEdgeCorners(2).map(extractUv).should.be.eql( [ [ 1, 1 ] ] );
f.getEdgeCorners(3).map(extractUv).should.be.eql( [ [ 0, 1 ], [ 0, 0.5 ] ] );
});
it('returns expected result for node with nested children', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.divide({ minDepth : 2 });
f.children.length.should.be.equal( 2 );
f.children[0].children.length.should.be.equal( 2 );
f.children[1].children.length.should.be.equal( 2 );
f.getEdgeCorners(0).map(extractUv).should.be.eql( [ [ 0, 0 ], [ 0.5, 0 ] ] );
f.getEdgeCorners(1).map(extractUv).should.be.eql( [ [ 1, 0 ], [ 1, 0.5 ] ] );
f.getEdgeCorners(2).map(extractUv).should.be.eql( [ [ 1, 1 ], [ 0.5, 1 ] ] );
f.getEdgeCorners(3).map(extractUv).should.be.eql( [ [ 0, 1 ], [ 0, 0.5 ] ] );
});
});
describe("verb.core.AdaptiveRefinementNode.getAllCorners",function(){
it('returns expected result for edge with more vertices on opposite side', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.divide({ minDepth : 1 }); // now f is split in 2 horizontally
f.children[0].divide({ minDepth : 1 }); // f[0] is split in 2 vertically
f.children[1].divide({ minDepth : 1 }); // f[1] is split in 2 veritcally
f.children[1].children[1].divide({ minDepth : 1 }); // f[1][3] is split in 2 horizontally
f.children[0].getAllCorners(1).map(extractUv).should.eql( [ [ 1, 0 ] ] );
f.children[0].children[1].getAllCorners(2).map(extractUv).should.eql( [ [ 1, 0.5 ] ] );
});
it('returns expected result for edge with neighbors that has with lesser number of vertices on opposite side', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.divide({ minDepth : 1 }); // now f is split in 2 horizontally
f.children[0].divide({ minDepth : 1 }); // f[0] is split in 2 vertically
f.children[1].divide({ minDepth : 1 }); // f[1] is split in 2 veritcally
f.children[1].children[1].divide({ minDepth : 1 }); // f[1][3] is split in 2 horizontally
f.children[1].children[1].children[1].getAllCorners(3).map(extractUv).should.eql( [ [ 0, 1 ] ] );
});
});
describe("verb.core.Vec.signedAngleBetween",function(){
it('computes correct area for triangular prism', function(){
verb.core.Vec.signedAngleBetween( [1,0,0], [0,1,0], [0,0,1] ).should.be.approximately( Math.PI / 2, verb.core.Constants.EPSILON );
verb.core.Vec.signedAngleBetween( [1,0,0], [-1,0,0], [0,0,1] ).should.be.approximately( Math.PI, verb.core.Constants.EPSILON );
verb.core.Vec.signedAngleBetween( [1,0,0], [0,-1,0], [0,0,1] ).should.be.approximately( 3 * Math.PI / 2, verb.core.Constants.EPSILON );
});
});
describe("verb.core.Trig.isPointInPlane",function(){
it('works for a few basic cases', function(){
verb.core.Trig.isPointInPlane( [0,0,0], new verb.core.Plane( [0,0,0], [1,0,0] ), verb.core.Constants.EPSILON ).should.be.equal( true );
verb.core.Trig.isPointInPlane( [0,0,1], new verb.core.Plane( [0,0,0], [1,0,0] ), verb.core.Constants.EPSILON ).should.be.equal( true );
verb.core.Trig.isPointInPlane( [1,0,1], new verb.core.Plane( [0,0,0], [1,0,0] ), verb.core.Constants.EPSILON ).should.be.equal( false );
});
});
describe("verb.core.AdaptiveRefinementNode.divide",function(){
it('can be called with options.minDepth', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.divide({ minDepth : 2 });
f.children.length.should.be.equal( 2 );
f.children[0].children.length.should.be.equal( 2 );
f.children[1].children.length.should.be.equal( 2 );
});
it('can be called with no options provided', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
f.divide();
// no division is done
should.equal( f.children, null);
});
});
describe("verb.core.Trig.distToSegment",function(){
it('works for simple case', function(){
verb.core.Trig.distToSegment([ -10,0,0], [3,3,0], [5,0,0] ).should.be.equal( 3 );
});
});
describe("verb.core.AdaptiveRefinementNode.evalSrf",function(){
it('works as expected', function(){
var f = new verb.core.AdaptiveRefinementNode(getFlatSurface());
var res = f.evalSrf( 0, 0 );
vecShouldBe( [0,0,0], res.point );
vecShouldBe( [0,0,-1], res.normal );
res = f.evalSrf( 1,0 );
vecShouldBe( [1,0,0], res.point );
vecShouldBe( [0,0,-1], res.normal );
res = f.evalSrf( 1,1 );
vecShouldBe( [1,1,0], res.point );
vecShouldBe( [0,0,-1], res.normal );
});
});
describe("verb.core.AdaptiveRefinementNode.triangulate",function(){
function getWarpedSurface(){
var p1 = [0,0,0]
, p2 = [1,0,0]
, p3 = [1,1,1]
, p4 = [0,1,0];
var p1p4 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p1, p4 ));
var p2p3 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p2, p3 ));
var p3p4 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p3, p4 ));
var p1p2 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p1, p2 ));
var p1p4p2p3 = verb.core.Vec.mul( 0.5, verb.core.Vec.add( p1p4, p2p3 ));
var cpts = [ [p1, p1p4, p4],
[p1p2, p1p4p2p3, p3p4],
[p2, p2p3, p3] ];
var wts = [[1,1,1], [1,1,1], [1,1,1]];
cpts = verb.eval.Eval.homogenize2d(cpts, wts);
return {"knotsU": [0,0,0,1,1,1],
"knotsV": [0,0,0,1,1,1],
"controlPoints": cpts,
"degreeU": 2,
"degreeV": 2 };
}
it('can triangulate a square, planar surface with no options defined', function(){
var srf = getFlatSurface();
var f = new verb.core.AdaptiveRefinementNode( srf );
f.divide();
var mesh = f.triangulate();
mesh.faces.should.eql( [ [ 0, 3, 1 ], [ 3, 2, 1 ] ]);
mesh.points.should.eql([ [ 0, 0, 0 ], [ 1, 0, 0 ], [ 1, 1, 0 ], [ 0, 1, 0 ] ]);
mesh.uvs.should.eql([ [ 0, 0 ], [ 1, 0 ], [ 1, 1 ], [ 0, 1 ] ]);
mesh.normals.should.eql( [ [ 0, 0, -1 ], [ 0, 0, -1 ], [ 0, 0, -1 ], [ 0, 0, -1 ] ] );
});
it('can triangulate a warped surface with no options defined', function(){
var srf = getWarpedSurface();
var f = new verb.core.AdaptiveRefinementNode( srf );
f.divide();
var mesh = f.triangulate();
mesh.faces.length.should.be.greaterThan( 4 );
mesh.points.length.should.be.greaterThan( 4 );
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 );
});
it('can triangulate a node with children', function(){
var srf = getFlatSurface();
var f = new verb.core.AdaptiveRefinementNode( srf );
f.divide({ minDepth: 1 });
var mesh = f.triangulate();
mesh.faces.length.should.be.equal( 4 );
mesh.points.length.should.be.greaterThan( 4 );
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 );
});
it('can triangulate a node with children and un-nested neighbors', function(){
var srf = getFlatSurface();
var f = new verb.core.AdaptiveRefinementNode( srf );
f.divide({ minDepth: 1 });
f.children[0].divide({ minDepth: 1 });
var mesh = f.triangulate();
mesh.faces.length.should.be.greaterThan( 4 );
mesh.points.length.should.be.greaterThan( 4 );
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 );
});
it('can triangulate a node with children and equally nested neighbors', function(){
var srf = getFlatSurface();
var f = new verb.core.AdaptiveRefinementNode( srf );
f.divide({ minDepth: 2 });
var mesh = f.triangulate();
mesh.faces.length.should.be.equal( 8 );
mesh.points.length.should.be.greaterThan( 4 );
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 );
});
it('can triangulate a node with children and more nested neighbors', function(){
var srf = getFlatSurface();
var f = new verb.core.AdaptiveRefinementNode( srf );
f.divide({ minDepth: 3 });
var mesh = f.triangulate();
mesh.faces.length.should.be.equal( 16 );
mesh.points.length.should.be.greaterThan( 4 );
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.core.Mat.solve",function(){
it('can solve simple case', function(){
var A = [[1,0.4], [-0.2,1]];
var At = verb.core.Mat.transpose(A);
var b = [5,4];
var x = verb.core.Mat.solve( A, b);
var s = verb.core.Vec.add(
verb.core.Vec.mul( x[0], At[0] ),
verb.core.Vec.mul( x[1], At[1] )
);
vecShouldBe( b, s );
});
function rand1d(n){
var row = [];
for (var j = 0; j < n; j++){
row.push(Math.random());
}
return row;
}
function rand2d(n){
var a = [];
for (var i = 0; i < n; i++){
a.push(rand1d(n));
}
return a;
}
it('can solve complex case', function(){
var n = 5;
var A = rand2d(n);
var At = verb.core.Mat.transpose(A);
var b = rand1d(n);
var x = verb.core.Mat.solve( A, b);
var s = x.reduce(function(acc, v, i){
return verb.core.Vec.add( acc, verb.core.Vec.mul( v, At[i] ) )
}, verb.core.Vec.zeros1d(n) );
vecShouldBe( b, s );
});
});
describe("verb.core.Mesh.makeMeshAabb",function(){
it('should return correct result for planar mesh', function(){
//
// 0 - 1
// | / \
// 2 -- 3
// | \ /
// 4 - 5
//
var points = [ [0,0,0], [1,0,0], [0, -1, 0 ], [2, -1, 0], [0, -2, 0], [1, -2, 0] ]
, tris = [ [0,2,1], [1,2,3], [2,4,5], [2,5,3] ]
, mesh = new verb.core.MeshData(tris, points, null, null)
, tri_indices = [0,1,2,3]
, aabb = verb.core.Mesh.makeMeshAabb(mesh, tri_indices);
should.equal( 2, aabb.max[0] );
should.equal( 0, aabb.min[0] );
should.equal( 0, aabb.max[1] );
should.equal( -2, aabb.min[1] );
should.equal( 0, aabb.max[2] );
should.equal( 0, aabb.min[2] );
});
it('makeMeshAabb should return correct result for non-planar mesh', function(){
//
// 0 - 1
// | / \
// 2 -- 3
// | \ /
// 4 - 5
//
var points = [ [0,0,-5], [1,0,0], [0, -1, 0 ], [2, -1, 0], [0, -2, 0], [1, -2, 4] ]
, tris = [ [0,2,1], [1,2,3], [2,4,5], [2,5,3] ]
, mesh = new verb.core.MeshData(tris, points, null, null)
, tri_indices = [0,1,2,3]
, aabb = verb.core.Mesh.makeMeshAabb(mesh, tri_indices);
should.equal( 2, aabb.max[0] );
should.equal( 0, aabb.min[0] );
should.equal( 0, aabb.max[1] );
should.equal( -2, aabb.min[1] );
should.equal( 4, aabb.max[2] );
should.equal( -5, aabb.min[2] );
});
});
describe("verb.core.Mesh.getTriangleCentroid",function(){
it('should return origin for zeroed triangle', function(){
var points = [[0,0,0],[0,0,0],[0,0,0]]
, tri = [0,1,2]
, centroid = verb.core.Mesh.getTriangleCentroid( points, tri );
should.equal( 0, centroid[0] );
should.equal( 0, centroid[1] );
should.equal( 0, centroid[2] );
});
it('should return correct value', function(){
var points = [[5,10,2],[3,-4,5],[-10,-3, 10]]
, tri = [0,1,2]
, centroid = verb.core.Mesh.getTriangleCentroid( points, tri );
should.equal( -2/3, centroid[0] );
should.equal( 1, centroid[1] );
should.equal( 17/3, centroid[2] );
});
});
describe("verb.eval.Eval.getMinCoordOnAxis",function(){
it('should return correct value', function(){
var points = [[5,10,2],[3,-4,5],[-10,-3, 10]]
, tri = [0,1,2]
, a1 = verb.core.Mesh.getMinCoordOnAxis( points, tri, 0 )
, a2 = verb.core.Mesh.getMinCoordOnAxis( points, tri, 1 )
, a3 = verb.core.Mesh.getMinCoordOnAxis( points, tri, 2 );
should.equal( -10, a1 );
should.equal( -4, a2 );
should.equal( 2, a3 );
});
});
describe("verb.core.Mesh.sortTrianglesOnLongestAxis",function(){
it('should return correct result with y axis regular array', function(){
//
// 0 - 1
// | 0 / 3 \
// 2 -- 3
// | 1 \ 2 /
// 4 - 5
//
var points = [ [0,0,0], [1,-0.2,0], [0, -1, 0 ], [1, -1.2, 0], [0, -2.2, 0], [1, -2, 0]]
, tris = [[0,2,1], [2,4,5], [2,5,3], [1,2,3]]
, mesh = new verb.core.MeshData(tris, points, null, null)
, tri_indices = [0,1,2,3]
, aabb = verb.core.Mesh.makeMeshAabb(mesh, tri_indices)
, sort_tri_indices = verb.core.Mesh.sortTrianglesOnLongestAxis( aabb, mesh, tri_indices );
sort_tri_indices.should.eql([ 1, 2, 3, 0 ])
});
it('should return correct result', function(){
var points = [ [0,10,0], [0,5,0], [0, 0, 0 ], [0, -5, 0], [0, -2, 0], [1, -2.2, 0]]
, tris = [[0,1,4], [2,3,4], [1,2,4]]
, mesh = new verb.core.MeshData(tris, points, null, null)
, tri_indices = [0,1,2]
, aabb = verb.core.Mesh.makeMeshAabb(mesh, tri_indices)
, sort_tri_indices = verb.core.Mesh.sortTrianglesOnLongestAxis( aabb, mesh, tri_indices );
sort_tri_indices.should.eql([ 1, 0, 2 ])
});
});
describe("verb.core.KdTree",function(){
var pts = [
new verb.core.KdPoint( [0,1,1], "a" ),
new verb.core.KdPoint( [0,2,1], "b" ),
new verb.core.KdPoint( [2,2,1], "c" )
];
it('gives correct results when requesting a single node', function(){
var tree = new verb.core.KdTree(pts, verb.core.Vec.distSquared );
var res = tree.nearest( [0,2.1,1], 1, 1.0 );
res[0].item0.point.should.eql(pts[1].point);
});
it('gives correct results for multiple nodes', function(){
var tree = new verb.core.KdTree(pts, verb.core.Vec.distSquared );
var res1 = tree.nearest( [0,1.1,1], 2, 1.0 );
res1[1].item0.point.should.eql(pts[0].point, 1.0);
res1[0].item0.point.should.eql(pts[1].point);
});
});
describe("verb.core.Mesh.triangleUVFromPoint",function(){
it('is correct for a basic example', function(){
var uvs = [ [0,0], [1,0], [1,1] ];
var pts = [ [0,0,0], [1,0,0], [1,1,0] ];
var tris = [[ 0, 1, 2 ]];
var pt = [0.5, 0.25, 0];
var mesh = new verb.core.MeshData(tris, pts, null, uvs);
var uv = verb.core.Mesh.triangleUVFromPoint( mesh, 0, pt );
uv[0].should.be.approximately( pt[0], verb.core.Constants.TOLERANCE );
uv[1].should.be.approximately( pt[1], verb.core.Constants.TOLERANCE );
});
});
describe("verb.core.Vec.sortedSetUnion",function(){
it('can merge two empty arrays', function(){
verb.core.Vec.sortedSetUnion([],[]).should.be.eql([]);
});
it('can merge array and empty array', function(){
verb.core.Vec.sortedSetUnion([],[1,2]).should.be.eql([1,2]);
verb.core.Vec.sortedSetUnion([1.3, 2],[]).should.be.eql([1.3,2]);
});
it('can merge two identical arrays', function(){
verb.core.Vec.sortedSetUnion([1,2],[1,2]).should.be.eql([1,2]);
});
it('can merge two differing arrays', function(){
verb.core.Vec.sortedSetUnion([1,2,3],[1,2,5,6]).should.be.eql([1,2,3,5,6]);
verb.core.Vec.sortedSetUnion([1,3],[1,2,5,6]).should.be.eql([1,2,3,5,6]);
verb.core.Vec.sortedSetUnion([1,27],[1,2,5,6]).should.be.eql([1,2,5,6,27]);
verb.core.Vec.sortedSetUnion([1,1.1,2,5,6,13],[1,2,5,6]).should.be.eql([1,1.1,2,5,6,13]);
});
});
describe("verb.core.Vec.sortedSetSub",function(){
it('can handle two empty arrays', function(){
verb.core.Vec.sortedSetSub([],[]).should.be.eql([]);
});
it('can subtract empty array from non-empty array', function(){
verb.core.Vec.sortedSetSub([1,2],[]).should.be.eql([1,2]);
});
it('can subtract two identical arrays', function(){
verb.core.Vec.sortedSetSub([1,2],[1,2]).should.be.eql([]);
});
it('can subtract two non-equal arrays', function(){
verb.core.Vec.sortedSetSub([1,2],[1]).should.be.eql([2]);
verb.core.Vec.sortedSetSub([1,2,3],[1,3]).should.be.eql([2]);
verb.core.Vec.sortedSetSub([-1,1,2,3],[1,3]).should.be.eql([-1,2]);
verb.core.Vec.sortedSetSub([0,0,0,0,0.5,1,1,1,1],[0,0,0,0,0.5,1,1,1,1]).should.be.eql([]);
});
});
describe("verb.core.Mat.mult",function(){
it('works for a few basic cases', function(){
var mat = [[1,2], [2,3]];
verb.core.Mat.mult( verb.core.Mat.identity(2), mat ).should.eql( mat );
verb.core.Mat.mult( mat, verb.core.Mat.identity(2) ).should.eql( mat );
});
});