diff --git a/Gruntfile.js b/Gruntfile.js index 05dfd54c..2a96feef 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -43,7 +43,8 @@ module.exports = function(grunt) { reporter: 'spec', quiet: false // Optionally suppress output to standard out (defaults to false) }, - src: ['test/testCore.js', 'test/testEval.js', 'test/testGeom.js'] + //src: ['test/testCore.js', 'test/testEval.js', 'test/testGeom.js'] + src: ['test/testEval.js'] } }, diff --git a/benchmark/regularCurveSampling.js b/benchmark/regularCurveSampling.js new file mode 100644 index 00000000..d8d37d75 --- /dev/null +++ b/benchmark/regularCurveSampling.js @@ -0,0 +1,22 @@ +var Benchmark = require('benchmark') + , verb = require('../build/js/verb.js'); + +var crv = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1], [2,1,1], [3,1,0]] ); + +module.exports = { + name: 'Regular curve sampling', + tests: { + 'rationalCurveRegularSample (6560)': function() { + var p = verb.eval.Tess.rationalCurveRegularSample( crv, 6560 ); + }, + 'direct evaluation (6560)': function() { + var p = []; + var sp = 1 / 6560; + + for (var i = 0; i < 6561; i++){ + p.push( verb.eval.Eval.rationalCurvePoint( crv, i*sp ) ) + } + } + } +}; + diff --git a/benchmark/regularSurfaceDerivatives.js b/benchmark/regularSurfaceDerivatives.js new file mode 100644 index 00000000..7f725992 --- /dev/null +++ b/benchmark/regularSurfaceDerivatives.js @@ -0,0 +1,56 @@ +var Benchmark = require('benchmark') + , verb = require('../build/js/verb.js'); + +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; +} + +var complexSurface = getComplexSurface(); + +module.exports = { + name: 'Regular surface derivatives', + tests: { + 'rationalSurfaceRegularSampleDerivatives (80 x 80)': function() { + var ar = verb.eval.Eval.rationalSurfaceRegularSampleDerivatives( complexSurface, 80, 80, 1 ); + }, + 'direct evaluation (80 x 80)': function() { + var ar = []; + var sp = 1 / 80; + + for (var i = 0; i < 81; i++){ + var ari = []; + ar.push(ari); + for (var j = 0; j < 81; j++){ + ari.push( verb.eval.Eval.rationalSurfaceDerivatives( complexSurface, i*sp, j*sp, 1 ) ) + } + } + } + } +}; + diff --git a/benchmark/regularSurfaceSampling.js b/benchmark/regularSurfaceSampling.js new file mode 100644 index 00000000..f24a96c5 --- /dev/null +++ b/benchmark/regularSurfaceSampling.js @@ -0,0 +1,59 @@ +var Benchmark = require('benchmark') + , verb = require('../build/js/verb.js'); + +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; +} + +var complexSurface = getComplexSurface(); + +module.exports = { + name: 'Regular surface sampling', + tests: { + 'surfaceRegularSample2 (80 x 80)': function() { + verb.eval.Tess.surfaceRegularSample2( complexSurface, 80, 80 ); + }, + 'surfaceRegularSample (80 x 80)': function() { + verb.eval.Tess.surfaceRegularSample( complexSurface, 80, 80 ); + }, + 'direct evaluation (80 x 80)': function() { + var ar = []; + var sp = 1 / 80; + + for (var i = 0; i < 81; i++){ + var ari = []; + ar.push(ari); + for (var j = 0; j < 81; j++){ + ari.push( verb.eval.Eval.surfacePoint( complexSurface, i*sp, j*sp ) ) + } + } + } + } +}; + diff --git a/benchmark/surfaceTessellation.js b/benchmark/surfaceTessellation.js new file mode 100644 index 00000000..bb8dbbc6 --- /dev/null +++ b/benchmark/surfaceTessellation.js @@ -0,0 +1,48 @@ +var Benchmark = require('benchmark') + , verb = require('../build/js/verb.js') + , verbOld = require('../build/js/verbOld.js'); + +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; +} + +var surface = getComplexSurface(); + +module.exports = { + name: 'rationalSurfaceAdaptiveSample', + tests: { + 'rationalSurfaceAdaptiveSample (tol 0.2)': function() { + var mesh = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface, 0.1 ); + }, + 'rationalSurfaceAdaptive (default)': function() { + var mesh = verb.eval.Tess.rationalSurfaceAdaptive( surface ); + } + } +}; + diff --git a/benchmark/tessellate.js b/benchmark/tessellate.js deleted file mode 100644 index 74e2fe9f..00000000 --- a/benchmark/tessellate.js +++ /dev/null @@ -1,60 +0,0 @@ -var Benchmark = require('benchmark') - , verb = require('../build/verb.js'); - -// callbacks for tests -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] ]; - - srf = new verb.NurbsSurface( degree, knots, degree, knots, pts, wts ); - - var srfObj = { - degree_u : srf.get('degreeU'), - degree_v : srf.get('degreeV'), - knots_u : srf.get('knotsU'), - knots_v : srf.get('knotsV'), - homo_control_points : srf.homogenize() - }; - - return srfObj; -} - -var srfObj = getComplexSurface(); - -var fdiv = new verb.eval.AdaptiveRefinementNode( srfObj ); -fdiv.divide({ tol: 5e-2 }); - -module.exports = { - name: 'Surface tessellation', - tests: { - 'adaptive (tol: 5e-2)': function() { - var f = new verb.eval.AdaptiveRefinementNode( srfObj ); - f.divide({ tol: 5e-2 }); - var mesh = f.triangulate(); - }, - // 'adaptive - just divide (tol: 5e-2)': function() { - // var f = new verb.eval.AdaptiveRefinementNode( srfObj ); - // f.divide({ tol: 5e-2 }); - // }, - // 'adaptive - just triangulate (tol: 5e-2)': function() { - // f.triangulate(); - // }, - 'uniform (30 x 30)': function() { - mesh = srf.tessellate({ minDivsU: 30, minDivsV: 30 }); - } - } -}; diff --git a/build/js/verb.js b/build/js/verb.js index 44927dc5..ceb504be 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -1942,7 +1942,7 @@ var verb_Verb = function() { }; $hxClasses["verb.Verb"] = verb_Verb; verb_Verb.__name__ = ["verb","Verb"]; verb_Verb.main = function() { - console.log("verb 2.0.0"); + console.log("verb 2.1.0"); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -3476,6 +3476,55 @@ verb_core_Vec.addAll = function(a) { return verb_core_Vec.add(a1,x); },verb_core_Vec.rep(f,0.0)); }; +verb_core_Vec.addAllMutate = function(a) { + var f = a[0]; + var _g1 = 1; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + verb_core_Vec.addMutate(f,a[i]); + } +}; +verb_core_Vec.addMulMutate = function(a,s,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] + s * b[i]; + } +}; +verb_core_Vec.subMulMutate = function(a,s,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] - s * b[i]; + } +}; +verb_core_Vec.addMutate = function(a,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] + b[i]; + } +}; +verb_core_Vec.subMutate = function(a,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] - b[i]; + } +}; +verb_core_Vec.mulMutate = function(a,b) { + var _g1 = 0; + var _g = b.length; + while(_g1 < _g) { + var i = _g1++; + b[i] = b[i] * a; + } +}; verb_core_Vec.norm = function(a) { var norm2 = verb_core_Vec.normSquared(a); if(norm2 != 0.0) return Math.sqrt(norm2); else return norm2; @@ -3750,11 +3799,12 @@ verb_eval_Analyze.rationalCurveClosestParam = function(curve,p) { var _g = pts.length - 1; while(_g1 < _g) { var i1 = _g1++; - var u0 = pts[i1][0]; - var u11 = pts[i1 + 1][0]; - var p0 = pts[i1].slice(1); - var p1 = pts[i1 + 1].slice(1); - var proj = verb_core_Trig.segmentClosestPoint(p,p0,p1,u0,u11); + var u0 = pts[i1].pop(); + var u11 = pts[i1 + 1].pop(); + var p0 = pts[i1]; + var p01 = pts[i1]; + var p1 = pts[i1 + 1]; + var proj = verb_core_Trig.segmentClosestPoint(p,p01,p1,u0,u11); var d1 = verb_core_Vec.norm(verb_core_Vec.sub(p,proj.pt)); if(d1 < min) { min = d1; @@ -4083,23 +4133,24 @@ verb_eval_Eval.rationalSurfaceDerivatives = function(surface,u,v,numDerivs) { var _g4 = l + 1; while(_g5 < _g4) { var j = _g5++; - v1 = verb_core_Vec.sub(v1,verb_core_Vec.mul(verb_core_Binomial.get(l,j) * wders[0][j],SKL[k][l - j])); + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(l,j) * wders[0][j],SKL[k][l - j]); } var _g51 = 1; var _g41 = k + 1; while(_g51 < _g41) { var i = _g51++; - v1 = verb_core_Vec.sub(v1,verb_core_Vec.mul(verb_core_Binomial.get(k,i) * wders[i][0],SKL[k - i][l])); + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(k,i) * wders[i][0],SKL[k - i][l]); var v2 = verb_core_Vec.zeros1d(dim); var _g7 = 1; var _g6 = l + 1; while(_g7 < _g6) { var j1 = _g7++; - v2 = verb_core_Vec.add(v2,verb_core_Vec.mul(verb_core_Binomial.get(l,j1) * wders[i][j1],SKL[k - i][l - j1])); + verb_core_Vec.addMulMutate(v2,verb_core_Binomial.get(l,j1) * wders[i][j1],SKL[k - i][l - j1]); } - v1 = verb_core_Vec.sub(v1,verb_core_Vec.mul(verb_core_Binomial.get(k,i),v2)); + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(k,i),v2); } - SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],v1)); + verb_core_Vec.mulMutate(1 / wders[0][0],v1); + SKL[k].push(v1); } } return SKL; @@ -4124,9 +4175,10 @@ verb_eval_Eval.rationalCurveDerivatives = function(curve,u,numDerivs) { var _g2 = k1 + 1; while(_g3 < _g2) { var i1 = _g3++; - v = verb_core_Vec.sub(v,verb_core_Vec.mul(verb_core_Binomial.get(k1,i1) * wders[i1],CK[k1 - i1])); + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k1,i1) * wders[i1],CK[k1 - i1]); } - CK.push(verb_core_Vec.mul(1 / wders[0],v)); + verb_core_Vec.mulMutate(1 / wders[0],v); + CK.push(v); } return CK; }; @@ -4150,7 +4202,7 @@ verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { if(numDerivs < degreeU) du = numDerivs; else du = degreeU; var dv; if(numDerivs < degreeV) dv = numDerivs; else dv = degreeV; - var SKL = verb_core_Vec.zeros3d(numDerivs + 1,numDerivs + 1,dim); + var SKL = verb_core_Vec.zeros3d(du + 1,dv + 1,dim); var knotSpan_index_u = verb_eval_Eval.knotSpanGivenN(n,degreeU,u,knotsU); var knotSpan_index_v = verb_eval_Eval.knotSpanGivenN(m,degreeV,v,knotsV); var uders = verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index_u,u,degreeU,n,knotsU); @@ -4170,7 +4222,7 @@ verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { var _g4 = degreeU + 1; while(_g5 < _g4) { var r = _g5++; - temp[s] = verb_core_Vec.add(temp[s],verb_core_Vec.mul(uders[k][r],controlPoints[knotSpan_index_u - degreeU + r][knotSpan_index_v - degreeV + s])); + verb_core_Vec.addMulMutate(temp[s],uders[k][r],controlPoints[knotSpan_index_u - degreeU + r][knotSpan_index_v - degreeV + s]); } } var nk = numDerivs - k; @@ -4184,7 +4236,7 @@ verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { var _g41 = degreeV + 1; while(_g51 < _g41) { var s1 = _g51++; - SKL[k][l] = verb_core_Vec.add(SKL[k][l],verb_core_Vec.mul(vders[l][s1],temp[s1])); + verb_core_Vec.addMulMutate(SKL[k][l],vders[l][s1],temp[s1]); } } } @@ -4221,12 +4273,199 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { var _g2 = degreeU + 1; while(_g3 < _g2) { var k = _g3++; - temp = verb_core_Vec.add(temp,verb_core_Vec.mul(u_basis_vals[k],controlPoints[uind + k][vind])); + verb_core_Vec.addMulMutate(temp,u_basis_vals[k],controlPoints[uind + k][vind]); } - position = verb_core_Vec.add(position,verb_core_Vec.mul(v_basis_vals[l],temp)); + verb_core_Vec.addMulMutate(position,v_basis_vals[l],temp); } return position; }; +verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { + var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); + var allratders = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var numDerivs1 = numDerivs + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var rowders = []; + allratders.push(rowders); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + var ders = allders[i][j]; + var Aders = verb_eval_Eval.rational2d(ders); + var wders = verb_eval_Eval.weight2d(ders); + var SKL = []; + var dim = Aders[0][0].length; + var _g2 = 0; + while(_g2 < numDerivs1) { + var k = _g2++; + SKL.push([]); + var _g4 = 0; + var _g3 = numDerivs1 - k; + while(_g4 < _g3) { + var l = _g4++; + var v = Aders[k][l]; + var _g6 = 1; + var _g5 = l + 1; + while(_g6 < _g5) { + var j1 = _g6++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(l,j1) * wders[0][j1],SKL[k][l - j1]); + } + var _g61 = 1; + var _g51 = k + 1; + while(_g61 < _g51) { + var i1 = _g61++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1) * wders[i1][0],SKL[k - i1][l]); + var v2 = verb_core_Vec.zeros1d(dim); + var _g8 = 1; + var _g7 = l + 1; + while(_g8 < _g7) { + var j2 = _g8++; + verb_core_Vec.addMulMutate(v2,verb_core_Binomial.get(l,j2) * wders[i1][j2],SKL[k - i1][l - j2]); + } + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1),v2); + } + verb_core_Vec.mulMutate(1 / wders[0][0],v); + SKL[k].push(v); + } + } + rowders.push(SKL); + } + } + return allratders; +}; +verb_eval_Eval.surfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var dim = controlPoints[0][0].length; + var spanU = (verb_core_ArrayExtensions.last(knotsU) - knotsU[0]) / divsU; + var spanV = (verb_core_ArrayExtensions.last(knotsV) - knotsV[0]) / divsV; + var knotSpansBasesU = verb_eval_Eval.regularlySpacedDerivativeBasisFunctions(degreeU,knotsU,divsU); + var knotSpansU = knotSpansBasesU.item0; + var basesU = knotSpansBasesU.item1; + var knotSpansBasesV = verb_eval_Eval.regularlySpacedDerivativeBasisFunctions(degreeV,knotsV,divsV); + var knotSpansV = knotSpansBasesV.item0; + var basesV = knotSpansBasesV.item1; + var pts = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var ptsi = []; + pts.push(ptsi); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + ptsi.push(verb_eval_Eval.surfaceDerivativesGivenBasesKnotSpans(degreeU,degreeV,controlPoints,knotSpansU[i],knotSpansV[j],basesU[i],basesV[j],dim,numDerivs)); + } + } + return pts; +}; +verb_eval_Eval.regularlySpacedBasisFunctions = function(degree,knots,divs) { + var n = knots.length - degree - 2; + var span = (verb_core_ArrayExtensions.last(knots) - knots[0]) / divs; + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var div1 = divs + 1; + var _g = 0; + while(_g < div1) { + var i = _g++; + while(u >= knots[knotIndex + 1]) knotIndex++; + knotspans.push(knotIndex); + bases.push(verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotIndex,u,degree,knots)); + u += span; + } + return new verb_core_Pair(knotspans,bases); +}; +verb_eval_Eval.regularlySpacedDerivativeBasisFunctions = function(degree,knots,divs) { + var n = knots.length - degree - 2; + var span = (verb_core_ArrayExtensions.last(knots) - knots[0]) / divs; + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var div1 = divs + 1; + var _g = 0; + while(_g < div1) { + var i = _g++; + while(u >= knots[knotIndex + 1]) knotIndex++; + knotspans.push(knotIndex); + bases.push(verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotIndex,u,degree,n,knots)); + u += span; + } + return new verb_core_Pair(knotspans,bases); +}; +verb_eval_Eval.surfacePointGivenBasesKnotSpans = function(degreeU,degreeV,controlPoints,knotSpanU,knotSpanV,basesU,basesV,dim) { + var position = verb_core_Vec.zeros1d(dim); + var temp; + var uind = knotSpanU - degreeU; + var vind = knotSpanV - degreeV; + var _g1 = 0; + var _g = degreeV + 1; + while(_g1 < _g) { + var l = _g1++; + temp = verb_core_Vec.zeros1d(dim); + var _g3 = 0; + var _g2 = degreeU + 1; + while(_g3 < _g2) { + var k = _g3++; + verb_core_Vec.addMulMutate(temp,basesU[k],controlPoints[uind + k][vind]); + } + vind++; + verb_core_Vec.addMulMutate(position,basesV[l],temp); + } + return position; +}; +verb_eval_Eval.surfaceDerivativesGivenBasesKnotSpans = function(degreeU,degreeV,controlPoints,knotSpanU,knotSpanV,basesU,basesV,dim,numDerivs) { + var dim1 = controlPoints[0][0].length; + var du; + if(numDerivs < degreeU) du = numDerivs; else du = degreeU; + var dv; + if(numDerivs < degreeV) dv = numDerivs; else dv = degreeV; + var SKL = verb_core_Vec.zeros3d(du + 1,dv + 1,dim1); + var temp = verb_core_Vec.zeros2d(degreeV + 1,dim1); + var dd = 0; + var _g1 = 0; + var _g = du + 1; + while(_g1 < _g) { + var k = _g1++; + var _g3 = 0; + var _g2 = degreeV + 1; + while(_g3 < _g2) { + var s = _g3++; + temp[s] = verb_core_Vec.zeros1d(dim1); + var _g5 = 0; + var _g4 = degreeU + 1; + while(_g5 < _g4) { + var r = _g5++; + verb_core_Vec.addMulMutate(temp[s],basesU[k][r],controlPoints[knotSpanU - degreeU + r][knotSpanV - degreeV + s]); + } + } + var nk = numDerivs - k; + if(nk < dv) dd = nk; else dd = dv; + var _g31 = 0; + var _g21 = dd + 1; + while(_g31 < _g21) { + var l = _g31++; + SKL[k][l] = verb_core_Vec.zeros1d(dim1); + var _g51 = 0; + var _g41 = degreeV + 1; + while(_g51 < _g41) { + var s1 = _g51++; + verb_core_Vec.addMulMutate(SKL[k][l],basesV[l][s1],temp[s1]); + } + } + } + return SKL; +}; verb_eval_Eval.curveDerivatives = function(crv,u,numDerivs) { var n = crv.knots.length - crv.degree - 2; return verb_eval_Eval.curveDerivativesGivenN(n,crv,u,numDerivs); @@ -4252,7 +4491,7 @@ verb_eval_Eval.curveDerivativesGivenN = function(n,curve,u,numDerivs) { var _g2 = degree + 1; while(_g3 < _g2) { var j1 = _g3++; - CK[k1] = verb_core_Vec.add(CK[k1],verb_core_Vec.mul(nders[k1][j1],controlPoints[knotSpan_index - degree + j1])); + verb_core_Vec.addMulMutate(CK[k1],nders[k1][j1],controlPoints[knotSpan_index - degree + j1]); } } return CK; @@ -4279,7 +4518,7 @@ verb_eval_Eval.curvePointGivenN = function(n,curve,u) { var _g = degree + 1; while(_g1 < _g) { var j = _g1++; - position = verb_core_Vec.add(position,verb_core_Vec.mul(basis_values[j],controlPoints[knotSpan_index - degree + j])); + verb_core_Vec.addMulMutate(position,basis_values[j],controlPoints[knotSpan_index - degree + j]); } return position; }; @@ -4325,11 +4564,11 @@ verb_eval_Eval.volumePointGivenNML = function(volume,n,m,l,u,v,w) { var _g4 = degreeU + 1; while(_g5 < _g4) { var k = _g5++; - temp = verb_core_Vec.add(temp,verb_core_Vec.mul(u_basis_vals[k],controlPoints[uind + k][vind][wind])); + verb_core_Vec.addMulMutate(temp,u_basis_vals[k],controlPoints[uind + k][vind][wind]); } - temp2 = verb_core_Vec.add(temp2,verb_core_Vec.mul(v_basis_vals[j],temp)); + verb_core_Vec.addMulMutate(temp2,v_basis_vals[j],temp); } - position = verb_core_Vec.add(position,verb_core_Vec.mul(w_basis_vals[i],temp2)); + verb_core_Vec.addMulMutate(position,w_basis_vals[i],temp2); } return position; }; @@ -4339,7 +4578,7 @@ verb_eval_Eval.derivativeBasisFunctions = function(u,degree,knots) { var n = m - degree - 1; return verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index,u,degree,n,knots); }; -verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotSpan_index,u,p,n,knots) { +verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotIndex,u,p,n,knots) { var ndu = verb_core_Vec.zeros2d(p + 1,p + 1); var left = verb_core_Vec.zeros1d(p + 1); var right = verb_core_Vec.zeros1d(p + 1); @@ -4350,8 +4589,8 @@ verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotSpan_index,u,p,n,k var _g = p + 1; while(_g1 < _g) { var j = _g1++; - left[j] = u - knots[knotSpan_index + 1 - j]; - right[j] = knots[knotSpan_index + j] - u; + left[j] = u - knots[knotIndex + 1 - j]; + right[j] = knots[knotIndex + j] - u; saved = 0.0; var _g2 = 0; while(_g2 < j) { @@ -5189,6 +5428,25 @@ verb_eval_Make.clonedCurve = function(curve) { return x.slice(); })); }; +verb_eval_Make.clonedSurface = function(surface) { + var newpts = []; + var newrow; + var _g = 0; + var _g1 = surface.controlPoints; + while(_g < _g1.length) { + var row = _g1[_g]; + ++_g; + newrow = []; + newpts.push(newrow); + var _g2 = 0; + while(_g2 < row.length) { + var pt = row[_g2]; + ++_g2; + newrow.push(pt.slice()); + } + } + return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),surface.knotsV.slice(),newpts); +}; verb_eval_Make.rationalBezierCurve = function(controlPoints,weights) { var degree = controlPoints.length - 1; var knots = []; @@ -5868,32 +6126,205 @@ verb_eval_Modify.rationalCurveTransform = function(curve,mat) { return new verb_core_NurbsCurveData(curve.degree,curve.knots.slice(),verb_eval_Eval.homogenize1d(pts,verb_eval_Eval.weight1d(curve.controlPoints))); }; verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { - var newPts = []; - var knots; + if(knotsToInsert.length == 0) return verb_eval_Make.clonedSurface(surface); var degree; - var ctrlPts; - if(!useV) { - ctrlPts = verb_core_Mat.transpose(surface.controlPoints); - knots = surface.knotsU; + var controlPoints = surface.controlPoints; + var knots; + if(useV) { + degree = surface.degreeV; + knots = surface.knotsV; + } else { degree = surface.degreeU; + knots = surface.knotsU; + } + var n; + if(useV) n = controlPoints[0].length - 1; else n = controlPoints.length - 1; + var m = n + degree + 1; + var r = knotsToInsert.length - 1; + var a = verb_eval_Eval.knotSpan(degree,knotsToInsert[0],knots); + var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); + var controlPoints_post = []; + var knots_post = []; + if(useV) { + var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); + var _g1 = 0; + var _g = controlPoints.length + km.length - 1; + while(_g1 < _g) { + var i1 = _g1++; + controlPoints_post.push([]); + } + var _g11 = 0; + var _g2 = a - degree + 1; + while(_g11 < _g2) { + var i2 = _g11++; + var _g3 = 0; + var _g21 = controlPoints.length; + while(_g3 < _g21) { + var j1 = _g3++; + controlPoints_post[j1][i2] = controlPoints[j1][i2]; + } + } + var _g12 = b - 1; + var _g4 = n + 1; + while(_g12 < _g4) { + var i3 = _g12++; + var l = i3 + r + 1; + var _g31 = 0; + var _g22 = controlPoints.length; + while(_g31 < _g22) { + var j2 = _g31++; + controlPoints_post[j2][l] = controlPoints[j2][i3]; + } + } } else { - ctrlPts = surface.controlPoints; - knots = surface.knotsV; - degree = surface.degreeV; + var _g13 = 0; + var _g5 = a - degree + 1; + while(_g13 < _g5) { + var i4 = _g13++; + controlPoints_post[i4] = controlPoints[i4].slice(0); + } + var _g14 = b - 1; + var _g6 = n + 1; + while(_g14 < _g6) { + var i5 = _g14++; + controlPoints_post[i5 + r + 1] = controlPoints[i5].slice(0); + } } - var c = null; + var _g15 = 0; + var _g7 = a + 1; + while(_g15 < _g7) { + var i6 = _g15++; + knots_post[i6] = knots[i6]; + } + var _g16 = b + degree; + var _g8 = m + 1; + while(_g16 < _g8) { + var i7 = _g16++; + knots_post[i7 + r + 1] = knots[i7]; + } + var i = b + degree - 1; + var k = b + degree + r; + var j = r; + var ci; + while(j >= 0) { + while(knotsToInsert[j] <= knots[i] && i > a) { + var wi = k - degree - 1; + var xi = i - degree - 1; + if(useV) { + var _g17 = 0; + var _g9 = controlPoints_post.length; + while(_g17 < _g9) { + var ci1 = _g17++; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi].slice(0); + } + } else controlPoints_post[wi] = controlPoints[xi].slice(0); + knots_post[k] = knots[i]; + k = k - 1; + i = i - 1; + } + if(useV) { + var _g18 = 0; + var _g10 = controlPoints_post.length; + while(_g18 < _g10) { + var ci2 = _g18++; + controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree].slice(0); + } + } else controlPoints_post[k - degree - 1] = controlPoints_post[k - degree].slice(0); + var _g19 = 1; + var _g20 = degree + 1; + while(_g19 < _g20) { + var l1 = _g19++; + var ind = k - degree + l1; + var alfa = knots_post[k + l1] - knotsToInsert[j]; + if(Math.abs(alfa) < verb_core_Constants.EPSILON) { + if(useV) { + var _g32 = 0; + var _g23 = controlPoints_post.length; + while(_g32 < _g23) { + var ci3 = _g32++; + controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; + } + } else controlPoints_post[ind - 1] = controlPoints_post[ind].slice(0); + } else { + alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); + if(useV) { + var _g33 = 0; + var _g24 = controlPoints_post.length; + while(_g33 < _g24) { + var wi1 = _g33++; + controlPoints_post[wi1][ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[wi1][ind - 1],controlPoints_post[wi1][ind]); + } + } else { + var _g34 = 0; + var _g25 = controlPoints_post[ind].length; + while(_g34 < _g25) { + var wi2 = _g34++; + controlPoints_post[ind - 1][wi2] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1][wi2],controlPoints_post[ind][wi2]); + } + } + } + } + knots_post[k] = knotsToInsert[j]; + k = k - 1; + j--; + } + if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),knots_post,controlPoints_post); else return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,knots_post,surface.knotsV.slice(),controlPoints_post); +}; +verb_eval_Modify.decomposeSurfaceIntoBeziers = function(surface) { + var knotmultsU = verb_eval_Analyze.knotMultiplicities(surface.knotsU); + var reqMultU = surface.degreeU + 1; var _g = 0; - while(_g < ctrlPts.length) { - var cptrow = ctrlPts[_g]; + while(_g < knotmultsU.length) { + var knotmult = knotmultsU[_g]; ++_g; - c = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,cptrow),knotsToInsert); - newPts.push(c.controlPoints); + if(knotmult.mult < reqMultU) { + var knotsInsert = verb_core_Vec.rep(reqMultU - knotmult.mult,knotmult.knot); + if(knotsInsert.length == 0) continue; + surface = verb_eval_Modify.surfaceKnotRefine(surface,knotsInsert,false); + } } - var newknots = c.knots; - if(!useV) { - newPts = verb_core_Mat.transpose(newPts); - return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,newknots,surface.knotsV.slice(),newPts); - } else return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),newknots,newPts); + var knotmultsV = verb_eval_Analyze.knotMultiplicities(surface.knotsV); + var reqMultV = surface.degreeV + 1; + var _g1 = 0; + while(_g1 < knotmultsV.length) { + var knotmult1 = knotmultsV[_g1]; + ++_g1; + if(knotmult1.mult < reqMultV) { + var knotsInsert1 = verb_core_Vec.rep(reqMultV - knotmult1.mult,knotmult1.knot); + if(knotsInsert1.length == 0) continue; + surface = verb_eval_Modify.surfaceKnotRefine(surface,knotsInsert1,true); + } + } + var numU = surface.knotsU.length / reqMultU - 1; + var numV = surface.knotsV.length / reqMultV - 1; + var knotLengthU = reqMultU * 2; + var knotLengthV = reqMultV * 2; + var subSurfaces = []; + var i = 0; + while(i < surface.controlPoints.length) { + var row = []; + subSurfaces.push(row); + var ktsU = surface.knotsU.slice(i,i + knotLengthU); + var j = 0; + while(j < surface.controlPoints[i].length) { + var ktsV = surface.knotsV.slice(j,j + knotLengthV); + var pts = verb_eval_Modify.submatrix(surface.controlPoints,i,j,reqMultV,reqMultU); + row.push(new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,ktsU,ktsV,pts)); + j += reqMultV; + } + i += reqMultU; + } + return subSurfaces; +}; +verb_eval_Modify.submatrix = function(mat,startRow,startCol,rows,cols) { + var newmat = []; + var _g1 = startRow; + var _g = startRow + rows; + while(_g1 < _g) { + var i = _g1++; + newmat.push(mat[i].slice(startCol,startCol + cols)); + } + return newmat; }; verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { var degree = curve.degree; @@ -5907,6 +6338,7 @@ verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { ++_g; if(knotmult.mult < reqMult) { var knotsInsert = verb_core_Vec.rep(reqMult - knotmult.mult,knotmult.knot); + if(knotsInsert.length == 0) continue; var res = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,controlPoints),knotsInsert); knots = res.knots; controlPoints = res.controlPoints; @@ -5979,7 +6411,7 @@ verb_eval_Modify.curveKnotRefine = function(curve,knotsToInsert) { var alfa = knots_post[k + l] - knotsToInsert[j]; if(Math.abs(alfa) < verb_core_Constants.EPSILON) controlPoints_post[ind - 1] = controlPoints_post[ind]; else { alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); - controlPoints_post[ind - 1] = verb_core_Vec.add(verb_core_Vec.mul(alfa,controlPoints_post[ind - 1]),verb_core_Vec.mul(1.0 - alfa,controlPoints_post[ind])); + controlPoints_post[ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1],controlPoints_post[ind]); } } knots_post[k] = knotsToInsert[j]; @@ -6047,7 +6479,7 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { while(_g31 < _g21) { var i7 = _g31++; alpha = (u - knots[L + i7]) / (knots[i7 + k + 1] - knots[L + i7]); - controlPoints_temp[i7] = verb_core_Vec.add(verb_core_Vec.mul(alpha,controlPoints_temp[i7 + 1]),verb_core_Vec.mul(1.0 - alpha,controlPoints_temp[i7])); + controlPoints_temp[i7] = verb_core_Vec.add(verb_core_Vec.mul(1.0 - alpha,controlPoints_temp[i7]),verb_core_Vec.mul(alpha,controlPoints_temp[i7 + 1])); } controlPoints_post[L] = controlPoints_temp[0]; controlPoints_post[k + r - j - s] = controlPoints_temp[degree - j - s]; @@ -6060,56 +6492,629 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { } return new verb_core_NurbsCurveData(degree,knots_post,controlPoints_post); }; +var verb_eval_NewMeshData = function() { }; +$hxClasses["verb.eval.NewMeshData"] = verb_eval_NewMeshData; +verb_eval_NewMeshData.__name__ = ["verb","eval","NewMeshData"]; +verb_eval_NewMeshData.prototype = { + __class__: verb_eval_NewMeshData +}; +var verb_eval_BezierEdgeIndices = function() { +}; +$hxClasses["verb.eval.BezierEdgeIndices"] = verb_eval_BezierEdgeIndices; +verb_eval_BezierEdgeIndices.__name__ = ["verb","eval","BezierEdgeIndices"]; +verb_eval_BezierEdgeIndices.prototype = { + __class__: verb_eval_BezierEdgeIndices +}; +var verb_eval_EdgeSide = $hxClasses["verb.eval.EdgeSide"] = { __ename__ : ["verb","eval","EdgeSide"], __constructs__ : ["North","South","East","West"] }; +verb_eval_EdgeSide.North = ["North",0]; +verb_eval_EdgeSide.North.toString = $estr; +verb_eval_EdgeSide.North.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.South = ["South",1]; +verb_eval_EdgeSide.South.toString = $estr; +verb_eval_EdgeSide.South.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.East = ["East",2]; +verb_eval_EdgeSide.East.toString = $estr; +verb_eval_EdgeSide.East.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.West = ["West",3]; +verb_eval_EdgeSide.West.toString = $estr; +verb_eval_EdgeSide.West.__enum__ = verb_eval_EdgeSide; var verb_eval_Tess = $hx_exports.eval.Tess = function() { }; $hxClasses["verb.eval.Tess"] = verb_eval_Tess; verb_eval_Tess.__name__ = ["verb","eval","Tess"]; -verb_eval_Tess.rationalCurveRegularSample = function(curve,numSamples,includeU) { - return verb_eval_Tess.rationalCurveRegularSampleRange(curve,curve.knots[0],verb_core_ArrayExtensions.last(curve.knots),numSamples,includeU); -}; -verb_eval_Tess.rationalCurveRegularSampleRange = function(curve,start,end,numSamples,includeU) { - if(numSamples < 1) numSamples = 2; - var p = []; - var span = (end - start) / (numSamples - 1); - var u = 0; +verb_eval_Tess.rationalBezierSurfaceRegularSample = function(surface,divsU,divsV) { + var pts = []; + var u = surface.knotsU[0]; + var t = (verb_core_ArrayExtensions.last(surface.knotsU) - surface.knotsU[0]) / divsU; var _g = 0; - while(_g < numSamples) { + while(_g < divsU) { var i = _g++; - u = start + span * i; - if(includeU) p.push([u].concat(verb_eval_Eval.rationalCurvePoint(curve,u))); else p.push(verb_eval_Eval.rationalCurvePoint(curve,u)); + var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); + var v = (verb_core_ArrayExtensions.last(iso.knots) - iso.knots[0]) / divsV; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(iso,pts,iso.knots[0],t,divsV,false); + u += t; + } + return pts; +}; +verb_eval_Tess.northIndex = function(i,j,divs) { + if(i <= 0) return null; + return divs[i - 1][j]; +}; +verb_eval_Tess.southIndex = function(i,j,divs) { + if(i >= divs.length - 1) return null; + return divs[i + 1][j]; +}; +verb_eval_Tess.eastIndex = function(i,j,divs) { + if(j >= divs[i].length - 1) return null; + return divs[i][j + 1]; +}; +verb_eval_Tess.westIndex = function(i,j,divs) { + if(j <= 0) return null; + return divs[i][j - 1]; +}; +verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { + var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); + var stepLengths = []; + var stepLengthRow; + var _g = 0; + while(_g < beziers.length) { + var bezierrow = beziers[_g]; + ++_g; + stepLengthRow = []; + stepLengths.push(stepLengthRow); + var _g1 = 0; + while(_g1 < bezierrow.length) { + var bezier = bezierrow[_g1]; + ++_g1; + var ls = verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol); + ls.item0 = Math.min(ls.item0,(verb_core_ArrayExtensions.last(bezier.knotsU) - verb_core_ArrayExtensions.first(bezier.knotsU)) / 2); + ls.item1 = Math.min(ls.item1,(verb_core_ArrayExtensions.last(bezier.knotsV) - verb_core_ArrayExtensions.first(bezier.knotsV)) / 2); + stepLengthRow.push(ls); + } + } + var pts = []; + var uvs = []; + var edgeRow; + var n; + var s; + var e; + var w; + var empty = new verb_core_Pair(Infinity,Infinity); + var beis = []; + var beir; + var bei; + var e0; + var e1; + var srf; + var _g11 = 0; + var _g2 = beziers.length; + while(_g11 < _g2) { + var i = _g11++; + beir = []; + beis.push(beir); + var _g3 = 0; + var _g21 = beziers[i].length; + while(_g3 < _g21) { + var j = _g3++; + srf = beziers[i][j]; + bei = new verb_eval_BezierEdgeIndices(); + beir.push(bei); + s = verb_eval_Tess.southIndex(i,j,stepLengths); + if(s == null) s = empty; + e = verb_eval_Tess.eastIndex(i,j,stepLengths); + if(e == null) e = empty; + if(i == 0) { + var ne = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.first(srf.knotsU),false); + e0 = pts.length; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(ne,pts,stepLengths[i][j].item1); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(ne.knots),stepLengths[i][j].item1,uvs,verb_core_ArrayExtensions.first(srf.knotsU),true); + bei.n = new verb_core_Pair(e0,e1); + } else bei.n = beis[i - 1][j].s; + if(j == 0) { + e0 = pts.length; + var we = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.first(srf.knotsV),true); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(we,pts,stepLengths[i][j].item0); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(we.knots),stepLengths[i][j].item0,uvs,verb_core_ArrayExtensions.first(srf.knotsV),false); + bei.w = new verb_core_Pair(e0,e1); + } else bei.w = beis[i][j - 1].e; + e0 = pts.length; + var se = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.last(srf.knotsU),false); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(se,pts,Math.min(s.item1,stepLengths[i][j].item1)); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(se.knots),Math.min(s.item1,stepLengths[i][j].item1),uvs,verb_core_ArrayExtensions.last(srf.knotsU),true); + bei.s = new verb_core_Pair(e0,e1); + e0 = pts.length; + var ee = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.last(srf.knotsV),true); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(ee,pts,Math.min(e.item0,stepLengths[i][j].item0)); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(ee.knots),Math.min(e.item0,stepLengths[i][j].item0),uvs,verb_core_ArrayExtensions.last(srf.knotsV),false); + bei.e = new verb_core_Pair(e0,e1); + } + } + var faces = []; + var p0; + var _g12 = 0; + var _g4 = beziers.length; + while(_g12 < _g4) { + var i1 = _g12++; + var _g31 = 0; + var _g22 = beziers[i1].length; + while(_g31 < _g22) { + var j1 = _g31++; + p0 = pts.length; + var bezier1 = beziers[i1][j1]; + var divsU = Math.ceil(1.0 / stepLengths[i1][j1].item0); + var domainV = verb_core_ArrayExtensions.last(bezier1.knotsV) - bezier1.knotsV[0]; + var domainU = verb_core_ArrayExtensions.last(bezier1.knotsU) - bezier1.knotsU[0]; + var divsV = Math.ceil(1.0 / stepLengths[i1][j1].item1); + var tessStepV = domainV / divsV; + var tessStepU = domainU / divsU; + var u = bezier1.knotsU[0] + tessStepU; + var _g5 = 0; + var _g41 = divsU - 1; + while(_g5 < _g41) { + var k = _g5++; + var iso = verb_eval_Make.surfaceIsocurve(bezier1,u,false); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(iso,pts,iso.knots[0] + tessStepV,tessStepV,divsV - 1,false); + verb_eval_Tess.regularUvsMutate(divsV - 1,iso.knots[0] + tessStepV,tessStepV,uvs,u,true); + u += tessStepU; + } + divsU = divsU - 2; + divsV = divsV - 2; + var _g42 = 0; + while(_g42 < divsU) { + var k1 = _g42++; + var _g51 = 0; + while(_g51 < divsV) { + var l = _g51++; + var a_k = p0 + k1 * (divsV + 1) + l; + var b_k = p0 + (k1 + 1) * (divsV + 1) + l; + var c_k = b_k + 1; + var d_k = a_k + 1; + var abc = [a_k,b_k,c_k]; + var acd = [a_k,c_k,d_k]; + faces.push(abc); + faces.push(acd); + } + } + bei = beis[i1][j1]; + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainV,p0,tessStepV,verb_eval_EdgeSide.North); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainV,p0,tessStepV,verb_eval_EdgeSide.South); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.East); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.West); + } + } + return new verb_core_MeshData(faces,pts,null,uvs); +}; +verb_eval_Tess.regularUvsMutate = function(count,start,step,uvs,constant,uConstant) { + var i = 0; + var u = start; + if(uConstant) while(i < count) { + uvs.push([constant,u]); + u += step; + i++; + } else while(i < count) { + uvs.push([u,constant]); + u += step; + i++; } - return p; }; -verb_eval_Tess.rationalCurveAdaptiveSample = function(curve,tol,includeU) { +verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tessStep,edgeSide) { + var edgeIndices; + var knots; + var reverseFace = false; + var tessIStep = 1; + var tessDivCount = 1; + switch(edgeSide[1]) { + case 0: + edgeIndices = bei.n; + knots = bezier.knotsV; + tessDivCount = divsV; + break; + case 1: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV + 1); + reverseFace = true; + tessDivCount = divsV; + break; + case 2: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV + 1; + p0 += divsV; + tessDivCount = divsU; + break; + case 3: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV + 1; + reverseFace = true; + tessDivCount = divsU; + break; + } + var edgeCount = edgeIndices.item1 - edgeIndices.item0 - 1; + var edgeStep = domain / edgeCount; + var edgeU = verb_core_ArrayExtensions.first(knots); + var tessU = verb_core_ArrayExtensions.first(knots) + 1.5 * tessStep; + var edgeI = 0; + var tessI = 0; + var tessDivI = 1; + while(edgeI < edgeCount) { + while(edgeU < tessU && edgeI < edgeCount || edgeI < edgeCount && tessDivI > tessDivCount) { + var ei = edgeIndices.item0 + edgeI; + var ei2 = ei + 1; + if(reverseFace) faces.push([ei,ei2,p0 + tessI]); else faces.push([ei,p0 + tessI,ei2]); + edgeI++; + edgeU += edgeStep; + } + if(edgeI < edgeCount) { + var ei1 = edgeIndices.item0 + edgeI; + if(reverseFace) faces.push([p0 + tessI,ei1,p0 + tessI + tessIStep]); else faces.push([p0 + tessI,p0 + tessI + tessIStep,ei1]); + } + tessDivI++; + tessI += tessIStep; + tessU += tessStep; + } +}; +verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2 = function(crv,pts,step,includeU) { if(includeU == null) includeU = false; - if(tol == null) tol = 1e-6; - if(curve.degree == 1) { - if(!includeU) return curve.controlPoints.map(verb_eval_Eval.dehomogenize); else { - var _g = []; - var _g2 = 0; - var _g1 = curve.controlPoints.length; - while(_g2 < _g1) { - var i = _g2++; - _g.push([curve.knots[i + 1]].concat(verb_eval_Eval.dehomogenize(curve.controlPoints[i]))); + var domain = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var steps = Math.ceil(1.0 / step); + var len = domain / steps; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(crv,pts,crv.knots[0],len,steps + 1,false); +}; +verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { + var dehomo = verb_eval_Eval.dehomogenize2d(surface.controlPoints); + var bb = new verb_core_BoundingBox(); + var _g = 0; + while(_g < dehomo.length) { + var row = dehomo[_g]; + ++_g; + bb.addRange(row); + } + var avgPt = verb_core_Vec.mul(0.5,verb_core_Vec.add(bb.min,bb.max)); + var m = verb_core_Mat.identity(4); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + var ts = verb_eval_Modify.rationalSurfaceTransform(surface,m); + dehomo = verb_eval_Eval.dehomogenize2d(ts.controlPoints); + var r = 0.0; + var n; + var _g1 = 0; + var _g2 = dehomo.length; + while(_g1 < _g2) { + var i = _g1++; + var _g3 = 0; + var _g21 = dehomo[i].length; + while(_g3 < _g21) { + var j = _g3++; + n = verb_core_Vec.norm(dehomo[i][j]); + if(n > r) r = n; + } + } + var duu = -Infinity; + var iduu; + var _g11 = 0; + var _g4 = surface.controlPoints.length - 2; + while(_g11 < _g4) { + var i1 = _g11++; + var _g31 = 0; + var _g22 = surface.controlPoints[i1].length; + while(_g31 < _g22) { + var j1 = _g31++; + iduu = verb_core_Vec.norm(verb_core_Vec.add(dehomo[i1 + 2][j1],verb_core_Vec.add(verb_core_Vec.mul(-2.0,dehomo[i1 + 1][j1]),dehomo[i1][j1]))) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i1 + 2][j1]) - 2 * verb_core_ArrayExtensions.last(ts.controlPoints[i1 + 1][j1]) + verb_core_ArrayExtensions.last(ts.controlPoints[i1][j1])); + if(iduu > duu) duu = iduu; + } + } + var dvv = -Infinity; + var idvv; + var _g12 = 0; + var _g5 = surface.controlPoints.length; + while(_g12 < _g5) { + var i2 = _g12++; + var _g32 = 0; + var _g23 = surface.controlPoints[i2].length - 2; + while(_g32 < _g23) { + var j2 = _g32++; + idvv = verb_core_Vec.norm(verb_core_Vec.add(dehomo[i2][j2 + 2],verb_core_Vec.add(verb_core_Vec.mul(-2.0,dehomo[i2][j2 + 1]),dehomo[i2][j2]))) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2 + 2]) - 2 * verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2 + 1]) + verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2])); + if(idvv > dvv) dvv = idvv; + } + } + var duv = -Infinity; + var iduv; + var _g13 = 0; + var _g6 = surface.controlPoints.length - 1; + while(_g13 < _g6) { + var i3 = _g13++; + var _g33 = 0; + var _g24 = surface.controlPoints[i3].length - 1; + while(_g33 < _g24) { + var j3 = _g33++; + iduv = verb_core_Vec.norm(verb_core_Vec.addAll([dehomo[i3 + 1][j3 + 1],verb_core_Vec.mul(-1.0,dehomo[i3][j3 + 1]),verb_core_Vec.mul(-1.0,dehomo[i3 + 1][j3]),dehomo[i3][j3]])) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i3 + 1][j3 + 1]) - verb_core_ArrayExtensions.last(ts.controlPoints[i3][j3 + 1]) - verb_core_ArrayExtensions.last(ts.controlPoints[i3 + 1][j3]) + verb_core_ArrayExtensions.last(ts.controlPoints[i3][j3])); + if(iduv > duv) duv = iduv; + } + } + duu *= surface.degreeU * (surface.degreeU - 1); + dvv *= surface.degreeV * (surface.degreeV - 1); + duv *= surface.degreeU * surface.degreeV; + var minw = Infinity; + var w; + var _g14 = 0; + var _g7 = surface.controlPoints.length; + while(_g14 < _g7) { + var i4 = _g14++; + var _g34 = 0; + var _g25 = surface.controlPoints[i4].length; + while(_g34 < _g25) { + var j4 = _g34++; + w = verb_core_ArrayExtensions.last(surface.controlPoints[i4][j4]); + if(w < minw) minw = w; + } + } + var stepu; + var stepv; + if(Math.abs(duu) < verb_core_Constants.TOLERANCE) { + stepu = 1.0; + if(Math.abs(dvv) < verb_core_Constants.TOLERANCE) { + stepv = 1.0; + return new verb_core_Pair(stepu,stepv); + } + stepv = (Math.sqrt(duv * duv + 8 * dvv * tol * minw) - duv) / dvv; + } + if(Math.abs(dvv) < verb_core_Constants.TOLERANCE) { + stepv = 1.0; + stepu = (Math.sqrt(duv * duv + 8 * duu * tol * minw) - duv) / duu; + return new verb_core_Pair(stepu,stepv); + } + var unum; + var vnum; + var denom; + unum = 4 * dvv * tol * minw; + denom = duu * dvv + duv * Math.sqrt(duu * dvv); + stepu = Math.sqrt(unum / denom); + vnum = 4 * duu * tol * minw; + stepv = Math.sqrt(vnum / denom); + return new verb_core_Pair(stepu,stepv); +}; +verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { + if(includeU == null) includeU = false; + if(crv.degree == 1) { + var pts1 = []; + var _g1 = 0; + var _g = crv.controlPoints.length; + while(_g1 < _g) { + var i = _g1++; + pts1.push(verb_eval_Eval.dehomogenize(crv.controlPoints[i])); + } + if(includeU) { + var _g11 = 0; + var _g2 = crv.controlPoints.length; + while(_g11 < _g2) { + var i1 = _g11++; + pts1[i1].push(crv.knots[i1 + 1]); } - return _g; - } - } - return verb_eval_Tess.rationalCurveAdaptiveSampleRange(curve,curve.knots[0],verb_core_ArrayExtensions.last(curve.knots),tol,includeU); -}; -verb_eval_Tess.rationalCurveAdaptiveSampleRange = function(curve,start,end,tol,includeU) { - var p1 = verb_eval_Eval.rationalCurvePoint(curve,start); - var p3 = verb_eval_Eval.rationalCurvePoint(curve,end); - var t = 0.5 + 0.2 * Math.random(); - var mid = start + (end - start) * t; - var p2 = verb_eval_Eval.rationalCurvePoint(curve,mid); - var diff = verb_core_Vec.sub(p1,p3); - var diff2 = verb_core_Vec.sub(p1,p2); - if(verb_core_Vec.dot(diff,diff) < tol && verb_core_Vec.dot(diff2,diff2) > tol || !verb_core_Trig.threePointsAreFlat(p1,p2,p3,tol)) { - var exact_mid = start + (end - start) * 0.5; - var left_pts = verb_eval_Tess.rationalCurveAdaptiveSampleRange(curve,start,exact_mid,tol,includeU); - var right_pts = verb_eval_Tess.rationalCurveAdaptiveSampleRange(curve,exact_mid,end,tol,includeU); - return left_pts.slice(0,-1).concat(right_pts); - } else if(includeU) return [[start].concat(p1),[end].concat(p3)]; else return [p1,p3]; + } + return pts1; + } + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var beziers; + if(crv.knots.length == (crv.degree + 1) * 2) beziers = [crv]; else beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var brange; + var fraction; + var currentU = crv.knots[0]; + var step = range / divs; + var brange1; + var bsteps; + var nextU; + var _g12 = 0; + var _g3 = beziers.length; + while(_g12 < _g3) { + var i2 = _g12++; + brange1 = verb_core_ArrayExtensions.last(beziers[i2].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i2].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,currentU,step,bsteps + 1,includeU); + currentU = nextU + step; + } + return pts; +}; +verb_eval_Tess.rationalCurveAdaptiveSample = function(crv,tol,includeU) { + if(includeU == null) includeU = false; + if(crv.degree == 1) { + var pts1 = []; + var _g1 = 0; + var _g = crv.controlPoints.length; + while(_g1 < _g) { + var i = _g1++; + pts1.push(verb_eval_Eval.dehomogenize(crv.controlPoints[i])); + } + if(includeU) { + var _g11 = 0; + var _g2 = crv.controlPoints.length; + while(_g11 < _g2) { + var i1 = _g11++; + pts1[i1].push(crv.knots[i1 + 1]); + } + } + return pts1; + } + var beziers; + if(crv.knots.length == (crv.degree + 1) * 2) beziers = [crv]; else beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var steps; + var domain; + var len; + var _g12 = 0; + var _g3 = beziers.length; + while(_g12 < _g3) { + var i2 = _g12++; + domain = verb_core_ArrayExtensions.last(beziers[i2].knots) - beziers[i2].knots[0]; + len = verb_eval_Tess.rationalBezierCurveStepLength(beziers[i2],tol); + steps = Math.ceil(domain / len); + len = domain / steps; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,beziers[i2].knots[0],len,steps + 1,includeU); + if(i2 == beziers.length - 1) break; + pts.pop(); + } + return pts; +}; +verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps,includeU) { + if(includeU == null) includeU = false; + var its = []; + var ts = [its]; + var u = startU; + var degree1 = crv.degree + 1; + if(numSteps <= crv.degree + 1) { + var _g = 0; + while(_g < numSteps) { + var i = _g++; + pts.push(verb_eval_Eval.rationalCurvePoint(crv,u)); + u += step; + } + return; + } + var _g1 = 0; + while(_g1 < degree1) { + var i1 = _g1++; + its.push(verb_eval_Eval.curvePoint(crv,u)); + u += step; + } + var prev; + var _g2 = 1; + while(_g2 < degree1) { + var i2 = _g2++; + its = []; + ts.push(its); + prev = ts[i2 - 1]; + var _g21 = 1; + var _g11 = prev.length; + while(_g21 < _g11) { + var j = _g21++; + its.push(verb_core_Vec.sub(prev[j],prev[j - 1])); + } + } + var _g3 = 0; + var _g12 = ts[0]; + while(_g3 < _g12.length) { + var pt = _g12[_g3]; + ++_g3; + pts.push(verb_eval_Eval.dehomogenize(pt)); + } + var front; + var _g4 = []; + var _g13 = 0; + while(_g13 < ts.length) { + var r = ts[_g13]; + ++_g13; + _g4.push(verb_core_ArrayExtensions.last(r)); + } + front = _g4; + var k; + var frlen2 = front.length - 2; + var _g22 = 0; + var _g14 = numSteps - degree1; + while(_g22 < _g14) { + var i3 = _g22++; + var _g41 = 0; + var _g31 = front.length - 1; + while(_g41 < _g31) { + var j1 = _g41++; + k = frlen2 - j1; + verb_core_Vec.addMutate(front[k],front[k + 1]); + } + pts.push(verb_eval_Eval.dehomogenize(front[0])); + } + u = startU; + if(includeU) { + var _g15 = 0; + while(_g15 < pts.length) { + var pt1 = pts[_g15]; + ++_g15; + pt1.push(u); + u += step; + } + } +}; +verb_eval_Tess.rationalBezierCurveStepLength = function(curve,tol) { + var dehomo = verb_eval_Eval.dehomogenize1d(curve.controlPoints); + var bb = new verb_core_BoundingBox(dehomo); + var avgPt = verb_core_Vec.mul(0.5,verb_core_Vec.add(bb.min,bb.max)); + var m = verb_core_Mat.identity(4); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + var tc = verb_eval_Modify.rationalCurveTransform(curve,m); + dehomo = verb_eval_Eval.dehomogenize1d(tc.controlPoints); + var r = 0.0; + var n; + var _g1 = 0; + var _g = dehomo.length; + while(_g1 < _g) { + var i = _g1++; + n = verb_core_Vec.norm(dehomo[i]); + if(n > r) r = n; + } + var wts = verb_eval_Eval.weight1d(curve.controlPoints); + var w = verb_core_Vec.min(wts); + var domain = verb_core_ArrayExtensions.last(curve.knots) - curve.knots[0]; + if(tol < r) { + var numer = 8 * w * tol; + var ws = verb_eval_Tess.secondForwardDiff(wts); + var pts = verb_eval_Tess.secondForwardDiff2(dehomo); + var fs; + var _g2 = []; + var _g21 = 0; + var _g11 = pts.length; + while(_g21 < _g11) { + var i1 = _g21++; + _g2.push(verb_core_Vec.norm(pts[i1]) + (r - tol) * ws[i1]); + } + fs = _g2; + var f = verb_core_Vec.max(fs); + var denom = curve.degree * (curve.degree - 1.0) * f; + return domain * Math.sqrt(numer / denom); + } else if(r >= tol && tol < 2.0 * r) { + var numer1 = 8 * w * tol; + var pts1 = verb_eval_Tess.secondForwardDiff2(dehomo); + var fs1; + var _g3 = []; + var _g22 = 0; + var _g12 = pts1.length; + while(_g22 < _g12) { + var i2 = _g22++; + _g3.push(verb_core_Vec.norm(pts1[i2])); + } + fs1 = _g3; + var f1 = verb_core_Vec.max(fs1); + var denom1 = curve.degree * (curve.degree - 1.0) * f1; + return domain * Math.sqrt(numer1 / denom1); + } else return domain; +}; +verb_eval_Tess.secondForwardDiff = function(array) { + var i = 0; + var res = []; + while(i < array.length - 2) { + res.push(array[i + 2] - 2.0 * array[i + 1] + array[i]); + i++; + } + return res; +}; +verb_eval_Tess.secondForwardDiff2 = function(array) { + var i = 0; + var res = []; + while(i < array.length - 2) { + res.push(verb_core_Vec.add(array[i + 2],verb_core_Vec.add(verb_core_Vec.mul(-2.0,array[i + 1]),array[i]))); + i++; + } + return res; }; verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { if(divs_u < 1) divs_u = 1; @@ -6134,8 +7139,8 @@ verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { var _g2 = divs_v + 1; while(_g3 < _g2) { var j = _g3++; - var pt_u = i * span_u; - var pt_v = j * span_v; + var pt_u = knotsU[0] + i * span_u; + var pt_v = knotsV[0] + j * span_v; uvs.push([pt_u,pt_v]); var derivs = verb_eval_Eval.rationalSurfaceDerivatives(surface,pt_u,pt_v,1); var pt = derivs[0][0]; @@ -6258,6 +7263,53 @@ verb_eval_Tess.rationalSurfaceAdaptive = function(surface,options) { var arrTrees = verb_eval_Tess.divideRationalSurfaceAdaptive(surface,options); return verb_eval_Tess.triangulateAdaptiveRefinementNodeTree(arrTrees); }; +verb_eval_Tess.rationalSurfaceRegularSample = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSample(surface,divsU,divsV)); +}; +verb_eval_Tess.surfaceRegularSample = function(surface,divsU,divsV) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var dim = controlPoints[0][0].length; + var spanU = (verb_core_ArrayExtensions.last(knotsU) - knotsU[0]) / divsU; + var spanV = (verb_core_ArrayExtensions.last(knotsV) - knotsV[0]) / divsV; + var knotSpansBasesU = verb_eval_Eval.regularlySpacedBasisFunctions(degreeU,knotsU,divsU); + var knotSpansU = knotSpansBasesU.item0; + var basesU = knotSpansBasesU.item1; + var knotSpansBasesV = verb_eval_Eval.regularlySpacedBasisFunctions(degreeV,knotsV,divsV); + var knotSpansV = knotSpansBasesV.item0; + var basesV = knotSpansBasesV.item1; + var pts = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var ptsi = []; + pts.push(ptsi); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + ptsi.push(verb_eval_Eval.surfacePointGivenBasesKnotSpans(degreeU,degreeV,controlPoints,knotSpansU[i],knotSpansV[j],basesU[i],basesV[j],dim)); + } + } + return pts; +}; +verb_eval_Tess.surfaceRegularSample2 = function(surface,divsU,divsV) { + var pts = []; + var u = surface.knotsU[0]; + var t = (verb_core_ArrayExtensions.last(surface.knotsU) - surface.knotsU[0]) / divsU; + var _g = 0; + while(_g < divsU) { + var i = _g++; + var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); + pts.push(verb_eval_Tess.rationalCurveRegularSample(iso,divsV)); + u += t; + } + return pts; +}; var verb_eval_AdaptiveRefinementOptions = $hx_exports.core.AdaptiveRefinementOptions = function() { this.minDivsV = 1; this.minDivsU = 1; @@ -6729,9 +7781,11 @@ verb_geom_NurbsCurve.prototype = $extend(verb_core_SerializableBase.prototype,{ }); } ,tessellate: function(tolerance) { + if(tolerance == null) tolerance = 1e-3; return verb_eval_Tess.rationalCurveAdaptiveSample(this._data,tolerance,false); } ,tessellateAsync: function(tolerance) { + if(tolerance == null) tolerance = 1e-3; return verb_exe_Dispatcher.dispatchMethod(verb_eval_Tess,"rationalCurveAdaptiveSample",[this._data,tolerance,false]); } ,__class__: verb_geom_NurbsCurve diff --git a/build/js/verb.min.js b/build/js/verb.min.js index b819a3e4..6da719bb 100644 --- a/build/js/verb.min.js +++ b/build/js/verb.min.js @@ -1,6 +1,15 @@ +<<<<<<< HEAD +/*! verb 2016-06-15 */ +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.verb=a()}}(function(){var a={};if("object"!=typeof c&&"function"==typeof require&&(Worker=require("webworker-threads").Worker),"object"!=typeof c){var b=this,c=b;if("function"==typeof importScripts){var d=function(a,c){var d=b;return a.split(".").forEach(function(a){d&&(d=d[a])}),d?d[c]:null};onmessage=function(a){if(a.data.className&&a.data.methodName){var b=d(a.data.className,a.data.methodName);return b?void postMessage({result:b.apply(null,a.data.args),id:a.data.id}):console.error("could not find "+a.data.className+"."+a.data.methodName)}}}}return function(a,b,c){"use strict";function d(a,b){function c(){}c.prototype=a;var d=new c;for(var e in b)d[e]=b[e];return b.toString!==Object.prototype.toString&&(d.toString=b.toString),d}function e(a){return a instanceof Array?function(){return i.iter(a)}:"function"==typeof a.iterator?f(a,a.iterator):a.iterator}function f(a,b){if(null==b)return null;null==b.__id__&&(b.__id__=lb++);var c;return null==a.hx__closures__?a.hx__closures__={}:c=a.hx__closures__[b.__id__],null==c&&(c=function(){return c.method.apply(c.scope,arguments)},c.scope=a,c.method=b,a.hx__closures__[b.__id__]=c),c}b.geom=b.geom||{},b.exe=b.exe||{},b.eval=b.eval||{},b.core=b.core||{},b.promhx=b.promhx||{};var g={},h=function(){return D.__string_rec(this,"")},i=function(){};g.HxOverrides=i,i.__name__=["HxOverrides"],i.strDate=function(a){var b=a.length;switch(b){case 8:var c=a.split(":"),d=new Date;return d.setTime(0),d.setUTCHours(c[0]),d.setUTCMinutes(c[1]),d.setUTCSeconds(c[2]),d;case 10:var e=a.split("-");return new Date(e[0],e[1]-1,e[2],0,0,0);case 19:var f=a.split(" "),g=f[0].split("-"),h=f[1].split(":");return new Date(g[0],g[1]-1,g[2],h[0],h[1],h[2]);default:throw new C("Invalid date format : "+a)}},i.cca=function(a,b){var c=a.charCodeAt(b);return c!=c?void 0:c},i.substr=function(a,b,c){return null!=b&&0!=b&&null!=c&&0>c?"":(null==c&&(c=a.length),0>b?(b=a.length+b,0>b&&(b=0)):0>c&&(c=a.length+c-b),a.substr(b,c))},i.iter=function(a){return{cur:0,arr:a,hasNext:function(){return this.curc;){var e=c++,f=this.cache[e];if(typeof f==b&&f==a)return this.buf.b+="r",null==e?this.buf.b+="null":this.buf.b+=""+e,!0}return this.cache.push(a),!1},serializeFields:function(a){for(var b=0,c=l.fields(a);bd?this.buf.b+="m":this.buf.b+="p";break;case 3:a?this.buf.b+="t":this.buf.b+="f";break;case 6:var e=b[2];if(e==String)return void this.serializeString(a);if(this.useCache&&this.serializeRef(a))return;switch(e){case Array:var f=0;this.buf.b+="a";for(var g=a.length,h=0;g>h;){var i=h++;null==a[i]?f++:(f>0&&(1==f?this.buf.b+="n":(this.buf.b+="u",null==f?this.buf.b+="null":this.buf.b+=""+f),f=0),this.serialize(a[i]))}f>0&&(1==f?this.buf.b+="n":(this.buf.b+="u",null==f?this.buf.b+="null":this.buf.b+=""+f)),this.buf.b+="h";break;case k:this.buf.b+="l";for(var j=a,o=j.h,p=null;null!=o;){var r;p=o[0],o=o[1],r=p,this.serialize(r)}this.buf.b+="h";break;case Date:var s=a;this.buf.b+="v",this.buf.add(s.getTime());break;case y:this.buf.b+="b";for(var u=a,x=u.keys();x.hasNext();){var A=x.next();this.serializeString(A),this.serialize(null!=sb[A]?u.getReserved(A):u.h[A])}this.buf.b+="h";break;case v:this.buf.b+="q";for(var B=a,E=B.keys();E.hasNext();){var F=E.next();this.buf.b+=":",null==F?this.buf.b+="null":this.buf.b+=""+F,this.serialize(B.h[F])}this.buf.b+="h";break;case w:this.buf.b+="M";for(var G=a,H=G.keys();H.hasNext();){var I=H.next(),J=l.field(I,"__id__");l.deleteField(I,"__id__"),this.serialize(I),I.__id__=J,this.serialize(G.h[I.__id__])}this.buf.b+="h";break;case z:for(var K=a,L=0,M=K.length-2,N=new n,O=t.BASE64;M>L;){var P=K.get(L++),Q=K.get(L++),R=K.get(L++);N.add(O.charAt(P>>2)),N.add(O.charAt(63&(P<<4|Q>>4))),N.add(O.charAt(63&(Q<<2|R>>6))),N.add(O.charAt(63&R))}if(L==M){var S=K.get(L++),T=K.get(L++);N.add(O.charAt(S>>2)),N.add(O.charAt(63&(S<<4|T>>4))),N.add(O.charAt(T<<2&63))}else if(L==M+1){var U=K.get(L++);N.add(O.charAt(U>>2)),N.add(O.charAt(U<<4&63))}var V=N.b;this.buf.b+="s",null==V.length?this.buf.b+="null":this.buf.b+=""+V.length,this.buf.b+=":",null==V?this.buf.b+="null":this.buf.b+=""+V;break;default:this.useCache&&this.cache.pop(),null!=a.hxSerialize?(this.buf.b+="C",this.serializeString(q.getClassName(e)),this.useCache&&this.cache.push(a),a.hxSerialize(this),this.buf.b+="g"):(this.buf.b+="c",this.serializeString(q.getClassName(e)),this.useCache&&this.cache.push(a),this.serializeFields(a))}break;case 4:if(D.__instanceof(a,qb)){var W=q.getClassName(a);this.buf.b+="A",this.serializeString(W)}else if(D.__instanceof(a,rb))this.buf.b+="B",this.serializeString(q.getEnumName(a));else{if(this.useCache&&this.serializeRef(a))return;this.buf.b+="o",this.serializeFields(a)}break;case 7:var X=b[2];if(this.useCache){if(this.serializeRef(a))return;this.cache.pop()}this.useEnumIndex?this.buf.b+="j":this.buf.b+="w",this.serializeString(q.getEnumName(X)),this.useEnumIndex?(this.buf.b+=":",this.buf.b+=m.string(a[1])):this.serializeString(a[0]),this.buf.b+=":";var Y=a.length;this.buf.b+=m.string(Y-2);for(var Z=2;Y>Z;){var $=Z++;this.serialize(a[$])}this.useCache&&this.cache.push(a);break;case 5:throw new C("Cannot serialize function");default:throw new C("Cannot serialize "+m.string(a))}},__class__:t};var u=function(a){this.buf=a,this.length=a.length,this.pos=0,this.scache=[],this.cache=[];var b=u.DEFAULT_RESOLVER;null==b&&(b=q,u.DEFAULT_RESOLVER=b),this.setResolver(b)};g["haxe.Unserializer"]=u,u.__name__=["haxe","Unserializer"],u.initCodes=function(){for(var a=[],b=0,c=u.BASE64.length;c>b;){var d=b++;a[u.BASE64.charCodeAt(d)]=d}return a},u.prototype={setResolver:function(a){null==a?this.resolver={resolveClass:function(a){return null},resolveEnum:function(a){return null}}:this.resolver=a},get:function(a){return this.buf.charCodeAt(a)},readDigits:function(){for(var a=0,b=!1,c=this.pos;;){var d=this.buf.charCodeAt(this.pos);if(d!=d)break;if(45!=d){if(48>d||d>57)break;a=10*a+(d-48),this.pos++}else{if(this.pos!=c)break;b=!0,this.pos++}}return b&&(a*=-1),a},readFloat:function(){for(var a=this.pos;;){var b=this.buf.charCodeAt(this.pos);if(!(b>=43&&58>b||101==b||69==b))break;this.pos++}return m.parseFloat(i.substr(this.buf,a,this.pos-a))},unserializeObject:function(a){for(;;){if(this.pos>=this.length)throw new C("Invalid object");if(103==this.buf.charCodeAt(this.pos))break;var b=this.unserialize();if("string"!=typeof b)throw new C("Invalid object key");var c=this.unserialize();a[b]=c}this.pos++},unserializeEnum:function(a,b){if(58!=this.get(this.pos++))throw new C("Invalid enum format");var c=this.readDigits();if(0==c)return q.createEnum(a,b);for(var d=[];c-->0;)d.push(this.unserialize());return q.createEnum(a,b,d)},unserialize:function(){var a=this.get(this.pos++);switch(a){case 110:return null;case 116:return!0;case 102:return!1;case 122:return 0;case 105:return this.readDigits();case 100:return this.readFloat();case 121:var b=this.readDigits();if(58!=this.get(this.pos++)||this.length-this.posh||h>=this.cache.length)throw new C("Invalid reference");return this.cache[h];case 82:var j=this.readDigits();if(0>j||j>=this.scache.length)throw new C("Invalid string reference");return this.scache[j];case 120:throw new C(this.unserialize());case 99:var l=this.unserialize(),m=this.resolver.resolveClass(l);if(null==m)throw new C("Class not found "+l);var n=q.createEmptyInstance(m);return this.cache.push(n),this.unserializeObject(n),n;case 119:var p=this.unserialize(),r=this.resolver.resolveEnum(p);if(null==r)throw new C("Enum not found "+p);var s=this.unserializeEnum(r,this.unserialize());return this.cache.push(s),s;case 106:var t=this.unserialize(),x=this.resolver.resolveEnum(t);if(null==x)throw new C("Enum not found "+t);this.pos++;var A=this.readDigits(),B=q.getEnumConstructs(x)[A];if(null==B)throw new C("Unknown enum index "+t+"@"+A);var D=this.unserializeEnum(x,B);return this.cache.push(D),D;case 108:var E=new k;this.cache.push(E);for(this.buf;104!=this.buf.charCodeAt(this.pos);)E.add(this.unserialize());return this.pos++,E;case 98:var F=new y;this.cache.push(F);for(this.buf;104!=this.buf.charCodeAt(this.pos);){var G=this.unserialize();F.set(G,this.unserialize())}return this.pos++,F;case 113:var H=new v;this.cache.push(H);for(var I=(this.buf,this.get(this.pos++));58==I;){var J=this.readDigits();H.set(J,this.unserialize()),I=this.get(this.pos++)}if(104!=I)throw new C("Invalid IntMap format");return H;case 77:var K=new w;this.cache.push(K);for(this.buf;104!=this.buf.charCodeAt(this.pos);){var L=this.unserialize();K.set(L,this.unserialize())}return this.pos++,K;case 118:var M;if(this.buf.charCodeAt(this.pos)>=48&&this.buf.charCodeAt(this.pos)<=57&&this.buf.charCodeAt(this.pos+1)>=48&&this.buf.charCodeAt(this.pos+1)<=57&&this.buf.charCodeAt(this.pos+2)>=48&&this.buf.charCodeAt(this.pos+2)<=57&&this.buf.charCodeAt(this.pos+3)>=48&&this.buf.charCodeAt(this.pos+3)<=57&&45==this.buf.charCodeAt(this.pos+4)){var N=i.substr(this.buf,this.pos,19);M=i.strDate(N),this.pos+=19}else{var O=this.readFloat(),P=new Date;P.setTime(O),M=P}return this.cache.push(M),M;case 115:var Q=this.readDigits(),R=this.buf;if(58!=this.get(this.pos++)||this.length-this.pos>2)+(V>=2?V-1:0);for(var W=U+(Q-V),X=z.alloc(T),Y=0;W>U;){var Z=S[o.fastCodeAt(R,U++)],$=S[o.fastCodeAt(R,U++)];X.set(Y++,Z<<2|$>>4);var _=S[o.fastCodeAt(R,U++)];X.set(Y++,$<<4|_>>2);var aa=S[o.fastCodeAt(R,U++)];X.set(Y++,_<<6|aa)}if(V>=2){var ba=S[o.fastCodeAt(R,U++)],ca=S[o.fastCodeAt(R,U++)];if(X.set(Y++,ba<<2|ca>>4),3==V){var da=S[o.fastCodeAt(R,U++)];X.set(Y++,ca<<4|da>>2)}}return this.pos+=Q,this.cache.push(X),X;case 67:var ea=this.unserialize(),fa=this.resolver.resolveClass(ea);if(null==fa)throw new C("Class not found "+ea);var ga=q.createEmptyInstance(fa);if(this.cache.push(ga),ga.hxUnserialize(this),103!=this.get(this.pos++))throw new C("Invalid custom data");return ga;case 65:var ha=this.unserialize(),ia=this.resolver.resolveClass(ha);if(null==ia)throw new C("Class not found "+ha);return ia;case 66:var ja=this.unserialize(),ka=this.resolver.resolveEnum(ja);if(null==ka)throw new C("Enum not found "+ja);return ka}throw this.pos--,new C("Invalid char "+this.buf.charAt(this.pos)+" at position "+this.pos)},__class__:u};var v=function(){this.h={}};g["haxe.ds.IntMap"]=v,v.__name__=["haxe","ds","IntMap"],v.__interfaces__=[r],v.prototype={set:function(a,b){this.h[a]=b},remove:function(a){return this.h.hasOwnProperty(a)?(delete this.h[a],!0):!1},keys:function(){var a=[];for(var b in this.h)this.h.hasOwnProperty(b)&&a.push(0|b);return i.iter(a)},__class__:v};var w=function(){this.h={},this.h.__keys__={}};g["haxe.ds.ObjectMap"]=w,w.__name__=["haxe","ds","ObjectMap"],w.__interfaces__=[r],w.prototype={set:function(a,b){var c=a.__id__||(a.__id__=++w.count);this.h[c]=b,this.h.__keys__[c]=a},keys:function(){var a=[];for(var b in this.h.__keys__)this.h.hasOwnProperty(b)&&a.push(this.h.__keys__[b]);return i.iter(a)},__class__:w};var x=g["haxe.ds.Option"]={__ename__:["haxe","ds","Option"],__constructs__:["Some","None"]};x.Some=function(a){var b=["Some",0,a];return b.__enum__=x,b.toString=h,b},x.None=["None",1],x.None.toString=h,x.None.__enum__=x;var y=function(){this.h={}};g["haxe.ds.StringMap"]=y,y.__name__=["haxe","ds","StringMap"],y.__interfaces__=[r],y.prototype={set:function(a,b){null!=sb[a]?this.setReserved(a,b):this.h[a]=b},get:function(a){return null!=sb[a]?this.getReserved(a):this.h[a]},setReserved:function(a,b){null==this.rh&&(this.rh={}),this.rh["$"+a]=b},getReserved:function(a){return null==this.rh?null:this.rh["$"+a]},keys:function(){var a=this.arrayKeys();return i.iter(a)},arrayKeys:function(){var a=[];for(var b in this.h)this.h.hasOwnProperty(b)&&a.push(b);if(null!=this.rh)for(var b in this.rh)36==b.charCodeAt(0)&&a.push(b.substr(1));return a},__class__:y};var z=function(a){this.length=a.byteLength,this.b=new ub(a),this.b.bufferValue=a,a.hxBytes=this,a.bytes=this.b};g["haxe.io.Bytes"]=z,z.__name__=["haxe","io","Bytes"],z.alloc=function(a){return new z(new tb(a))},z.prototype={get:function(a){return this.b[a]},set:function(a,b){this.b[a]=255&b},__class__:z};var A=g["haxe.io.Error"]={__ename__:["haxe","io","Error"],__constructs__:["Blocked","Overflow","OutsideBounds","Custom"]};A.Blocked=["Blocked",0],A.Blocked.toString=h,A.Blocked.__enum__=A,A.Overflow=["Overflow",1],A.Overflow.toString=h,A.Overflow.__enum__=A,A.OutsideBounds=["OutsideBounds",2],A.OutsideBounds.toString=h,A.OutsideBounds.__enum__=A,A.Custom=function(a){var b=["Custom",3,a];return b.__enum__=A,b.toString=h,b};var B=function(){};g["haxe.io.FPHelper"]=B,B.__name__=["haxe","io","FPHelper"],B.i32ToFloat=function(a){var b=1-(a>>>31<<1),c=a>>>23&255,d=8388607&a;return 0==d&&0==c?0:b*(1+Math.pow(2,-23)*d)*Math.pow(2,c-127)},B.floatToI32=function(a){if(0==a)return 0;var b;b=0>a?-a:a;var c=Math.floor(Math.log(b)/.6931471805599453);-127>c?c=-127:c>128&&(c=128);var d=8388607&Math.round(8388608*(b/Math.pow(2,c)-1));return(0>a?-2147483648:0)|c+127<<23|d},B.i64ToDouble=function(a,b){var c=1-(b>>>31<<1),d=(b>>20&2047)-1023,e=4294967296*(1048575&b)+2147483648*(a>>>31)+(2147483647&a);return 0==e&&-1023==d?0:c*(1+Math.pow(2,-52)*e)*Math.pow(2,d)},B.doubleToI64=function(a){var b=B.i64tmp;if(0==a)b.low=0,b.high=0;else{var c;c=0>a?-a:a;var d,e=Math.floor(Math.log(c)/.6931471805599453),f=4503599627370496*(c/Math.pow(2,e)-1);d=Math.round(f);var g=0|d,h=d/4294967296|0;b.low=g,b.high=(0>a?-2147483648:0)|e+1023<<20|h}return b};var C=function(a){Error.call(this),this.val=a,this.message=String(a),Error.captureStackTrace&&Error.captureStackTrace(this,C)};g["js._Boot.HaxeError"]=C,C.__name__=["js","_Boot","HaxeError"],C.__super__=Error,C.prototype=d(Error.prototype,{__class__:C});var D=function(){};g["js.Boot"]=D,D.__name__=["js","Boot"],D.getClass=function(a){if(a instanceof Array&&null==a.__enum__)return Array;var b=a.__class__;if(null!=b)return b;var c=D.__nativeClassName(a);return null!=c?D.__resolveNativeClass(c):null},D.__string_rec=function(a,b){if(null==a)return"null";if(b.length>=5)return"<...>";var c=typeof a;switch("function"==c&&(a.__name__||a.__ename__)&&(c="object"),c){case"object":if(a instanceof Array){if(a.__enum__){if(2==a.length)return a[0];var d=a[0]+"(";b+=" ";for(var e=2,f=a.length;f>e;){var g=e++;d+=2!=g?","+D.__string_rec(a[g],b):D.__string_rec(a[g],b)}return d+")"}var h=a.length,i="[";b+=" ";for(var j=0;h>j;){var k=j++;i+=(k>0?",":"")+D.__string_rec(a[k],b)}return i+="]"}var l;try{l=a.toString}catch(m){return m instanceof C&&(m=m.val),"???"}if(null!=l&&l!=Object.toString&&"function"==typeof l){var n=a.toString();if("[object Object]"!=n)return n}var o=null,p="{\n";b+=" ";var q=null!=a.hasOwnProperty;for(var o in a)(!q||a.hasOwnProperty(o))&&"prototype"!=o&&"__class__"!=o&&"__super__"!=o&&"__interfaces__"!=o&&"__properties__"!=o&&(2!=p.length&&(p+=", \n"),p+=b+o+" : "+D.__string_rec(a[o],b));return b=b.substring(1),p+="\n"+b+"}";case"function":return"";case"string":return a;default:return String(a)}},D.__interfLoop=function(a,b){if(null==a)return!1;if(a==b)return!0;var c=a.__interfaces__;if(null!=c)for(var d=0,e=c.length;e>d;){var f=d++,g=c[f];if(g==b||D.__interfLoop(g,b))return!0}return D.__interfLoop(a.__super__,b)},D.__instanceof=function(a,b){if(null==b)return!1;switch(b){case mb:return(0|a)===a;case ob:return"number"==typeof a;case pb:return"boolean"==typeof a;case String:return"string"==typeof a;case Array:return a instanceof Array&&null==a.__enum__;case nb:return!0;default:if(null==a)return!1;if("function"==typeof b){if(a instanceof b)return!0;if(D.__interfLoop(D.getClass(a),b))return!0}else if("object"==typeof b&&D.__isNativeObj(b)&&a instanceof b)return!0;return b==qb&&null!=a.__name__?!0:b==rb&&null!=a.__ename__?!0:a.__enum__==b}},D.__nativeClassName=function(a){var b=D.__toStr.call(a).slice(8,-1);return"Object"==b||"Function"==b||"Math"==b||"JSON"==b?null:b},D.__isNativeObj=function(a){return null!=D.__nativeClassName(a)},D.__resolveNativeClass=function(a){return c[a]};var E=function(a){if(a instanceof Array&&null==a.__enum__)this.a=a,this.byteLength=a.length;else{var b=a;this.a=[];for(var c=0;b>c;){var d=c++;this.a[d]=0}this.byteLength=b}};g["js.html.compat.ArrayBuffer"]=E,E.__name__=["js","html","compat","ArrayBuffer"],E.sliceImpl=function(a,b){var c=new ub(this,a,null==b?null:b-a),d=new tb(c.byteLength),e=new ub(d);return e.set(c),d},E.prototype={slice:function(a,b){return new E(this.a.slice(a,b))},__class__:E};var F=function(a,b,c){if(this.buf=a,null==b?this.offset=0:this.offset=b,null==c?this.length=a.byteLength-this.offset:this.length=c,this.offset<0||this.length<0||this.offset+this.length>a.byteLength)throw new C(A.OutsideBounds)};g["js.html.compat.DataView"]=F,F.__name__=["js","html","compat","DataView"],F.prototype={getInt8:function(a){var b=this.buf.a[this.offset+a];return b>=128?b-256:b},getUint8:function(a){return this.buf.a[this.offset+a]},getInt16:function(a,b){var c=this.getUint16(a,b);return c>=32768?c-65536:c},getUint16:function(a,b){return b?this.buf.a[this.offset+a]|this.buf.a[this.offset+a+1]<<8:this.buf.a[this.offset+a]<<8|this.buf.a[this.offset+a+1]},getInt32:function(a,b){var c=this.offset+a,d=this.buf.a[c++],e=this.buf.a[c++],f=this.buf.a[c++],g=this.buf.a[c++];return b?d|e<<8|f<<16|g<<24:g|f<<8|e<<16|d<<24},getUint32:function(a,b){var c=this.getInt32(a,b);return 0>c?c+4294967296:c},getFloat32:function(a,b){return B.i32ToFloat(this.getInt32(a,b))},getFloat64:function(a,b){var c=this.getInt32(a,b),d=this.getInt32(a+4,b);return B.i64ToDouble(b?c:d,b?d:c)},setInt8:function(a,b){0>b?this.buf.a[a+this.offset]=b+128&255:this.buf.a[a+this.offset]=255&b},setUint8:function(a,b){this.buf.a[a+this.offset]=255&b},setInt16:function(a,b,c){this.setUint16(a,0>b?b+65536:b,c)},setUint16:function(a,b,c){var d=a+this.offset;c?(this.buf.a[d]=255&b,this.buf.a[d++]=b>>8&255):(this.buf.a[d++]=b>>8&255,this.buf.a[d]=255&b)},setInt32:function(a,b,c){this.setUint32(a,b,c)},setUint32:function(a,b,c){var d=a+this.offset;c?(this.buf.a[d++]=255&b,this.buf.a[d++]=b>>8&255,this.buf.a[d++]=b>>16&255,this.buf.a[d++]=b>>>24):(this.buf.a[d++]=b>>>24,this.buf.a[d++]=b>>16&255,this.buf.a[d++]=b>>8&255,this.buf.a[d++]=255&b)},setFloat32:function(a,b,c){this.setUint32(a,B.floatToI32(b),c)},setFloat64:function(a,b,c){var d=B.doubleToI64(b);c?(this.setUint32(a,d.low),this.setUint32(a,d.high)):(this.setUint32(a,d.high),this.setUint32(a,d.low))},__class__:F};var G=function(){};g["js.html.compat.Uint8Array"]=G,G.__name__=["js","html","compat","Uint8Array"],G._new=function(a,b,c){var d;if("number"==typeof a){d=[];for(var e=0;a>e;){var f=e++;d[f]=0}d.byteLength=d.length,d.byteOffset=0,d.buffer=new E(d)}else if(D.__instanceof(a,E)){var g=a;null==b&&(b=0),null==c&&(c=g.byteLength-b),d=0==b?g.a:g.a.slice(b,b+c),d.byteLength=d.length,d.byteOffset=b,d.buffer=g}else{if(!(a instanceof Array&&null==a.__enum__))throw new C("TODO "+m.string(a));d=a.slice(),d.byteLength=d.length,d.byteOffset=0,d.buffer=new E(d)}return d.subarray=G._subarray,d.set=G._set,d},G._set=function(a,b){var c=this;if(D.__instanceof(a.buffer,E)){var d=a;if(a.byteLength+b>c.byteLength)throw new C("set() outside of range");for(var e=0,f=a.byteLength;f>e;){var g=e++;c[g+b]=d[g]}}else{if(!(a instanceof Array&&null==a.__enum__))throw new C("TODO");var h=a;if(h.length+b>c.byteLength)throw new C("set() outside of range");for(var i=0,j=h.length;j>i;){var k=i++;c[k+b]=h[k]}}},G._subarray=function(a,b){var c=this,d=G._new(c.slice(a,b));return d.byteOffset=a,d};var H=function(a){this._resolved=!1,this._pending=!1,this._errorPending=!1,this._fulfilled=!1,this._update=[],this._error=[],this._errored=!1,null!=a&&H.link(a,this,function(a){return a})};g["promhx.base.AsyncBase"]=H,H.__name__=["promhx","base","AsyncBase"],H.link=function(a,b,c){a._update.push({async:b,linkf:function(a){b.handleResolve(c(a))}}),H.immediateLinkUpdate(a,b,c)},H.immediateLinkUpdate=function(a,b,c){if(!a._errored||a._errorPending||a._error.length>0||b.handleError(a._errorVal),a._resolved&&!a._pending)try{b.handleResolve(c(a._val))}catch(d){d instanceof C&&(d=d.val),b.handleError(d)}},H.linkAll=function(a,b){for(var c=function(c,d,f){if(0==c.length||H.allFulfilled(c)){for(var g,h=[],i=e(a)();i.hasNext();){var j=i.next();h.push(j==d?f:j._val)}g=h,b.handleResolve(g)}},d=e(a)();d.hasNext();){var f=d.next();f._update.push({async:b,linkf:function(a,b,c){return function(d){a(b,c,d)}}(c,function(b){for(var c,d=[],g=e(a)();g.hasNext();){var h=g.next();h!=f&&d.push(h)}return c=d}(this),f)})}H.allFulfilled(a)&&b.handleResolve(function(b){for(var c,d=[],f=e(a)();f.hasNext();){var g=f.next();d.push(g._val)}return c=d}(this))},H.pipeLink=function(a,b,c){var d=!1,e=function(a){if(!d){d=!0;var e=c(a);e._update.push({async:b,linkf:f(b,b.handleResolve)}),H.immediateLinkUpdate(e,b,function(a){return a})}};if(a._update.push({async:b,linkf:e}),a._resolved&&!a._pending)try{e(a._val)}catch(g){g instanceof C&&(g=g.val),b.handleError(g)}},H.allResolved=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._resolved)return!1}return!0},H.allFulfilled=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._fulfilled)return!1}return!0},H.prototype={catchError:function(a){return this._error.push(a),this},errorThen:function(a){return this._errorMap=a,this},isResolved:function(){return this._resolved},isErrored:function(){return this._errored},isErrorHandled:function(){return this._error.length>0},isErrorPending:function(){return this._errorPending},isFulfilled:function(){return this._fulfilled},isPending:function(){return this._pending},handleResolve:function(a){this._resolve(a)},_resolve:function(a){var b=this;this._pending?M.enqueue(function(a,b){return function(){a(b)}}(f(this,this._resolve),a)):(this._resolved=!0,this._pending=!0,M.queue.add(function(){b._val=a;for(var c=0,d=b._update;c0)for(var c=0,d=b._error;c0))throw new C(a);for(var f=0,g=b._update;f0&&null!=(b=M.queue.pop());)b();return M.queue.isEmpty()},M.clear=function(){M.queue=new k},M.f=function(){var a=M.queue.pop();null!=a&&a(),M.queue.isEmpty()||M.continueOnNextLoop()},M.continueOnNextLoop=function(){null!=M.nextLoop?M.nextLoop(M.f):setImmediate(M.f)};var N=g["promhx.error.PromiseError"]={__ename__:["promhx","error","PromiseError"],__constructs__:["AlreadyResolved","DownstreamNotFullfilled"]};N.AlreadyResolved=function(a){var b=["AlreadyResolved",0,a];return b.__enum__=N,b.toString=h,b},N.DownstreamNotFullfilled=function(a){var b=["DownstreamNotFullfilled",1,a];return b.__enum__=N,b.toString=h,b};var O=function(){};g["verb.Verb"]=O,O.__name__=["verb","Verb"],O.main=function(){a.log("verb 2.1.0")};var P=function(){};g["verb.core.ArrayExtensions"]=P,P.__name__=["verb","core","ArrayExtensions"],P.alloc=function(a,b){if(!(0>b))for(;a.length0;){for(var d=a.pop(),e=!0,f=0;fa)return 0;if(b>a-b&&(b=a-b),Q.memo_exists(a,b))return Q.get_memo(a,b);for(var c=1,d=a,e=1,f=b+1;f>e;){var g=e++;Q.memo_exists(d,g)?(a--,c=Q.get_memo(d,g)):(c*=a--,c/=g,Q.memoize(d,g,c))}return c},Q.get_no_memo=function(a,b){if(0==b)return 1;if(0==a||b>a)return 0;b>a-b&&(b=a-b);for(var c=1,d=1,e=b+1;e>d;){var f=d++;c*=a--,c/=f}return c},Q.memo_exists=function(a,b){return Q.memo.h.hasOwnProperty(a)&&Q.memo.h[a].h.hasOwnProperty(b)},Q.get_memo=function(a,b){return Q.memo.h[a].h[b]},Q.memoize=function(a,b,c){Q.memo.h.hasOwnProperty(a)||Q.memo.set(a,new v),Q.memo.h[a].h[b]=c};var R=b.core.BoundingBox=function(a){this.max=null,this.min=null,this.dim=3,this.initialized=!1,null!=a&&this.addRange(a)};g["verb.core.BoundingBox"]=R,R.__name__=["verb","core","BoundingBox"],R.intervalsOverlap=function(a,b,c,d,e){null==e&&(e=-1);var f;f=-.5>e?S.TOLERANCE:e;var g=Math.min(a,b)-f,h=Math.max(a,b)+f,i=Math.min(c,d)-f,j=Math.max(c,d)+f;return g>=i&&j>=g||h>=i&&j>=h||i>=g&&h>=i||j>=g&&h>=j},R.prototype={fromPoint:function(a){return new R([a])},add:function(a){if(!this.initialized)return this.dim=a.length,this.min=a.slice(0),this.max=a.slice(0),this.initialized=!0,this;for(var b=0,c=this.dim;c>b;){var d=b++;a[d]>this.max[d]&&(this.max[d]=a[d]),a[d]c;){var d=c++;this.add(a[d])}return this},contains:function(a,b){return null==b&&(b=-1),this.initialized?this.intersects(new R([a]),b):!1},intersects:function(a,b){if(null==b&&(b=-1),!this.initialized||!a.initialized)return!1;for(var c=this.min,d=this.max,e=a.min,f=a.max,g=0,h=this.dim;h>g;){var i=g++;if(!R.intervalsOverlap(c[i],d[i],e[i],f[i],b))return!1}return!0},clear:function(){return this.initialized=!1,this},getLongestAxis:function(){for(var a=0,b=0,c=0,d=this.dim;d>c;){var e=c++,f=this.getAxisLength(e);f>a&&(a=f,b=e)}return b},getAxisLength:function(a){return 0>a||a>this.dim-1?0:Math.abs(this.min[a]-this.max[a])},intersect:function(a,b){if(!this.initialized)return null;var c=this.min,d=this.max,e=a.min,f=a.max;if(!this.intersects(a,b))return null;for(var g=[],h=[],i=0,j=this.dim;j>i;){var k=i++;g.push(Math.min(d[k],f[k])),h.push(Math.max(c[k],e[k]))}return new R([h,g])},__class__:R};var S=b.core.Constants=function(){};g["verb.core.Constants"]=S,S.__name__=["verb","core","Constants"];var T=b.core.SerializableBase=function(){};g["verb.core.SerializableBase"]=T,T.__name__=["verb","core","SerializableBase"],T.prototype={serialize:function(){var a=new t;return a.serialize(this),a.toString()},__class__:T};var U=b.core.Plane=function(a,b){this.origin=a,this.normal=b};g["verb.core.Plane"]=U,U.__name__=["verb","core","Plane"],U.__super__=T,U.prototype=d(T.prototype,{__class__:U});var V=b.core.Ray=function(a,b){this.origin=a,this.dir=b};g["verb.core.Ray"]=V,V.__name__=["verb","core","Ray"],V.__super__=T,V.prototype=d(T.prototype,{__class__:V});var W=b.core.NurbsCurveData=function(a,b,c){this.degree=a,this.controlPoints=c,this.knots=b};g["verb.core.NurbsCurveData"]=W,W.__name__=["verb","core","NurbsCurveData"],W.__super__=T,W.prototype=d(T.prototype,{__class__:W});var X=b.core.NurbsSurfaceData=function(a,b,c,d,e){this.degreeU=a,this.degreeV=b,this.knotsU=c,this.knotsV=d,this.controlPoints=e};g["verb.core.NurbsSurfaceData"]=X,X.__name__=["verb","core","NurbsSurfaceData"],X.__super__=T,X.prototype=d(T.prototype,{__class__:X});var Y=b.core.MeshData=function(a,b,c,d){this.faces=a,this.points=b,this.normals=c,this.uvs=d};g["verb.core.MeshData"]=Y,Y.__name__=["verb","core","MeshData"],Y.empty=function(){return new Y([],[],[],[])},Y.__super__=T,Y.prototype=d(T.prototype,{__class__:Y});var Z=b.core.PolylineData=function(a,b){this.points=a,this.params=b};g["verb.core.PolylineData"]=Z,Z.__name__=["verb","core","PolylineData"],Z.__super__=T,Z.prototype=d(T.prototype,{__class__:Z});var $=b.core.VolumeData=function(a,b,c,d,e,f,g){this.degreeU=a,this.degreeV=b,this.degreeW=c,this.knotsU=d,this.knotsV=e,this.knotsW=f,this.controlPoints=g};g["verb.core.VolumeData"]=$,$.__name__=["verb","core","VolumeData"],$.__super__=T,$.prototype=d(T.prototype,{__class__:$});var _=b.core.Pair=function(a,b){this.item0=a,this.item1=b};g["verb.core.Pair"]=_,_.__name__=["verb","core","Pair"],_.prototype={__class__:_};var aa=b.core.Interval=function(a,b){this.min=a,this.max=b};g["verb.core.Interval"]=aa,aa.__name__=["verb","core","Interval"],aa.prototype={__class__:aa};var ba=b.core.CurveCurveIntersection=function(a,b,c,d){this.point0=a,this.point1=b,this.u0=c,this.u1=d};g["verb.core.CurveCurveIntersection"]=ba,ba.__name__=["verb","core","CurveCurveIntersection"],ba.prototype={__class__:ba};var ca=b.core.CurveSurfaceIntersection=function(a,b,c,d){this.u=a,this.uv=b,this.curvePoint=c,this.surfacePoint=d};g["verb.core.CurveSurfaceIntersection"]=ca,ca.__name__=["verb","core","CurveSurfaceIntersection"],ca.prototype={__class__:ca};var da=b.core.MeshIntersectionPoint=function(a,b,c,d,e){this.visited=!1,this.adj=null,this.opp=null,this.uv0=a,this.uv1=b,this.point=c,this.faceIndex0,this.faceIndex1};g["verb.core.MeshIntersectionPoint"]=da,da.__name__=["verb","core","MeshIntersectionPoint"],da.prototype={__class__:da};var ea=b.core.PolylineMeshIntersection=function(a,b,c,d,e){this.point=a,this.u=b,this.uv=c,this.polylineIndex=d,this.faceIndex=e};g["verb.core.PolylineMeshIntersection"]=ea,ea.__name__=["verb","core","PolylineMeshIntersection"],ea.prototype={__class__:ea};var fa=b.core.SurfaceSurfaceIntersectionPoint=function(a,b,c,d){this.uv0=a,this.uv1=b,this.point=c,this.dist=d};g["verb.core.SurfaceSurfaceIntersectionPoint"]=fa,fa.__name__=["verb","core","SurfaceSurfaceIntersectionPoint"],fa.prototype={__class__:fa};var ga=b.core.TriSegmentIntersection=function(a,b,c,d){this.point=a,this.s=b,this.t=c,this.p=d};g["verb.core.TriSegmentIntersection"]=ga,ga.__name__=["verb","core","TriSegmentIntersection"],ga.prototype={__class__:ga};var ha=b.core.CurveTriPoint=function(a,b,c){this.u=a,this.point=b,this.uv=c};g["verb.core.CurveTriPoint"]=ha,ha.__name__=["verb","core","CurveTriPoint"],ha.prototype={__class__:ha};var ia=function(a,b,c,d,e){null==e&&(e=!1),null==d&&(d=-1),this.uv=c,this.point=a,this.normal=b,this.id=d,this.degen=e};g["verb.core.SurfacePoint"]=ia,ia.__name__=["verb","core","SurfacePoint"],ia.fromUv=function(a,b){return new ia(null,null,[a,b])},ia.prototype={__class__:ia};var ja=b.core.CurvePoint=function(a,b){this.u=a,this.pt=b};g["verb.core.CurvePoint"]=ja,ja.__name__=["verb","core","CurvePoint"],ja.prototype={__class__:ja};var ka=b.core.KdTree=function(a,b){this.dim=3,this.points=a,this.distanceFunction=b,this.dim=a[0].point.length,this.root=this.buildTree(a,0,null)};g["verb.core.KdTree"]=ka,ka.__name__=["verb","core","KdTree"],ka.prototype={buildTree:function(a,b,c){var d,e,f=b%this.dim;return 0==a.length?null:1==a.length?new na(a[0],f,c):(a.sort(function(a,b){var c=a.point[f]-b.point[f];return 0==c?0:c>0?1:-1}),d=Math.floor(a.length/2),e=new na(a[d],f,c),e.left=this.buildTree(a.slice(0,d),b+1,e),e.right=this.buildTree(a.slice(d+1),b+1,e),e)},nearest:function(a,b,c){var d,e=this,f=new la(function(a){return-a.item1}),g=null;g=function(c){for(var d,h,i=c.dimension,j=e.distanceFunction(a,c.kdPoint.point),k=[],l=0,m=e.dim;m>l;){l++;k.push(0)}h=k;for(var n,o,p=function(a,c){f.push(new _(a,c)),f.size()>b&&f.pop()},q=0,r=e.dim;r>q;){var s=q++;s==c.dimension?h[s]=a[s]:h[s]=c.kdPoint.point[s]}return n=e.distanceFunction(h,c.kdPoint.point),null==c.right&&null==c.left?void((f.size()h;){h++;f.push(new _(null,c))}d(this.root);for(var i=[],j=0;b>j;){var k=j++;null!=f.content[k].item0&&i.push(new _(f.content[k].item0.kdPoint,f.content[k].item1))}return i},__class__:ka};var la=function(a){this.content=[],this.scoreFunction=a};g["verb.core.BinaryHeap"]=la,la.__name__=["verb","core","BinaryHeap"],la.prototype={push:function(a){this.content.push(a),this.bubbleUp(this.content.length-1)},pop:function(){var a=this.content[0],b=this.content.pop();return this.content.length>0&&(this.content[0]=b,this.sinkDown(0)),a},peek:function(){return this.content[0]},remove:function(a){for(var b=this.content.length,c=0;b>c;){var d=c++;if(this.content[d]==a){var e=this.content.pop();return void(d!=b-1&&(this.content[d]=e,this.scoreFunction(e)0;){var c=Math.floor((a+1)/2)-1,d=this.content[c];if(!(this.scoreFunction(b)f){var i=this.content[f];h=this.scoreFunction(i),d>h&&(g=f)}if(b>e){var j=this.content[e],k=this.scoreFunction(j);(-1==g?d:h)>k&&(g=e)}if(-1==g)break;this.content[a]=this.content[g],this.content[g]=c,a=g}},__class__:la};var ma=b.core.KdPoint=function(a,b){this.point=a,this.obj=b};g["verb.core.KdPoint"]=ma,ma.__name__=["verb","core","KdPoint"],ma.prototype={__class__:ma};var na=b.core.KdNode=function(a,b,c){this.kdPoint=a,this.left=null,this.right=null,this.parent=c,this.dimension=b};g["verb.core.KdNode"]=na,na.__name__=["verb","core","KdNode"],na.prototype={__class__:na};var oa=function(){};g["verb.eval.IBoundingBoxTree"]=oa,oa.__name__=["verb","eval","IBoundingBoxTree"],oa.prototype={__class__:oa};var pa=function(a,b){this._boundingBox=null,this._curve=a,null==b&&(b=Ca.domain(this._curve.knots)/64),this._knotTol=b};g["verb.core.LazyCurveBoundingBoxTree"]=pa,pa.__name__=["verb","core","LazyCurveBoundingBoxTree"],pa.__interfaces__=[oa],pa.prototype={split:function(){var a=P.first(this._curve.knots),b=P.last(this._curve.knots),c=b-a,d=Ga.curveSplit(this._curve,(b+a)/2+.1*c*Math.random());return new _(new pa(d[0],this._knotTol),new pa(d[1],this._knotTol))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=new R(Ia.dehomogenize1d(this._curve.controlPoints))),this._boundingBox},"yield":function(){return this._curve},indivisible:function(a){return Ca.domain(this._curve.knots)d;){var f=d++;c.push(f)}b=c}this._faceIndices=b};g["verb.core.LazyMeshBoundingBoxTree"]=qa,qa.__name__=["verb","core","LazyMeshBoundingBoxTree"],qa.__interfaces__=[oa],qa.prototype={split:function(){var a=va.sortTrianglesOnLongestAxis(this.boundingBox(),this._mesh,this._faceIndices),b=P.left(a),c=P.right(a);return new _(new qa(this._mesh,b),new qa(this._mesh,c))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=va.makeMeshAabb(this._mesh,this._faceIndices)),this._boundingBox},"yield":function(){return this._faceIndices[0]},indivisible:function(a){return 1==this._faceIndices.length},empty:function(){return 0==this._faceIndices.length},__class__:qa};var ra=function(a,b){this._boundingBox=null,this._polyline=a,null==b&&(b=new aa(0,0!=a.points.length?a.points.length-1:0)),this._interval=b};g["verb.core.LazyPolylineBoundingBoxTree"]=ra,ra.__name__=["verb","core","LazyPolylineBoundingBoxTree"],ra.__interfaces__=[oa],ra.prototype={split:function(){var a=this._interval.min,b=this._interval.max,c=a+Math.ceil((b-a)/2),d=new aa(a,c),e=new aa(c,b);return new _(new ra(this._polyline,d),new ra(this._polyline,e))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=new R(this._polyline.points)),this._boundingBox},"yield":function(){return this._interval.min},indivisible:function(a){return this._interval.max-this._interval.min==1},empty:function(){return this._interval.max-this._interval.min==0},__class__:ra};var sa=function(a,b,c,d){null==b&&(b=!1),this._boundingBox=null,this._surface=a,this._splitV=b,null==c&&(c=Ca.domain(a.knotsU)/16),null==d&&(d=Ca.domain(a.knotsV)/16),this._knotTolU=c,this._knotTolV=d};g["verb.core.LazySurfaceBoundingBoxTree"]=sa,sa.__name__=["verb","core","LazySurfaceBoundingBoxTree"],sa.__interfaces__=[oa],sa.prototype={split:function(){var a,b;this._splitV?(a=P.first(this._surface.knotsV),b=P.last(this._surface.knotsV)):(a=P.first(this._surface.knotsU),b=P.last(this._surface.knotsU));var c=(a+b)/2,d=Ga.surfaceSplit(this._surface,c,this._splitV);return new _(new sa(d[0],!this._splitV,this._knotTolU,this._knotTolV),new sa(d[1],!this._splitV,this._knotTolU,this._knotTolV))},boundingBox:function(){if(null==this._boundingBox){this._boundingBox=new R;for(var a=0,b=this._surface.controlPoints;ad;){var f=d++;c.push(Ca.mul(a,b[f]))}return c},ta.mult=function(a,b){var c,d,e,f,g,h,i,j;c=a.length,d=b.length,e=b[0].length,f=[];for(var k=c-1,l=0,m=0;k>=0;){for(g=[],h=a[k],m=e-1;m>=0;){for(i=h[d-1]*b[d-1][m],l=d-2;l>=1;)j=l-1,i+=h[l]*b[l][m]+h[j]*b[j][m],l-=2;0==l&&(i+=h[0]*b[0][m]),g[m]=i,m--}f[k]=g,k--}return f},ta.add=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Ca.add(a[f],b[f]))}return c},ta.div=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Ca.div(a[f],b))}return c},ta.sub=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Ca.sub(a[f],b[f]))}return c},ta.dot=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Ca.dot(a[f],b))}return c},ta.identity=function(a){for(var b=Ca.zeros2d(a,a),c=0;a>c;){var d=c++;b[d][d]=1}return b},ta.transpose=function(a){if(0==a.length)return[];for(var b=[],c=0,d=a[0].length;d>c;){var e=c++;b.push(function(b){for(var c,d=[],f=0,g=a.length;g>f;){var h=f++;d.push(a[h][e])}return c=d}(this))}return b},ta.solve=function(a,b){return ta.LUsolve(ta.LU(a),b)},ta.LUsolve=function(a,b){var c,d,e,f,g,h=a.LU,i=h.length,j=b.slice(),k=a.P;for(c=i-1;-1!=c;)j[c]=b[c],--c;for(c=0;i>c;){for(e=k[c],k[c]!=c&&(g=j[c],j[c]=j[e],j[e]=g),f=h[c],d=0;c>d;)j[c]-=j[d]*f[d],++d;++c}for(c=i-1;c>=0;){for(f=h[c],d=c+1;i>d;)j[c]-=j[d]*f[d],++d;j[c]/=f[c],--c}return j},ta.LU=function(a){for(var b,c,d,e,f,g,h,i,j,k=(Math.abs,[]),l=0,m=a.length;m>l;){var n=l++;k.push(a[n].slice())}a=k;var o=a.length,p=o-1,q=[];for(d=0;o>d;){for(h=d,g=a[d],j=Math.abs(g[d]),c=d+1;o>c;)e=Math.abs(a[c][d]),e>j&&(j=e,h=c),++c;for(q[d]=h,h!=d&&(a[d]=a[h],a[h]=g,g=a[d]),f=g[d],b=d+1;o>b;)a[b][d]/=f,++b;for(b=d+1;o>b;){for(i=a[b],c=d+1;p>c;)i[c]-=i[d]*g[c],++c,i[c]-=i[d]*g[c],++c;c==p&&(i[c]-=i[d]*g[c]),++b}++d}return new ua(a,q)};var ua=function(a,b){this.LU=a,this.P=b};g["verb.core._Mat.LUDecomp"]=ua,ua.__name__=["verb","core","_Mat","LUDecomp"],ua.prototype={__class__:ua};var va=b.core.Mesh=function(){};g["verb.core.Mesh"]=va,va.__name__=["verb","core","Mesh"],va.getTriangleNorm=function(a,b){var c=a[b[0]],d=a[b[1]],e=a[b[2]],f=Ca.sub(d,c),g=Ca.sub(e,c),h=Ca.cross(f,g);return Ca.mul(1/Ca.norm(h),h)},va.makeMeshAabb=function(a,b){for(var c=new R,d=0;dd?1:-1});for(var i=[],j=0,k=e.length;k>j;){var l=j++;i.push(e[l].item1)}return i},va.getMinCoordOnAxis=function(a,b,c){for(var d=1/0,e=0;3>e;){var f=e++,g=a[b[f]][c];d>g&&(d=g)}return d},va.getTriangleCentroid=function(a,b){for(var c=[0,0,0],d=0;3>d;)for(var e=d++,f=0;3>f;){var g=f++;c[g]+=a[b[e]][g]}for(var h=0;3>h;){var i=h++;c[i]/=3}return c},va.triangleUVFromPoint=function(a,b,c){var d=a.faces[b],e=a.points[d[0]],f=a.points[d[1]],g=a.points[d[2]],h=a.uvs[d[0]],i=a.uvs[d[1]],j=a.uvs[d[2]],k=Ca.sub(e,c),l=Ca.sub(f,c),m=Ca.sub(g,c),n=Ca.norm(Ca.cross(Ca.sub(e,f),Ca.sub(e,g))),o=Ca.norm(Ca.cross(l,m))/n,p=Ca.norm(Ca.cross(m,k))/n,q=Ca.norm(Ca.cross(k,l))/n;return Ca.add(Ca.mul(o,h),Ca.add(Ca.mul(p,i),Ca.mul(q,j)))};var wa=function(a,b){if(this._empty=!1,this._face=-1,null==b){for(var c=[],d=0,e=a.faces.length;e>d;){var f=d++;c.push(f)}b=c}if(this._boundingBox=va.makeMeshAabb(a,b),b.length<1)return void(this._empty=!0);if(b.length<2)return void(this._face=b[0]);var g=va.sortTrianglesOnLongestAxis(this._boundingBox,a,b),h=P.left(g),i=P.right(g);this._children=new _(new wa(a,h),new wa(a,i))};g["verb.core.MeshBoundingBoxTree"]=wa,wa.__name__=["verb","core","MeshBoundingBoxTree"],wa.__interfaces__=[oa],wa.prototype={split:function(){return this._children},boundingBox:function(){return this._boundingBox},"yield":function(){return this._face},indivisible:function(a){return null==this._children},empty:function(){return this._empty},__class__:wa};var xa=b.core.Minimizer=function(){};g["verb.core.Minimizer"]=xa,xa.__name__=["verb","core","Minimizer"],xa.uncmin=function(a,b,c,d,e){null==c&&(c=1e-8),null==d&&(d=function(b){return xa.numericalGradient(a,b)}),null==e&&(e=1e3),b=b.slice(0);var f,g=b.length,h=a(b),i=h;if(isNaN(h))throw new C("uncmin: f(x0) is a NaN!");c=Math.max(c,S.EPSILON);var j,k,l,m,n,o,p,q,r,s=ta.identity(g),t=0,u=[],v="";for(k=d(b);e>t;){if(!Ca.all(Ca.finite(k))){v="Gradient has Infinity or NaN";break}if(j=Ca.neg(ta.dot(s,k)),!Ca.all(Ca.finite(j))){v="Search direction has Infinity or NaN";break}if(r=Ca.norm(j),c>r){v="Newton step smaller than tol";break}for(q=1,f=Ca.dot(k,j),m=b;e>t&&!(c>q*r)&&(u=Ca.mul(q,j),m=Ca.add(b,u),i=a(m),i-h>=.1*q*f||isNaN(i));)q*=.5,++t;if(c>q*r){v="Line search step size smaller than tol";break}if(t==e){v="maxit reached during line search";break}l=d(m),n=Ca.sub(l,k),p=Ca.dot(n,u),o=ta.dot(s,n),s=ta.sub(ta.add(s,ta.mul((p+Ca.dot(n,o))/(p*p),xa.tensor(u,u))),ta.div(ta.add(xa.tensor(o,u),xa.tensor(u,o)),p)),b=m,h=i,k=l,++t}return new ya(b,h,k,s,t,v)},xa.numericalGradient=function(a,b){var c=b.length,d=a(b);if(NaN==d)throw new C("gradient: f(x) is a NaN!");for(var e,f,g,h,i,j,k,l,m,n=b.slice(0),o=[],p=.001,q=0,r=0;c>r;)for(var s=r++,t=Math.max(1e-6*d,1e-8);;){if(++q,q>20)throw new C("Numerical gradient fails");if(n[s]=b[s]+t,e=a(n),n[s]=b[s]-t,f=a(n),n[s]=b[s],isNaN(e)||isNaN(f))t/=16;else{if(o[s]=(e-f)/(2*t),h=b[s]-t,i=b[s],j=b[s]+t,k=(e-d)/t,l=(d-f)/t,m=Ca.max([Math.abs(o[s]),Math.abs(d),Math.abs(e),Math.abs(f),Math.abs(h),Math.abs(i),Math.abs(j),1e-8]),g=Math.min(Ca.max([Math.abs(k-o[s]),Math.abs(l-o[s]),Math.abs(k-l)])/m,t/m),!(g>p))break;t/=16}}return o},xa.tensor=function(a,b){for(var c,d,e=a.length,f=b.length,g=[],h=e-1;h>=0;){c=[],d=a[h];for(var i=f-1;i>=3;)c[i]=d*b[i],--i,c[i]=d*b[i],--i,c[i]=d*b[i],--i,c[i]=d*b[i],--i;for(;i>=0;)c[i]=d*b[i],--i;g[h]=c,h--}return g};var ya=function(a,b,c,d,e,f){this.solution=a,this.value=b,this.gradient=c,this.invHessian=d,this.iterations=e,this.message=f};g["verb.core.MinimizationResult"]=ya,ya.__name__=["verb","core","MinimizationResult"],ya.prototype={__class__:ya};var za=function(){};g["verb.core.ISerializable"]=za,za.__name__=["verb","core","ISerializable"],za.prototype={__class__:za};var Aa=b.core.Deserializer=function(){};g["verb.core.Deserializer"]=Aa,Aa.__name__=["verb","core","Deserializer"],Aa.deserialize=function(a){var b=new u(a),c=b.unserialize();return c};var Ba=b.core.Trig=function(){};g["verb.core.Trig"]=Ba,Ba.__name__=["verb","core","Trig"],Ba.isPointInPlane=function(a,b,c){return Math.abs(Ca.dot(Ca.sub(a,b.origin),b.normal))h},Ba.segmentClosestPoint=function(a,b,c,d,e){var f=Ca.sub(c,b),g=Ca.norm(f);if(gk?{u:d,pt:b}:k>g?{u:e,pt:c}:{u:d+(e-d)*k/g,pt:Ca.add(h,Ca.mul(k,i))}};var Ca=b.core.Vec=function(){};g["verb.core.Vec"]=Ca,Ca.__name__=["verb","core","Vec"],Ca.angleBetween=function(a,b){return Math.acos(Ca.dot(a,b)/(Ca.norm(a)*Ca.norm(b)))},Ca.positiveAngleBetween=function(a,b,c){var d=Ca.cross(a,b),e=Ca.norm(a),f=Ca.norm(b),g=e*f,h=Ca.dot(a,b),i=Ca.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=Ca.dot(c,d);return Math.abs(l)0?k:-k},Ca.signedAngleBetween=function(a,b,c){var d=Ca.cross(a,b),e=Ca.norm(a),f=Ca.norm(b),g=e*f,h=Ca.dot(a,b),i=Ca.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=Ca.dot(c,d);return l>0?k:2*Math.PI-k},Ca.angleBetweenNormalized2d=function(a,b){var c=a[0]*b[1]-a[1]*b[0];return Math.atan2(c,Ca.dot(a,b))},Ca.domain=function(a){return P.last(a)-P.first(a)},Ca.range=function(a){for(var b=[],c=0,d=0;a>d;){d++;b.push(c),c+=1}return b},Ca.span=function(a,b,c){if(null==c)return[];if(cb&&c>0)return[];if(b>a&&0>c)return[];for(var d=[],e=a;b>=e;)d.push(e),e+=c;return d},Ca.neg=function(a){return a.map(function(a){return-a})},Ca.min=function(a){return j.fold(a,function(a,b){return Math.min(a,b)},1/0)},Ca.max=function(a){return j.fold(a,function(a,b){return Math.max(a,b)},-(1/0))},Ca.all=function(a){return j.fold(a,function(a,b){return b&&a},!0)},Ca.finite=function(a){return a.map(function(a){return isFinite(a)})},Ca.onRay=function(a,b,c){return Ca.add(a,Ca.mul(c,b))},Ca.lerp=function(a,b,c){return Ca.add(Ca.mul(a,b),Ca.mul(1-a,c))},Ca.normalized=function(a){return Ca.div(a,Ca.norm(a))},Ca.cross=function(a,b){return[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]},Ca.dist=function(a,b){return Ca.norm(Ca.sub(a,b))},Ca.distSquared=function(a,b){return Ca.normSquared(Ca.sub(a,b))},Ca.sum=function(a){return j.fold(a,function(a,b){return b+a},0)},Ca.addAll=function(a){var b=e(a)();if(!b.hasNext())return null;var c=b.next().length;return j.fold(a,function(a,b){return Ca.add(b,a)},Ca.rep(c,0))},Ca.addAllMutate=function(a){for(var b=a[0],c=1,d=a.length;d>c;){var e=c++;Ca.addMutate(b,a[e])}},Ca.addMulMutate=function(a,b,c){for(var d=0,e=a.length;e>d;){var f=d++;a[f]=a[f]+b*c[f]}},Ca.subMulMutate=function(a,b,c){for(var d=0,e=a.length;e>d;){var f=d++;a[f]=a[f]-b*c[f]}},Ca.addMutate=function(a,b){for(var c=0,d=a.length;d>c;){var e=c++;a[e]=a[e]+b[e]}},Ca.subMutate=function(a,b){for(var c=0,d=a.length;d>c;){var e=c++;a[e]=a[e]-b[e]}},Ca.mulMutate=function(a,b){for(var c=0,d=b.length;d>c;){var e=c++;b[e]=b[e]*a}},Ca.norm=function(a){var b=Ca.normSquared(a);return 0!=b?Math.sqrt(b):b},Ca.normSquared=function(a){return j.fold(a,function(a,b){return b+a*a},0)},Ca.rep=function(a,b){for(var c=[],d=0;a>d;){d++;c.push(b)}return c},Ca.zeros1d=function(a){for(var b=[],c=0;a>c;){c++;b.push(0)}return b},Ca.zeros2d=function(a,b){for(var c=[],d=0;a>d;){d++;c.push(Ca.zeros1d(b))}return c},Ca.zeros3d=function(a,b,c){for(var d=[],e=0;a>e;){e++;d.push(Ca.zeros2d(b,c))}return d},Ca.dot=function(a,b){for(var c=0,d=0,e=a.length;e>d;){var f=d++;c+=a[f]*b[f]}return c},Ca.add=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(a[f]+b[f])}return c},Ca.mul=function(a,b){for(var c=[],d=0,e=b.length;e>d;){var f=d++;c.push(a*b[f])}return c},Ca.div=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(a[f]/b)}return c},Ca.sub=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(a[f]-b[f])}return c},Ca.isZero=function(a){for(var b=0,c=a.length;c>b;){var d=b++;if(Math.abs(a[d])>S.TOLERANCE)return!1}return!0},Ca.sortedSetUnion=function(a,b){for(var c=[],d=0,e=0;d=a.length)c.push(b[e]),e++;else if(e>=b.length)c.push(a[d]),d++;else{var f=a[d]-b[e];Math.abs(f)0?(c.push(b[e]),e++):(c.push(a[d]),d++)}return c},Ca.sortedSetSub=function(a,b){for(var c=[],d=0,e=0;d=b.length?(c.push(a[d]),d++):Math.abs(a[d]-b[e])S.EPSILON&&(c=new Ea(e,0),b.push(c)),c.inc()}return b},Da.isRationalSurfaceClosed=function(a,b){null==b&&(b=!0);var c;c=b?a.controlPoints:ta.transpose(a.controlPoints);for(var d=0,e=c[0].length;e>d;){var f=d++,g=Ca.dist(P.first(c)[f],P.last(c)[f])r;){var t=r++,u=p.points[t],v=Ca.normSquared(Ca.sub(b,u));q>v&&(q=v,e=p.uvs[t])}for(var w=function(b){return Ia.rationalSurfaceDerivatives(a,b[0],b[1],2)},x=function(a,b,c){var d=b[1][0],e=b[0][1],f=b[2][0],g=b[0][2],h=b[1][1],i=b[1][1],j=Ca.dot(d,c),k=Ca.dot(e,c),l=[-j,-k],m=Ca.dot(d,d)+Ca.dot(f,c),n=Ca.dot(d,e)+Ca.dot(h,c),o=Ca.dot(d,e)+Ca.dot(i,c),p=Ca.dot(e,e)+Ca.dot(g,c),q=[[m,n],[o,p]],r=ta.solve(q,l);return Ca.add(r,a)};f>g;){c=w(e),d=Ca.sub(c[0][0],b);var y=Ca.norm(d),z=Ca.dot(c[1][0],d),A=Ca.norm(c[1][0])*y,B=Ca.dot(c[0][1],d),C=Ca.norm(c[0][1])*y,D=z/A,E=B/C,F=h>y,G=i>D,H=i>E;if(F&&G&&H)return e;var I=x(e,c,d);I[0]k&&(I=n?[j+(I[0]-k),I[1]]:[k-S.EPSILON,I[1]]),I[1]m&&(I=o?[I[0],l+(I[0]-m)]:[I[0],m-S.EPSILON]);var J=Ca.norm(Ca.mul(I[0]-e[0],c[1][0])),K=Ca.norm(Ca.mul(I[1]-e[1],c[0][1]));if(h>J+K)return e;e=I,g++}return e},Da.rationalCurveClosestPoint=function(a,b){return Ia.rationalCurvePoint(a,Da.rationalCurveClosestParam(a,b))},Da.rationalCurveClosestParam=function(a,b){for(var c=1/0,d=0,e=Pa.rationalCurveRegularSample(a,a.controlPoints.length*a.degree,!0),f=0,g=e.length-1;g>f;){var h=f++,i=e[h].pop(),j=e[h+1].pop(),k=(e[h],e[h]),l=e[h+1],m=Ba.segmentClosestPoint(b,k,l,i,j),n=Ca.norm(Ca.sub(b,m.pt));c>n&&(c=n,d=m.u)}for(var o,p,q=5,r=0,s=1e-4,t=5e-4,u=a.knots[0],v=P.last(a.knots),w=Ca.normSquared(Ca.sub(a.controlPoints[0],P.last(a.controlPoints)))r;){o=y(x),p=Ca.sub(o[0],b);var A=Ca.norm(p),B=Ca.dot(o[1],p),C=Ca.norm(o[1])*A,D=B/C,E=s>A,F=Math.abs(D)G?G=w?v-(G-u):u:G>v&&(G=w?u+(G-v):v);var H=Ca.norm(Ca.mul(G-x,o[1]));if(s>H)return x;x=G,r++}return x},Da.rationalCurveParamAtArcLength=function(a,b,c,d,e){if(null==c&&(c=.001),bi&&hb)return a.knots[0];var e;if(e=null!=d?d:Da.rationalBezierCurveArcLength(a),b>e)return P.last(a.knots);var f,g=a.knots[0],h=0,i=P.last(a.knots),j=e,k=0,l=0;for(f=null!=c?c:2*S.TOLERANCE;j-h>f;)k=(g+i)/2,l=Da.rationalBezierCurveArcLength(a,k),l>b?(i=k,j=l):(g=k,h=l);return(g+i)/2},Da.rationalCurveArcLength=function(a,b,c){null==c&&(c=16),b=null==b?P.last(a.knots):b;for(var d=La.decomposeCurveIntoBeziers(a),e=0,f=d[0],g=0;ej;){var k=j++;e=g*Da.Tvalues[i][k]+g+a.knots[0],f=Ia.rationalCurveDerivatives(a,e,1),h+=Da.Cvalues[i][k]*Ca.norm(f[1])}return g*h};var Ea=b.eval.KnotMultiplicity=function(a,b){this.knot=a,this.mult=b};g["verb.eval.KnotMultiplicity"]=Ea,Ea.__name__=["verb","eval","KnotMultiplicity"],Ea.prototype={inc:function(){this.mult++},__class__:Ea};var Fa=b.eval.Check=function(){};g["verb.eval.Check"]=Fa,Fa.__name__=["verb","eval","Check"],Fa.isValidKnotVector=function(a,b){if(0==a.length)return!1;if(a.length<2*(b+1))return!1;for(var c=P.first(a),d=0,e=b+1;e>d;){var f=d++;if(Math.abs(a[f]-c)>S.EPSILON)return!1}c=P.last(a);for(var g=a.length-b-1,h=a.length;h>g;){var i=g++;if(Math.abs(a[i]-c)>S.EPSILON)return!1}return Fa.isNonDecreasing(a); +},Fa.isNonDecreasing=function(a){for(var b=P.first(a),c=0,d=a.length;d>c;){var e=c++;if(a[e]i;){i++;h.push(b)}g=h;for(var k=[],l=[],m=Ia.knotSpan(e,b,d),n=null,o=0;og;){g++;f.push(b)}c=f;var i=La.curveKnotRefine(a,c),j=Ia.knotSpan(d,b,e),k=i.knots.slice(0,j+d+2),l=i.knots.slice(j+1),m=i.controlPoints.slice(0,j+1),n=i.controlPoints.slice(j+1);return[new W(d,k,m),new W(d,l,n)]},Ga.rationalCurveByEqualArcLength=function(a,b){var c=Da.rationalCurveArcLength(a),d=c/b;return Ga.rationalCurveByArcLength(a,d)},Ga.rationalCurveByArcLength=function(a,b){var c=La.decomposeCurveIntoBeziers(a),d=c.map(function(a){return Da.rationalBezierCurveArcLength(a)}),e=Ca.sum(d),f=[new Ha(a.knots[0],0)];if(b>e)return f;for(var g,h=b,i=0,j=h,k=0,l=0;ij;){var l=j++;h.push([]);for(var m=0,n=d-l+1;n>m;){for(var o=m++,p=f[l][o],q=1,r=o+1;r>q;){var s=q++;Ca.subMulMutate(p,Q.get(o,s)*g[0][s],h[l][o-s])}for(var t=1,u=l+1;u>t;){var v=t++;Ca.subMulMutate(p,Q.get(l,v)*g[v][0],h[l-v][o]);for(var w=Ca.zeros1d(i),x=1,y=o+1;y>x;){var z=x++;Ca.addMulMutate(w,Q.get(o,z)*g[v][z],h[l-v][o-z])}Ca.subMulMutate(p,Q.get(l,v),w)}Ca.mulMutate(1/g[0][0],p),h[l].push(p)}}return h},Ia.rationalSurfacePoint=function(a,b,c){return Ia.dehomogenize(Ia.surfacePoint(a,b,c))},Ia.rationalCurveDerivatives=function(a,b,c){null==c&&(c=1);for(var d=Ia.curveDerivatives(a,b,c),e=Ia.rational1d(d),f=Ia.weight1d(d),g=[],h=0,i=c+1;i>h;){for(var j=h++,k=e[j],l=1,m=j+1;m>l;){var n=l++;Ca.subMulMutate(k,Q.get(j,n)*f[n],g[j-n])}Ca.mulMutate(1/f[0],k),g.push(k)}return g},Ia.rationalCurvePoint=function(a,b){return Ia.dehomogenize(Ia.curvePoint(a,b))},Ia.surfaceDerivatives=function(a,b,c,d){var e=a.knotsU.length-a.degreeU-2,f=a.knotsV.length-a.degreeV-2;return Ia.surfaceDerivativesGivenNM(e,f,a,b,c,d)},Ia.surfaceDerivativesGivenNM=function(a,b,c,d,e,f){var g=c.degreeU,h=c.degreeV,i=c.controlPoints,j=c.knotsU,k=c.knotsV;if(!Ia.areValidRelations(g,i.length,j.length)||!Ia.areValidRelations(h,i[0].length,k.length))throw new C("Invalid relations between control points, knot vector, and n");var l,m=i[0][0].length;l=g>f?f:g;var n;n=h>f?f:h;for(var o=Ca.zeros3d(l+1,n+1,m),p=Ia.knotSpanGivenN(a,g,d,j),q=Ia.knotSpanGivenN(b,h,e,k),r=Ia.derivativeBasisFunctionsGivenNI(p,d,g,a,j),s=Ia.derivativeBasisFunctionsGivenNI(q,e,h,b,k),t=Ca.zeros2d(h+1,m),u=0,v=0,w=l+1;w>v;){for(var x=v++,y=0,z=h+1;z>y;){var A=y++;t[A]=Ca.zeros1d(m);for(var B=0,D=g+1;D>B;){var E=B++;Ca.addMulMutate(t[A],r[x][E],i[p-g+E][q-h+A])}}var F=f-x;u=n>F?F:n;for(var G=0,H=u+1;H>G;){var I=G++;o[x][I]=Ca.zeros1d(m);for(var J=0,K=h+1;K>J;){var L=J++;Ca.addMulMutate(o[x][I],s[I][L],t[L])}}}return o},Ia.surfacePoint=function(a,b,c){var d=a.knotsU.length-a.degreeU-2,e=a.knotsV.length-a.degreeV-2;return Ia.surfacePointGivenNM(d,e,a,b,c)},Ia.surfacePointGivenNM=function(a,b,c,d,e){var f=c.degreeU,g=c.degreeV,h=c.controlPoints,i=c.knotsU,j=c.knotsV;if(!Ia.areValidRelations(f,h.length,i.length)||!Ia.areValidRelations(g,h[0].length,j.length))throw new C("Invalid relations between control points, knot vector, and n");for(var k=h[0][0].length,l=Ia.knotSpanGivenN(a,f,d,i),m=Ia.knotSpanGivenN(b,g,e,j),n=Ia.basisFunctionsGivenKnotSpanIndex(l,d,f,i),o=Ia.basisFunctionsGivenKnotSpanIndex(m,e,g,j),p=l-f,q=m,r=Ca.zeros1d(k),s=Ca.zeros1d(k),t=0,u=g+1;u>t;){var v=t++;s=Ca.zeros1d(k),q=m-g+v;for(var w=0,x=f+1;x>w;){var y=w++;Ca.addMulMutate(s,n[y],h[p+y][q])}Ca.addMulMutate(r,o[v],s)}return r},Ia.rationalSurfaceRegularSampleDerivatives=function(a,b,c,d){for(var e=Ia.surfaceRegularSampleDerivatives(a,b,c,d),f=[],g=b+1,h=c+1,i=d+1,j=0;g>j;){var k=j++,l=[];f.push(l);for(var m=0;h>m;){for(var n=m++,o=e[k][n],p=Ia.rational2d(o),q=Ia.weight2d(o),r=[],s=p[0][0].length,t=0;i>t;){var u=t++;r.push([]);for(var v=0,w=i-u;w>v;){for(var x=v++,y=p[u][x],z=1,A=x+1;A>z;){var B=z++;Ca.subMulMutate(y,Q.get(x,B)*q[0][B],r[u][x-B])}for(var C=1,D=u+1;D>C;){var E=C++;Ca.subMulMutate(y,Q.get(u,E)*q[E][0],r[u-E][x]);for(var F=Ca.zeros1d(s),G=1,H=x+1;H>G;){var I=G++;Ca.addMulMutate(F,Q.get(x,I)*q[E][I],r[u-E][x-I])}Ca.subMulMutate(y,Q.get(u,E),F)}Ca.mulMutate(1/q[0][0],y),r[u].push(y)}}l.push(r)}}return f},Ia.surfaceRegularSampleDerivatives=function(a,b,c,d){for(var e=a.degreeU,f=a.degreeV,g=a.controlPoints,h=a.knotsU,i=a.knotsV,j=g[0][0].length,k=((P.last(h)-h[0])/b,(P.last(i)-i[0])/c,Ia.regularlySpacedDerivativeBasisFunctions(e,h,b)),l=k.item0,m=k.item1,n=Ia.regularlySpacedDerivativeBasisFunctions(f,i,c),o=n.item0,p=n.item1,q=[],r=b+1,s=c+1,t=0;r>t;){var u=t++,v=[];q.push(v);for(var w=0;s>w;){var x=w++;v.push(Ia.surfaceDerivativesGivenBasesKnotSpans(e,f,g,l[u],o[x],m[u],p[x],j,d))}}return q},Ia.regularlySpacedBasisFunctions=function(a,b,c){for(var d=b.length-a-2,e=(P.last(b)-b[0])/c,f=[],g=[],h=b[0],i=Ia.knotSpanGivenN(d,a,h,b),j=c+1,k=0;j>k;){for(k++;h>=b[i+1];)i++;g.push(i),f.push(Ia.basisFunctionsGivenKnotSpanIndex(i,h,a,b)),h+=e}return new _(g,f)},Ia.regularlySpacedDerivativeBasisFunctions=function(a,b,c){for(var d=b.length-a-2,e=(P.last(b)-b[0])/c,f=[],g=[],h=b[0],i=Ia.knotSpanGivenN(d,a,h,b),j=c+1,k=0;j>k;){for(k++;h>=b[i+1];)i++;g.push(i),f.push(Ia.derivativeBasisFunctionsGivenNI(i,h,a,d,b)),h+=e}return new _(g,f)},Ia.surfacePointGivenBasesKnotSpans=function(a,b,c,d,e,f,g,h){for(var i,j=Ca.zeros1d(h),k=d-a,l=e-b,m=0,n=b+1;n>m;){var o=m++;i=Ca.zeros1d(h);for(var p=0,q=a+1;q>p;){var r=p++;Ca.addMulMutate(i,f[r],c[k+r][l])}l++,Ca.addMulMutate(j,g[o],i)}return j},Ia.surfaceDerivativesGivenBasesKnotSpans=function(a,b,c,d,e,f,g,h,i){var j,k=c[0][0].length;j=a>i?i:a;var l;l=b>i?i:b;for(var m=Ca.zeros3d(j+1,l+1,k),n=Ca.zeros2d(b+1,k),o=0,p=0,q=j+1;q>p;){for(var r=p++,s=0,t=b+1;t>s;){var u=s++;n[u]=Ca.zeros1d(k);for(var v=0,w=a+1;w>v;){var x=v++;Ca.addMulMutate(n[u],f[r][x],c[d-a+x][e-b+u])}}var y=i-r;o=l>y?y:l;for(var z=0,A=o+1;A>z;){var B=z++;m[r][B]=Ca.zeros1d(k);for(var C=0,D=b+1;D>C;){var E=C++;Ca.addMulMutate(m[r][B],g[B][E],n[E])}}}return m},Ia.curveDerivatives=function(a,b,c){var d=a.knots.length-a.degree-2;return Ia.curveDerivativesGivenN(d,a,b,c)},Ia.curveDerivativesGivenN=function(a,b,c,d){var e=b.degree,f=b.controlPoints,g=b.knots;if(!Ia.areValidRelations(e,f.length,g.length))throw new C("Invalid relations between control points, knot vector, and n");var h,i=f[0].length;h=e>d?d:e;for(var j=Ca.zeros2d(h+1,i),k=Ia.knotSpanGivenN(a,e,c,g),l=Ia.derivativeBasisFunctionsGivenNI(k,c,e,h,g),m=0,n=h+1;n>m;)for(var o=m++,p=0,q=e+1;q>p;){var r=p++;Ca.addMulMutate(j[o],l[o][r],f[k-e+r])}return j},Ia.curvePoint=function(a,b){var c=a.knots.length-a.degree-2;return Ia.curvePointGivenN(c,a,b)},Ia.areValidRelations=function(a,b,c){return b+a+1-c==0},Ia.curvePointGivenN=function(a,b,c){var d=b.degree,e=b.controlPoints,f=b.knots;if(!Ia.areValidRelations(d,e.length,f.length))throw new C("Invalid relations between control points, knot Array, and n");for(var g=Ia.knotSpanGivenN(a,d,c,f),h=Ia.basisFunctionsGivenKnotSpanIndex(g,c,d,f),i=Ca.zeros1d(e[0].length),j=0,k=d+1;k>j;){var l=j++;Ca.addMulMutate(i,h[l],e[g-d+l])}return i},Ia.volumePoint=function(a,b,c,d){var e=a.knotsU.length-a.degreeU-2,f=a.knotsV.length-a.degreeV-2,g=a.knotsW.length-a.degreeW-2;return Ia.volumePointGivenNML(a,e,f,g,b,c,d)},Ia.volumePointGivenNML=function(a,b,c,d,e,f,g){if(!Ia.areValidRelations(a.degreeU,a.controlPoints.length,a.knotsU.length)||!Ia.areValidRelations(a.degreeV,a.controlPoints[0].length,a.knotsV.length)||!Ia.areValidRelations(a.degreeW,a.controlPoints[0][0].length,a.knotsW.length))throw new C("Invalid relations between control points and knot vector");for(var h=a.controlPoints,i=a.degreeU,j=a.degreeV,k=a.degreeW,l=a.knotsU,m=a.knotsV,n=a.knotsW,o=h[0][0][0].length,p=Ia.knotSpanGivenN(b,i,e,l),q=Ia.knotSpanGivenN(c,j,f,m),r=Ia.knotSpanGivenN(d,k,g,n),s=Ia.basisFunctionsGivenKnotSpanIndex(p,e,i,l),t=Ia.basisFunctionsGivenKnotSpanIndex(q,f,j,m),u=Ia.basisFunctionsGivenKnotSpanIndex(r,g,k,n),v=p-i,w=Ca.zeros1d(o),x=Ca.zeros1d(o),y=Ca.zeros1d(o),z=0,A=k+1;A>z;){var B=z++;y=Ca.zeros1d(o);for(var D=r-k+B,E=0,F=j+1;F>E;){var G=E++;x=Ca.zeros1d(o);for(var H=q-j+G,I=0,J=i+1;J>I;){var K=I++;Ca.addMulMutate(x,s[K],h[v+K][H][D])}Ca.addMulMutate(y,t[G],x)}Ca.addMulMutate(w,u[B],y)}return w},Ia.derivativeBasisFunctions=function(a,b,c){var d=Ia.knotSpan(b,a,c),e=c.length-1,f=e-b-1;return Ia.derivativeBasisFunctionsGivenNI(d,a,b,f,c)},Ia.derivativeBasisFunctionsGivenNI=function(a,b,c,d,e){var f=Ca.zeros2d(c+1,c+1),g=Ca.zeros1d(c+1),h=Ca.zeros1d(c+1),i=0,j=0;f[0][0]=1;for(var k=1,l=c+1;l>k;){var m=k++;g[m]=b-e[a+1-m],h[m]=e[a+m]-b,i=0;for(var n=0;m>n;){var o=n++;f[m][o]=h[o+1]+g[m-o],j=f[o][m-1]/f[m][o],f[o][m]=i+h[o+1]*j,i=g[m-o]*j}f[m][m]=i}for(var p=Ca.zeros2d(d+1,c+1),q=Ca.zeros2d(2,c+1),r=0,s=1,t=0,u=0,v=0,w=0,x=0,y=0,z=c+1;z>y;){var A=y++;p[0][A]=f[A][c]}for(var B=0,C=c+1;C>B;){var D=B++;r=0,s=1,q[0][0]=1;for(var E=1,F=d+1;F>E;){var G=E++;t=0,u=D-G,v=c-G,D>=G&&(q[s][0]=q[r][0]/f[v+1][u],t=q[s][0]*f[u][v]),w=u>=-1?1:-u,x=v>=D-1?G-1:c-D;for(var H=w,I=x+1;I>H;){var J=H++;q[s][J]=(q[r][J]-q[r][J-1])/f[v+1][u+J],t+=q[s][J]*f[u+J][v]}v>=D&&(q[s][G]=-q[r][G-1]/f[v+1][D],t+=q[s][G]*f[D][v]),p[G][D]=t;var K=r;r=s,s=K}}for(var L=c,M=1,N=d+1;N>M;){for(var O=M++,P=0,Q=c+1;Q>P;){var R=P++;p[O][R]*=L}L*=c-O}return p},Ia.basisFunctions=function(a,b,c){var d=Ia.knotSpan(b,a,c);return Ia.basisFunctionsGivenKnotSpanIndex(d,a,b,c)},Ia.basisFunctionsGivenKnotSpanIndex=function(a,b,c,d){var e=Ca.zeros1d(c+1),f=Ca.zeros1d(c+1),g=Ca.zeros1d(c+1),h=0,i=0;e[0]=1;for(var j=1,k=c+1;k>j;){var l=j++;f[l]=b-d[a+1-l],g[l]=d[a+l]-b,h=0;for(var m=0;l>m;){var n=m++;i=e[n]/(g[n+1]+f[l-n]),e[n]=h+g[n+1]*i,h=f[l-n]*i}e[l]=h}return e},Ia.knotSpan=function(a,b,c){return Ia.knotSpanGivenN(c.length-a-2,a,b,c)},Ia.knotSpanGivenN=function(a,b,c,d){if(c>d[a+1]-S.EPSILON)return a;if(c=d[g+1];)cf;){var g=f++;c.push(a[g]/d)}return c},Ia.rational1d=function(a){var b=a[0].length-1;return a.map(function(a){return a.slice(0,b)})},Ia.rational2d=function(a){return a.map(Ia.rational1d)},Ia.weight1d=function(a){var b=a[0].length-1;return a.map(function(a){return a[b]})},Ia.weight2d=function(a){return a.map(Ia.weight1d)},Ia.dehomogenize1d=function(a){return a.map(Ia.dehomogenize)},Ia.dehomogenize2d=function(a){return a.map(Ia.dehomogenize1d)},Ia.homogenize1d=function(a,b){var c,d=a.length,e=a[0].length,f=[],g=0,h=[];c=null!=b?b:Ca.rep(a.length,1);for(var i=0;d>i;){var j=i++,k=[];h=a[j],g=c[j];for(var l=0;e>l;){var m=l++;k.push(h[m]*g)}k.push(g),f.push(k)}return f},Ia.homogenize2d=function(a,b){var c,d=a.length,e=[];if(null!=b)c=b;else{for(var f=[],g=0;d>g;){g++;f.push(Ca.rep(a[0].length,1))}c=f}for(var h=0;d>h;){var i=h++;e.push(Ia.homogenize1d(a[i],c[i]))}return e};var Ja=b.eval.Intersect=function(){};g["verb.eval.Intersect"]=Ja,Ja.__name__=["verb","eval","Intersect"],Ja.surfaces=function(a,b,c){var d=Pa.rationalSurfaceAdaptive(a),e=Pa.rationalSurfaceAdaptive(b),f=Ja.meshes(d,e),g=f.map(function(d){return d.map(function(d){return Ja.surfacesAtPointWithEstimate(a,b,d.uv0,d.uv1,c)})});return g.map(function(a){return Ka.rationalInterpCurve(a.map(function(a){return a.point}),3)})},Ja.surfacesAtPointWithEstimate=function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s=5,t=0;do{if(f=Ia.rationalSurfaceDerivatives(a,c[0],c[1],1),g=f[0][0],i=f[1][0],j=f[0][1],h=Ca.normalized(Ca.cross(i,j)),k=Ca.dot(h,g),l=Ia.rationalSurfaceDerivatives(b,d[0],d[1],1),m=l[0][0],o=l[1][0],p=l[0][1],n=Ca.normalized(Ca.cross(o,p)),q=Ca.dot(n,m),r=Ca.distSquared(g,m),e*e>r)break;var u=Ca.normalized(Ca.cross(h,n)),v=Ca.dot(u,g),w=Ja.threePlanes(h,k,n,q,u,v);if(null==w)throw new C("panic!");var x=Ca.sub(w,g),y=Ca.sub(w,m),z=Ca.cross(i,h),A=Ca.cross(j,h),B=Ca.cross(o,n),D=Ca.cross(p,n),E=Ca.dot(A,x)/Ca.dot(A,i),F=Ca.dot(z,x)/Ca.dot(z,j),G=Ca.dot(D,y)/Ca.dot(D,o),H=Ca.dot(B,y)/Ca.dot(B,p);c=Ca.add([E,F],c),d=Ca.add([G,H],d),t++}while(s>t);return new fa(c,d,g,r)},Ja.meshes=function(a,b,c,d){null==c&&(c=new qa(a)),null==d&&(d=new qa(b));var e=Ja.boundingBoxTrees(c,d,0),f=P.unique(e.map(function(c){return Ja.triangles(a,c.item0,b,c.item1)}).filter(function(a){return null!=a}).filter(function(a){return Ca.distSquared(a.min.point,a.max.point)>S.EPSILON}),function(a,b){var c=Ca.sub(a.min.uv0,b.min.uv0),d=Ca.dot(c,c),e=Ca.sub(a.max.uv0,b.max.uv0),f=Ca.dot(e,e),g=Ca.sub(a.min.uv0,b.max.uv0),h=Ca.dot(g,g),i=Ca.sub(a.max.uv0,b.min.uv0),j=Ca.dot(i,i);return d0&&(p.push(p[p.length-1].opp),l.push(p))}if(0==k.length&&e.length>0&&(n||m0;){var g=d.pop(),h=e.pop();if(!g.empty()&&!h.empty()&&g.boundingBox().intersects(h.boundingBox(),c)){var i=g.indivisible(c),j=h.indivisible(c);if(i&&j)f.push(new _(g["yield"](),h["yield"]()));else if(!i||j)if(i||!j){var k=g.split(),l=h.split();d.push(k.item1),e.push(l.item1),d.push(k.item1),e.push(l.item0),d.push(k.item0),e.push(l.item1),d.push(k.item0),e.push(l.item0)}else{var m=g.split();d.push(m.item1),e.push(h),d.push(m.item0),e.push(h)}else{var n=h.split();d.push(g),e.push(n.item1),d.push(g),e.push(n.item0)}}}return f},Ja.curves=function(a,b,c){var d=Ja.boundingBoxTrees(new pa(a),new pa(b),0);return P.unique(d.map(function(d){return Ja.curvesWithEstimate(a,b,P.first(d.item0.knots),P.first(d.item1.knots),c)}).filter(function(a){return Ca.distSquared(a.point0,a.point1)m;){var n=m++,o=e[n],p=i[n],q=Ja.rays(o,p,a.origin,a.dir);if(null!=q){var r=q.u0,s=q.u1;r<-S.EPSILON||r>j[n]+S.EPSILON||((null==k||sl.u)&&(l=new ha(s,Ca.onRay(a.origin,a.dir,s),Ca.onRay(f[n],g[n],r/j[n]))))}}return null==l||null==k?null:new aa(k,l)},Ja.mergeTriangleClipIntervals=function(a,b,c,d,e,f){if(b.min.u>a.max.u+S.EPSILON||a.min.u>b.max.u+S.EPSILON)return null;var g;g=a.min.u>b.min.u?new _(a.min,0):new _(b.min,1);var h;h=a.max.ug&&(f=1,g=h),i>g&&(f=2,g=i);var j,k,l,m;0==f?(j=b[1],k=b[2],l=d[1],m=d[2]):1==f?(j=b[0],k=b[2],l=d[0],m=d[2]):(j=b[0],k=b[1],l=d[0],m=d[1]);var n,o=-Ca.dot(a,b),p=-Ca.dot(c,d),q=j*m-k*l,r=(k*p-o*m)/q,s=(o*l-j*p)/q;return n=0==f?[0,r,s]:1==f?[r,0,s]:[r,s,0],new V(n,Ca.normalized(e))},Ja.threePlanes=function(a,b,c,d,e,f){var g=Ca.cross(c,e),h=Ca.dot(a,g);if(Math.abs(h)q)return new ba(o,p,m,n)}return null},Ja.rays=function(a,b,c,d){var e=Ca.dot(b,d),f=Ca.dot(b,c),g=Ca.dot(b,a),h=Ca.dot(d,c),i=Ca.dot(d,a),j=Ca.dot(b,b),k=Ca.dot(d,d),l=j*k-e*e;if(Math.abs(l)o||o>1)return null;var p=Ca.add(a,Ca.mul(o,k)),q=Ca.dot(h,i),r=Ca.dot(h,h),s=Ca.dot(i,i),t=Ca.sub(p,e),u=Ca.dot(t,h),v=Ca.dot(t,i),w=q*q-r*s;if(Math.abs(w)1+S.EPSILON||y>1+S.EPSILON||y<-S.EPSILON||x<-S.EPSILON||x+y>1+S.EPSILON?null:new ga(p,x,y,o)},Ja.segmentAndPlane=function(a,b,c,d){var e=Ca.dot(d,Ca.sub(b,a));if(Math.abs(e)1+S.EPSILON||g<-S.EPSILON?null:{p:g}};var Ka=b.eval.Make=function(){};g["verb.eval.Make"]=Ka,Ka.__name__=["verb","eval","Make"],Ka.rationalTranslationalSurface=function(a,b){for(var c=Ia.rationalCurvePoint(b,P.first(b.knots)),d=P.first(b.knots),e=P.last(b.knots),f=2*b.controlPoints.length,g=(e-d)/(f-1),h=[],i=0;f>i;){var j=i++,k=Ca.sub(Ia.rationalCurvePoint(b,d+j*g),c),l=La.rationalCurveTransform(a,[[1,0,0,k[0]],[0,1,0,k[1]],[0,0,1,k[2]],[0,0,0,1]]);h.push(l)}return Ka.loftedSurface(h)},Ka.surfaceBoundaryCurves=function(a){var b=Ka.surfaceIsocurve(a,P.first(a.knotsU),!1),c=Ka.surfaceIsocurve(a,P.last(a.knotsU),!1),d=Ka.surfaceIsocurve(a,P.first(a.knotsV),!0),e=Ka.surfaceIsocurve(a,P.last(a.knotsV),!0);return[b,c,d,e]},Ka.surfaceIsocurve=function(a,b,c){null==c&&(c=!1);var d;d=c?a.knotsV:a.knotsU;var e;e=c?a.degreeV:a.degreeU;for(var f=Da.knotMultiplicities(d),g=-1,h=0,i=f.length;i>h;){var j=h++;if(Math.abs(b-f[j].knot)=0&&(k-=f[g].mult);var l;l=k>0?La.surfaceKnotRefine(a,Ca.rep(k,b),c):a;var m=Ia.knotSpan(e,b,d);return Math.abs(b-P.first(d))a.length-1&&(b=a.length-1);for(var d=a[0].knots,e=[],f=[],g=0,h=a[0].controlPoints.length;h>g;){var i=[g++],j=a.map(function(a){return function(b){return b.controlPoints[a[0]]}}(i)),k=Ka.rationalInterpCurve(j,b,!0);f.push(k.controlPoints),e=k.knots}return new X(c,b,d,e,f)},Ka.clonedCurve=function(a){return new W(a.degree,a.knots.slice(),a.controlPoints.map(function(a){return a.slice()}))},Ka.clonedSurface=function(a){for(var b,c=[],d=0,e=a.controlPoints;de;){e++;d.push(0)}for(var g=0,h=c+1;h>g;){g++;d.push(1)}return null==b&&(b=Ca.rep(a.length,1)),new W(c,d,Ia.homogenize1d(a,b))},Ka.fourPointSurface=function(a,b,c,d,e){null==e&&(e=3);for(var f=e,g=[],h=0,i=e+1;i>h;){for(var j=h++,k=[],l=0,m=e+1;m>l;){var n=l++,o=1-j/f,p=Ca.lerp(o,a,b),q=Ca.lerp(o,d,c),r=Ca.lerp(1-n/f,p,q);r.push(1),k.push(r)}g.push(k)}var s=Ca.rep(e+1,0),t=Ca.rep(e+1,1);return new X(e,e,s.concat(t),s.concat(t),g)},Ka.ellipseArc=function(a,b,c,d,e){var f=Ca.norm(b),g=Ca.norm(c);b=Ca.normalized(b),c=Ca.normalized(c),d>e&&(e=2*Math.PI+d);var h=e-d,i=0;i=h<=Math.PI/2?1:h<=Math.PI?2:h<=3*Math.PI/2?3:4;var j=h/i,k=Math.cos(j/2),l=Ca.add(a,Ca.add(Ca.mul(f*Math.cos(d),b),Ca.mul(g*Math.sin(d),c))),m=Ca.sub(Ca.mul(Math.cos(d),c),Ca.mul(Math.sin(d),b)),n=[],o=Ca.zeros1d(2*i+3),p=0,q=d,r=Ca.zeros1d(2*i);n[0]=l,r[0]=1;for(var s=1,t=i+1;t>s;){var u=s++;q+=j;var v=Ca.add(a,Ca.add(Ca.mul(f*Math.cos(q),b),Ca.mul(g*Math.sin(q),c)));r[p+2]=1,n[p+2]=v;var w=Ca.sub(Ca.mul(Math.cos(q),c),Ca.mul(Math.sin(q),b)),x=Ja.rays(l,Ca.mul(1/Ca.norm(m),m),v,Ca.mul(1/Ca.norm(w),w)),y=Ca.add(l,Ca.mul(x.u0,m));r[p+1]=k,n[p+1]=y,p+=2,i>u&&(l=v,m=w)}for(var z=2*i+1,A=0;3>A;){var B=A++;o[B]=0,o[B+z]=1}switch(i){case 2:o[3]=o[4]=.5;break;case 3:o[3]=o[4]=.3333333333333333,o[5]=o[6]=.6666666666666666;break;case 4:o[3]=o[4]=.25,o[5]=o[6]=.5,o[7]=o[8]=.75}return new W(2,o,Ia.homogenize1d(n,r))},Ka.arc=function(a,b,c,d,e,f){return Ka.ellipseArc(a,Ca.mul(d,Ca.normalized(b)),Ca.mul(d,Ca.normalized(c)),e,f)},Ka.polyline=function(a){for(var b=[0,0],c=0,d=0,e=a.length-1;e>d;){var f=d++;c+=Ca.dist(a[f],a[f+1]),b.push(c)}b.push(c),b=Ca.mul(1/c,b);for(var g,h=[],i=0,j=a.length;j>i;){i++;h.push(1)}return g=h,new W(1,b,Ia.homogenize1d(a.slice(0),g))},Ka.extrudedSurface=function(a,b,c){for(var d=[[],[],[]],e=[[],[],[]],f=Ia.dehomogenize1d(c.controlPoints),g=Ia.weight1d(c.controlPoints),h=Ca.mul(b,a),i=Ca.mul(.5*b,a),j=0,k=f.length;k>j;){var l=j++;d[2][l]=f[l],d[1][l]=Ca.add(i,f[l]),d[0][l]=Ca.add(h,f[l]),e[0][l]=g[l],e[1][l]=g[l],e[2][l]=g[l]}return new X(2,c.degree,[0,0,0,1,1,1],c.knots,Ia.homogenize2d(d,e))},Ka.cylindricalSurface=function(a,b,c,d,e){var f=Ca.cross(a,b),g=(2*Math.PI,Ka.arc(c,b,f,e,0,2*Math.PI));return Ka.extrudedSurface(a,d,g)},Ka.revolvedSurface=function(a,b,c,d){var e,f,g=Ia.dehomogenize1d(a.controlPoints),h=Ia.weight1d(a.controlPoints);d<=Math.PI/2?(e=1,f=Ca.zeros1d(6+2*(e-1))):d<=Math.PI?(e=2,f=Ca.zeros1d(6+2*(e-1)),f[3]=f[4]=.5):d<=3*Math.PI/2?(e=3,f=Ca.zeros1d(6+2*(e-1)),f[3]=f[4]=.3333333333333333,f[5]=f[6]=.6666666666666666):(e=4,f=Ca.zeros1d(6+2*(e-1)),f[3]=f[4]=.25,f[5]=f[6]=.5,f[7]=f[8]=.75);for(var i=d/e,j=3+2*(e-1),k=0;3>k;){var l=k++;f[l]=0,f[j+l]=1}for(var m=Math.cos(i/2),n=0,o=Ca.zeros1d(e+1),p=Ca.zeros1d(e+1),q=Ca.zeros3d(2*e+1,g.length,3),r=Ca.zeros2d(2*e+1,g.length),s=1,t=e+1;t>s;){var u=s++;n+=i,p[u]=Math.cos(n),o[u]=Math.sin(n)}for(var v=0,w=g.length;w>v;){var x=v++,y=Ba.rayClosestPoint(g[x],b,c),z=Ca.sub(g[x],y),A=Ca.norm(z),B=Ca.cross(c,z);A>S.EPSILON&&(z=Ca.mul(1/A,z),B=Ca.mul(1/A,B)),q[0][x]=g[x];var C=g[x];r[0][x]=h[x];for(var D=B,E=0,F=1,G=e+1;G>F;){var H,I=F++;H=0==A?y:Ca.add(y,Ca.add(Ca.mul(A*p[I],z),Ca.mul(A*o[I],B))),q[E+2][x]=H,r[E+2][x]=h[x];var J=Ca.sub(Ca.mul(p[I],B),Ca.mul(o[I],z));if(0==A)q[E+1][x]=y;else{var K=Ja.rays(C,Ca.mul(1/Ca.norm(D),D),H,Ca.mul(1/Ca.norm(J),J)),L=Ca.add(C,Ca.mul(K.u0,D));q[E+1][x]=L}r[E+1][x]=m*h[x],E+=2,e>I&&(C=H,D=J)}}return new X(2,a.degree,f,a.knots,Ia.homogenize2d(q,r))},Ka.sphericalSurface=function(a,b,c,d){var e=Ka.arc(a,Ca.mul(-1,b),c,d,0,Math.PI);return Ka.revolvedSurface(e,a,b,2*Math.PI)},Ka.conicalSurface=function(a,b,c,d,e){var f=2*Math.PI,g=1,h=[Ca.add(c,Ca.mul(d,a)),Ca.add(c,Ca.mul(e,b))],i=[0,0,1,1],j=[1,1],k=new W(g,i,Ia.homogenize1d(h,j));return Ka.revolvedSurface(k,c,a,f)},Ka.rationalInterpCurve=function(a,b,c,d,e){if(null==c&&(c=!1),null==b&&(b=3),a.lengthg;){var i=g++,j=Ca.norm(Ca.sub(a[i],a[i-1])),k=f[f.length-1];f.push(k+j)}for(var l=f[f.length-1],m=0,n=f.length;n>m;){var o=m++;f[o]=f[o]/l}var p,q=Ca.rep(b+1,0),r=null!=d&&null!=e;p=r?0:1;var s;s=r?f.length-b+1:f.length-b;for(var t=p;s>t;){for(var u=t++,v=0,w=0;b>w;){var x=w++;v+=f[u+x]}q.push(1/b*v)}var y,z=q.concat(Ca.rep(b+1,1)),A=[];y=r?a.length+1:a.length-1;var B;B=r?1:0;var D;D=r?a.length-(b-1):a.length-(b+1);for(var E=0;ET;){var U,V=[T++];if(r){U=[a[0][V[0]]],U.push(S*d[V[0]]);for(var X=1,Y=a.length-1;Y>X;){var Z=X++;U.push(a[Z][V[0]])}U.push(R*e[V[0]]),U.push(P.last(a)[V[0]])}else U=a.map(function(a){return function(b){return b[a[0]]}}(V));var $=ta.solve(A,U);Q.push($)}var _=ta.transpose(Q);if(!c){var aa=Ca.rep(_.length,1);_=Ia.homogenize1d(_,aa)}return new W(b,z,_)};var La=b.eval.Modify=function(){};g["verb.eval.Modify"]=La,La.__name__=["verb","eval","Modify"],La.curveReverse=function(a){return new W(a.degree,La.knotsReverse(a.knots),P.reversed(a.controlPoints))},La.surfaceReverse=function(a,b){return null==b&&(b=!1),b?new X(a.degreeU,a.degreeV,a.knotsU,La.knotsReverse(a.knotsV),function(b){for(var c,d=[],e=0,f=a.controlPoints;ee;){var f=e++;c.push(c[f-1]+(a[d-f]-a[d-f-1]))}return c},La.unifyCurveKnotVectors=function(a){a=a.map(Ka.clonedCurve);for(var b=j.fold(a,function(a,b){return La.imax(a.degree,b)},0),c=0,d=a.length;d>c;){var e=c++;a[e].degreek;){var m=k++,n=[f[m].min];a[m].knots=a[m].knots.map(function(a){return function(b){return b-a[0]}}(n))}for(var o=f.map(function(a){return a.max-a.min}),p=j.fold(o,function(a,b){return Math.max(a,b)},0),q=0,r=a.length;r>q;){var s=q++,t=[p/o[s]];a[s].knots=a[s].knots.map(function(a){return function(b){return b*a[0]}}(t))}for(var u=j.fold(a,function(a,b){return Ca.sortedSetUnion(a.knots,b)},[]),v=0,w=a.length;w>v;){var x=v++,y=Ca.sortedSetSub(u,a[x].knots);0==y.length&&(a[x]=a[x]),a[x]=La.curveKnotRefine(a[x],y)}return a},La.imin=function(a,b){return b>a?a:b},La.imax=function(a,b){return a>b?a:b},La.curveElevateDegree=function(a,b){if(b<=a.degree)return a;var c,d=a.knots.length-a.degree-2,e=a.degree,f=a.knots,g=a.controlPoints,h=b-a.degree,i=a.controlPoints[0].length,j=Ca.zeros2d(e+h+1,e+1),k=[],l=[],m=[],n=d+e+1,o=b,p=Math.floor(o/2),q=[],r=[];j[0][0]=1,j[o][e]=1;for(var s=1,t=p+1;t>s;)for(var u=s++,v=1/Q.get(o,u),w=La.imin(e,u),x=La.imax(0,u-h),y=w+1;y>x;){var z=x++;j[u][z]=v*Q.get(e,z)*Q.get(h,u-z)}for(var A=p+1;o>A;)for(var B=A++,C=La.imin(e,B),D=La.imax(0,B-h),E=C+1;E>D;){var F=D++;j[B][F]=j[o-B][e-F]}var G=o,H=o+1,I=-1,J=e,K=e+1,L=1,M=f[0];q[0]=g[0];for(var N=0,O=o+1;O>N;){var P=N++;r[P]=M}for(var R=0,S=e+1;S>R;){var T=R++;k[T]=g[T]}for(;n>K;){for(var U=K;n>K&&f[K]==f[K+1];)K+=1;var V=K-U+1,X=f[K],Y=I;I=e-V;var Z;Z=Y>0?Math.floor((Y+2)/2):1;var $;if($=I>0?Math.floor(o-(I+1)/2):o,I>0){for(var _=X-M,aa=[],ba=e;ba>V;)aa[ba-V-1]=_/(f[J+ba]-M),ba--;for(var ca=1,da=I+1;da>ca;){for(var ea=ca++,fa=I-ea,ga=V+ea,ha=e;ha>=ga;)k[ha]=Ca.add(Ca.mul(aa[ha-ga],k[ha]),Ca.mul(1-aa[ha-ga],k[ha-1])),ha--;m[fa]=k[e]}}for(var ia=Z,ja=o+1;ja>ia;){var ka=ia++;l[ka]=Ca.zeros1d(i);for(var la=La.imin(e,ka),ma=La.imax(0,ka-h),na=la+1;na>ma;){var oa=ma++;l[ka]=Ca.add(l[ka],Ca.mul(j[ka][oa],k[oa]))}}if(Y>1)for(var pa=H-2,qa=H,ra=X-M,sa=(X-r[H-1])/ra,ta=1;Y>ta;){for(var ua=ta++,va=pa,wa=qa,xa=wa-H+1;wa-va>ua;){if(L>va){var ya=(X-r[va])/(M-r[va]);q[va]=Ca.lerp(ya,q[va],q[va-1])}if(wa>=Z){if(H-o+Y>=wa-ua){var za=(X-r[wa-ua])/ra;l[xa]=Ca.lerp(za,l[xa],l[xa+1])}}else l[xa]=Ca.lerp(sa,l[xa],l[xa+1]);va+=1,wa-=1,xa-=1}pa-=1,qa+=1}if(J!=e)for(var Aa=0,Ba=o-Y;Ba>Aa;){Aa++;r[H]=M,H+=1}for(var Da=Z,Ea=$+1;Ea>Da;){var Fa=Da++;q[L]=l[Fa],L+=1}if(n>K){for(var Ga=0;I>Ga;){var Ha=Ga++;k[Ha]=m[Ha]}for(var Ia=I,Ja=e+1;Ja>Ia;){var Ka=Ia++;k[Ka]=g[K-e+Ka]}J=K,K+=1,M=X}else for(var Ma=0,Na=o+1;Na>Ma;){var Oa=Ma++;r[H+Oa]=X}}return c=G-o-1,new W(b,r,q)},La.rationalSurfaceTransform=function(a,b){for(var c=Ia.dehomogenize2d(a.controlPoints),d=0,e=c.length;e>d;)for(var f=d++,g=0,h=c[f].length;h>g;){var i=g++,j=c[f][i];j.push(1),c[f][i]=ta.dot(b,j).slice(0,j.length-1)}return new X(a.degreeU,a.degreeV,a.knotsU.slice(),a.knotsV.slice(),Ia.homogenize2d(c,Ia.weight2d(a.controlPoints)))},La.rationalCurveTransform=function(a,b){for(var c=Ia.dehomogenize1d(a.controlPoints),d=0,e=c.length;e>d;){var f=d++,g=c[f];g.push(1),c[f]=ta.dot(b,g).slice(0,g.length-1)}return new W(a.degree,a.knots.slice(),Ia.homogenize1d(c,Ia.weight1d(a.controlPoints)))},La.surfaceKnotRefine=function(a,b,c){if(0==b.length)return Ka.clonedSurface(a);var d,e,f=a.controlPoints;c?(d=a.degreeV,e=a.knotsV):(d=a.degreeU,e=a.knotsU);var g;g=c?f[0].length-1:f.length-1;var h=g+d+1,i=b.length-1,j=Ia.knotSpan(d,b[0],e),k=Ia.knotSpan(d,b[i],e),l=[],m=[];if(c){for(var n=Da.knotMultiplicities(b),o=0,p=f.length+n.length-1;p>o;){o++;l.push([])}for(var q=0,r=j-d+1;r>q;)for(var s=q++,t=0,u=f.length;u>t;){var v=t++;l[v][s]=f[v][s]}for(var w=k-1,x=g+1;x>w;)for(var y=w++,z=y+i+1,A=0,B=f.length;B>A;){var C=A++;l[C][z]=f[C][y]}}else{for(var D=0,E=j-d+1;E>D;){var F=D++;l[F]=f[F].slice(0)}for(var G=k-1,H=g+1;H>G;){var I=G++;l[I+i+1]=f[I].slice(0)}}for(var J=0,K=j+1;K>J;){var L=J++;m[L]=e[L]}for(var M=k+d,N=h+1;N>M;){var O=M++;m[O+i+1]=e[O]}for(var P=k+d-1,Q=k+d+i,R=i;R>=0;){for(;b[R]<=e[P]&&P>j;){var T=Q-d-1,U=P-d-1;if(c)for(var V=0,W=l.length;W>V;){var Y=V++;l[Y][T]=f[Y][U].slice(0)}else l[T]=f[U].slice(0);m[Q]=e[P],Q-=1,P-=1}if(c)for(var Z=0,$=l.length;$>Z;){var _=Z++;l[_][Q-d-1]=l[_][Q-d].slice(0)}else l[Q-d-1]=l[Q-d].slice(0);for(var aa=1,ba=d+1;ba>aa;){var ca=aa++,da=Q-d+ca,ea=m[Q+ca]-b[R];if(Math.abs(ea)fa;){var ha=fa++;l[ha][da-1]=l[ha][da]}else l[da-1]=l[da].slice(0);else if(ea/=m[Q+ca]-e[P-d+ca],c)for(var ia=0,ja=l.length;ja>ia;){var ka=ia++;l[ka][da-1]=Ca.lerp(ea,l[ka][da-1],l[ka][da])}else for(var la=0,ma=l[da].length;ma>la;){var na=la++;l[da-1][na]=Ca.lerp(ea,l[da-1][na],l[da][na])}}m[Q]=b[R],Q-=1,R--}return c?new X(a.degreeU,a.degreeV,a.knotsU.slice(),m,l):new X(a.degreeU,a.degreeV,m,a.knotsV.slice(),l)},La.decomposeSurfaceIntoBeziers=function(a){for(var b=Da.knotMultiplicities(a.knotsU),c=a.degreeU+1,d=0;dg;){var i=g++;f.push(a[i].slice(c,c+e))}return f},La.decomposeCurveIntoBeziers=function(a){for(var b=a.degree,c=a.controlPoints,d=a.knots,e=Da.knotMultiplicities(d),f=b+1,g=0;gm;){var o=m++;k[o]=d[o]}for(var p=j-1,q=f+1;q>p;){var r=p++;k[r+h+1]=d[r]}for(var s=0,t=i+1;t>s;){var u=s++;l[u]=e[u]}for(var v=j+c,w=g+1;w>v;){var x=v++;l[x+h+1]=e[x]}for(var y=j+c-1,z=j+c+h,A=h;A>=0;){for(;b[A]<=e[y]&&y>i;)k[z-c-1]=d[y-c-1],l[z]=e[y],z-=1,y-=1;k[z-c-1]=k[z-c];for(var B=1,C=c+1;C>B;){var D=B++,E=z-c+D,F=l[z+D]-b[A];Math.abs(F)m;){var o=m++;k[o]=f[o]}for(var p=1,q=c+1;q>p;){var r=p++;k[i+r]=b}for(var s=i+1,t=f.length;t>s;){var u=s++;k[u+c]=f[u]}for(var v=0,w=i-d+1;w>v;){var x=v++;l[x]=e[x]}for(var y=i-g;h>y;){var z=y++;l[z+c]=e[z]}for(var A=0,B=d-g+1;B>A;){var C=A++;j[C]=e[i-d+C]}for(var D=0,E=0,F=1,G=c+1;G>F;){var H=F++;D=i-d+H;for(var I=0,J=d-H-g+1;J>I;){var K=I++;E=(b-f[D+K])/(f[K+i+1]-f[D+K]),j[K]=Ca.add(Ca.mul(1-E,j[K]),Ca.mul(E,j[K+1]))}l[D]=j[0],l[i+c-H-g]=j[d-H-g]}for(var L=D+1,M=i-g;M>L;){var N=L++;l[N]=j[N-D]}return new W(d,k,l)};var Ma=function(){};g["verb.eval.NewMeshData"]=Ma,Ma.__name__=["verb","eval","NewMeshData"],Ma.prototype={__class__:Ma};var Na=function(){};g["verb.eval.BezierEdgeIndices"]=Na,Na.__name__=["verb","eval","BezierEdgeIndices"],Na.prototype={__class__:Na};var Oa=g["verb.eval.EdgeSide"]={__ename__:["verb","eval","EdgeSide"],__constructs__:["North","South","East","West"]};Oa.North=["North",0],Oa.North.toString=h,Oa.North.__enum__=Oa,Oa.South=["South",1],Oa.South.toString=h,Oa.South.__enum__=Oa,Oa.East=["East",2],Oa.East.toString=h,Oa.East.__enum__=Oa,Oa.West=["West",3],Oa.West.toString=h,Oa.West.__enum__=Oa;var Pa=b.eval.Tess=function(){};g["verb.eval.Tess"]=Pa,Pa.__name__=["verb","eval","Tess"],Pa.rationalBezierSurfaceRegularSample=function(a,b,c){for(var d=[],e=a.knotsU[0],f=(P.last(a.knotsU)-a.knotsU[0])/b,g=0;b>g;){var h=(g++,Ka.surfaceIsocurve(a,e,!0));(P.last(h.knots)-h.knots[0])/c;Pa.rationalBezierCurveRegularSamplePointsMutate(h,d,h.knots[0],f,c,!1),e+=f}return d},Pa.northIndex=function(a,b,c){return 0>=a?null:c[a-1][b]},Pa.southIndex=function(a,b,c){return a>=c.length-1?null:c[a+1][b]},Pa.eastIndex=function(a,b,c){return b>=c[a].length-1?null:c[a][b+1]},Pa.westIndex=function(a,b,c){return 0>=b?null:c[a][b-1]},Pa.rationalSurfaceAdaptiveSample=function(a,b){for(var c,d=La.decomposeSurfaceIntoBeziers(a),e=[],f=0;fv;){var x=v++;m=[],u.push(m);for(var y=0,z=d[x].length;z>y;){var A=y++;if(q=d[x][A],n=new Na,m.push(n),k=Pa.southIndex(x,A,e),null==k&&(k=t),l=Pa.eastIndex(x,A,e),null==l&&(l=t),0==x){var B=Ka.surfaceIsocurve(q,P.first(q.knotsU),!1);o=r.length,Pa.rationalBezierCurveRegularSamplePointsMutate2(B,r,e[x][A].item1),p=r.length,Pa.regularUvsMutate(p-o,P.first(B.knots),e[x][A].item1,s,P.first(q.knotsU),!0),n.n=new _(o,p)}else n.n=u[x-1][A].s;if(0==A){o=r.length;var C=Ka.surfaceIsocurve(q,P.first(q.knotsV),!0);Pa.rationalBezierCurveRegularSamplePointsMutate2(C,r,e[x][A].item0),p=r.length,Pa.regularUvsMutate(p-o,P.first(C.knots),e[x][A].item0,s,P.first(q.knotsV),!1),n.w=new _(o,p)}else n.w=u[x][A-1].e;o=r.length;var D=Ka.surfaceIsocurve(q,P.last(q.knotsU),!1);Pa.rationalBezierCurveRegularSamplePointsMutate2(D,r,Math.min(k.item1,e[x][A].item1)),p=r.length,Pa.regularUvsMutate(p-o,P.first(D.knots),Math.min(k.item1,e[x][A].item1),s,P.last(q.knotsU),!0),n.s=new _(o,p),o=r.length;var E=Ka.surfaceIsocurve(q,P.last(q.knotsV),!0);Pa.rationalBezierCurveRegularSamplePointsMutate2(E,r,Math.min(l.item0,e[x][A].item0)),p=r.length,Pa.regularUvsMutate(p-o,P.first(E.knots),Math.min(l.item0,e[x][A].item0),s,P.last(q.knotsV),!1),n.e=new _(o,p)}}for(var F,G=[],H=0,I=d.length;I>H;)for(var J=H++,K=0,L=d[J].length;L>K;){var M=K++;F=r.length;for(var N=d[J][M],O=Math.ceil(1/e[J][M].item0),Q=P.last(N.knotsV)-N.knotsV[0],R=P.last(N.knotsU)-N.knotsU[0],S=Math.ceil(1/e[J][M].item1),T=Q/S,U=R/O,V=N.knotsU[0]+U,W=0,X=O-1;X>W;){var Z=(W++,Ka.surfaceIsocurve(N,V,!1));Pa.rationalBezierCurveRegularSamplePointsMutate(Z,r,Z.knots[0]+T,T,S-1,!1),Pa.regularUvsMutate(S-1,Z.knots[0]+T,T,s,V,!0),V+=U}O-=2,S-=2;for(var $=0;O>$;)for(var aa=$++,ba=0;S>ba;){var ca=ba++,da=F+aa*(S+1)+ca,ea=F+(aa+1)*(S+1)+ca,fa=ea+1,ga=da+1,ha=[da,ea,fa],ia=[da,fa,ga];G.push(ha),G.push(ia)}n=u[J][M],Pa.stitchMesh(N,G,n,O,S,Q,F,T,Oa.North),Pa.stitchMesh(N,G,n,O,S,Q,F,T,Oa.South),Pa.stitchMesh(N,G,n,O,S,R,F,U,Oa.East),Pa.stitchMesh(N,G,n,O,S,R,F,U,Oa.West)}return new Y(G,r,null,s)},Pa.regularUvsMutate=function(a,b,c,d,e,f){var g=0,h=b;if(f)for(;a>g;)d.push([e,h]),h+=c,g++;else for(;a>g;)d.push([h,e]),h+=c,g++},Pa.stitchMesh=function(a,b,c,d,e,f,g,h,i){var j,k,l=!1,m=1,n=1;switch(i[1]){case 0:j=c.n,k=a.knotsV,n=e;break;case 1:j=c.s,k=a.knotsV,g+=d*(e+1),l=!0,n=e;break;case 2:j=c.e,k=a.knotsU,m=e+1,g+=e,n=d;break;case 3:j=c.w,k=a.knotsU,m=e+1,l=!0,n=d}for(var o=j.item1-j.item0-1,p=f/o,q=P.first(k),r=P.first(k)+1.5*h,s=0,t=0,u=1;o>s;){for(;r>q&&o>s||o>s&&u>n;){var v=j.item0+s,w=v+1;l?b.push([v,w,g+t]):b.push([v,g+t,w]),s++,q+=p}if(o>s){var x=j.item0+s;l?b.push([g+t,x,g+t+m]):b.push([g+t,g+t+m,x])}u++,t+=m,r+=h}},Pa.rationalBezierCurveRegularSamplePointsMutate2=function(a,b,c,d){null==d&&(d=!1);var e=P.last(a.knots)-a.knots[0],f=Math.ceil(1/c),g=e/f;Pa.rationalBezierCurveRegularSamplePointsMutate(a,b,a.knots[0],g,f+1,!1)},Pa.rationalBezierSurfaceStepLength=function(a,b){for(var c=Ia.dehomogenize2d(a.controlPoints),d=new R,e=0;el;)for(var n=l++,o=0,p=c[n].length;p>o;){var q=o++;j=Ca.norm(c[n][q]),j>k&&(k=j)}for(var r,s=-(1/0),t=0,u=a.controlPoints.length-2;u>t;)for(var v=t++,w=0,x=a.controlPoints[v].length;x>w;){var y=w++;r=Ca.norm(Ca.add(c[v+2][y],Ca.add(Ca.mul(-2,c[v+1][y]),c[v][y])))-(k-b)*(P.last(i.controlPoints[v+2][y])-2*P.last(i.controlPoints[v+1][y])+P.last(i.controlPoints[v][y])),r>s&&(s=r)}for(var z,A=-(1/0),B=0,C=a.controlPoints.length;C>B;)for(var D=B++,E=0,F=a.controlPoints[D].length-2;F>E;){var G=E++;z=Ca.norm(Ca.add(c[D][G+2],Ca.add(Ca.mul(-2,c[D][G+1]),c[D][G])))-(k-b)*(P.last(i.controlPoints[D][G+2])-2*P.last(i.controlPoints[D][G+1])+P.last(i.controlPoints[D][G])),z>A&&(A=z)}for(var H,I=-(1/0),J=0,K=a.controlPoints.length-1;K>J;)for(var L=J++,M=0,N=a.controlPoints[L].length-1;N>M;){var O=M++;H=Ca.norm(Ca.addAll([c[L+1][O+1],Ca.mul(-1,c[L][O+1]),Ca.mul(-1,c[L+1][O]),c[L][O]]))-(k-b)*(P.last(i.controlPoints[L+1][O+1])-P.last(i.controlPoints[L][O+1])-P.last(i.controlPoints[L+1][O])+P.last(i.controlPoints[L][O])),H>I&&(I=H)}s*=a.degreeU*(a.degreeU-1),A*=a.degreeV*(a.degreeV-1),I*=a.degreeU*a.degreeV;for(var Q,T=1/0,U=0,V=a.controlPoints.length;V>U;)for(var W=U++,X=0,Y=a.controlPoints[W].length;Y>X;){var Z=X++;Q=P.last(a.controlPoints[W][Z]),T>Q&&(T=Q)}var $,aa;if(Math.abs(s)e;){var g=e++;d.push(Ia.dehomogenize(a.controlPoints[g]))}if(c)for(var h=0,i=a.controlPoints.length;i>h;){var j=h++;d[j].push(a.knots[j+1])}return d}var k,l=P.last(a.knots)-a.knots[0];k=a.knots.length==2*(a.degree+1)?[a]:La.decomposeCurveIntoBeziers(a);for(var m,n,o,p=[],q=a.knots[0],r=l/b,s=0,t=k.length;t>s;){var u=s++;m=P.last(k[u].knots)-q,n=Math.ceil(m/r),o=q+n*r,o>P.last(k[u].knots)+S.TOLERANCE&&(o-=r,n--),Pa.rationalBezierCurveRegularSamplePointsMutate(k[u],p,q,r,n+1,c),q=o+r}return p},Pa.rationalCurveAdaptiveSample=function(a,b,c){if(null==c&&(c=!1),1==a.degree){for(var d=[],e=0,f=a.controlPoints.length;f>e;){var g=e++;d.push(Ia.dehomogenize(a.controlPoints[g]))}if(c)for(var h=0,i=a.controlPoints.length;i>h;){var j=h++;d[j].push(a.knots[j+1])}return d}var k;k=a.knots.length==2*(a.degree+1)?[a]:La.decomposeCurveIntoBeziers(a);for(var l,m,n,o=[],p=0,q=k.length;q>p;){var r=p++;if(m=P.last(k[r].knots)-k[r].knots[0],n=Pa.rationalBezierCurveStepLength(k[r],b),l=Math.ceil(m/n),n=m/l,Pa.rationalBezierCurveRegularSamplePointsMutate(k[r],o,k[r].knots[0],n,l+1,c),r==k.length-1)break;o.pop()}return o},Pa.rationalBezierCurveRegularSamplePointsMutate=function(a,b,c,d,e,f){null==f&&(f=!1);var g=[],h=[g],i=c,j=a.degree+1;if(e<=a.degree+1)for(var k=0;e>k;){k++;b.push(Ia.rationalCurvePoint(a,i)),i+=d}else{for(var l=0;j>l;){l++;g.push(Ia.curvePoint(a,i)),i+=d}for(var m,n=1;j>n;){var o=n++;g=[],h.push(g),m=h[o-1];for(var p=1,q=m.length;q>p;){var r=p++;g.push(Ca.sub(m[r],m[r-1]))}}for(var s=0,t=h[0];sB;){for(var D=(B++,0),E=v.length-1;E>D;){var F=D++;z=A-F,Ca.addMutate(v[z],v[z+1])}b.push(Ia.dehomogenize(v[0]))}if(i=c,f)for(var G=0;Gj;){var l=j++;h=Ca.norm(c[l]),h>i&&(i=h)}var m=Ia.weight1d(a.controlPoints),n=Ca.min(m),o=P.last(a.knots)-a.knots[0];if(i>b){for(var p,q=8*n*b,r=Pa.secondForwardDiff(m),s=Pa.secondForwardDiff2(c),t=[],u=0,v=s.length;v>u;){var w=u++;t.push(Ca.norm(s[w])+(i-b)*r[w])}p=t;var x=Ca.max(p),y=a.degree*(a.degree-1)*x;return o*Math.sqrt(q/y)}if(i>=b&&2*i>b){for(var z,A=8*n*b,B=Pa.secondForwardDiff2(c),C=[],D=0,E=B.length;E>D;){var F=D++;C.push(Ca.norm(B[F]))}z=C;var G=Ca.max(z),H=a.degree*(a.degree-1)*G;return o*Math.sqrt(A/H)}return o},Pa.secondForwardDiff=function(a){for(var b=0,c=[];bb&&(b=1),1>c&&(c=1);for(var d=(a.degreeU,a.degreeV,a.controlPoints,a.knotsU),e=a.knotsV,f=P.last(d)-d[0],g=P.last(e)-e[0],h=f/b,i=g/c,j=[],k=[],l=[],m=0,n=b+1;n>m;)for(var o=m++,p=0,q=c+1;q>p;){var r=p++,s=d[0]+o*h,t=e[0]+r*i;k.push([s,t]);var u=Ia.rationalSurfaceDerivatives(a,s,t,1),v=u[0][0];j.push(v);var w=Ca.normalized(Ca.cross(u[1][0],u[0][1]));l.push(w)}for(var x=[],y=0;b>y;)for(var z=y++,A=0;c>A;){var B=A++,C=z*(c+1)+B,D=(z+1)*(c+1)+B,E=D+1,F=C+1,G=[C,D,E],H=[C,E,F];x.push(G),x.push(H)}return new Y(x,j,l,k)},Pa.divideRationalSurfaceAdaptive=function(a,b){null==b&&(b=new Qa),null!=b.minDivsU?b.minDivsU=b.minDivsU:b.minDivsU=1,null!=b.minDivsV?b.minDivsU=b.minDivsV:b.minDivsU=1,null!=b.refine?b.refine=b.refine:b.refine=!0;var c,d=2*(a.controlPoints.length-1),e=2*(a.controlPoints[0].length-1);c=b.minDivsU>d?b.minDivsU=b.minDivsU:b.minDivsU=d;var f;f=b.minDivsV>e?b.minDivsV=b.minDivsV:b.minDivsV=e;for(var g=P.last(a.knotsU),h=a.knotsU[0],i=P.last(a.knotsV),j=a.knotsV[0],k=(g-h)/c,l=(i-j)/f,m=[],n=[],o=0,p=f+1;p>o;){for(var q=o++,r=[],s=0,t=c+1;t>s;){var u=s++,v=h+k*u,w=j+l*q,x=Ia.rationalSurfaceDerivatives(a,v,w,1),y=Ca.normalized(Ca.cross(x[0][1],x[1][0]));r.push(new ia(x[0][0],y,[v,w],-1,Ca.isZero(y)))}n.push(r)}for(var z=0;f>z;)for(var A=z++,B=0;c>B;){var C=B++,D=[n[f-A-1][C],n[f-A-1][C+1],n[f-A][C+1],n[f-A][C]];m.push(new Ra(a,D))}if(!b.refine)return m;for(var E=0;f>E;)for(var F=E++,G=0;c>G;){var H=G++,I=F*c+H,J=Pa.north(I,F,H,c,f,m),K=Pa.east(I,F,H,c,f,m),L=Pa.south(I,F,H,c,f,m),M=Pa.west(I,F,H,c,f,m);m[I].neighbors=[L,K,J,M],m[I].divide(b)}return m},Pa.north=function(a,b,c,d,e,f){return 0==b?null:f[a-d]},Pa.south=function(a,b,c,d,e,f){return b==e-1?null:f[a+d]},Pa.east=function(a,b,c,d,e,f){return c==d-1?null:f[a+1]},Pa.west=function(a,b,c,d,e,f){return 0==c?null:f[a-1]},Pa.triangulateAdaptiveRefinementNodeTree=function(a){for(var b=Y.empty(),c=0;cs;){var t=s++,u=[];p.push(u);for(var v=0;r>v;){var w=v++;u.push(Ia.surfacePointGivenBasesKnotSpans(d,e,f,k[t],n[w],l[t],o[w],i))}}return p},Pa.surfaceRegularSample2=function(a,b,c){for(var d=[],e=a.knotsU[0],f=(P.last(a.knotsU)-a.knotsU[0])/b,g=0;b>g;){var h=(g++,Ka.surfaceIsocurve(a,e,!0));d.push(Pa.rationalCurveRegularSample(h,c)),e+=f}return d};var Qa=b.core.AdaptiveRefinementOptions=function(){this.minDivsV=1,this.minDivsU=1,this.refine=!0,this.maxDepth=10,this.minDepth=0,this.normTol=.025};g["verb.eval.AdaptiveRefinementOptions"]=Qa,Qa.__name__=["verb","eval","AdaptiveRefinementOptions"],Qa.prototype={__class__:Qa};var Ra=b.core.AdaptiveRefinementNode=function(a,b,c){if(this.srf=a,null==c?this.neighbors=[null,null,null,null]:this.neighbors=c,this.corners=b,null==this.corners){var d=a.knotsU[0],e=P.last(a.knotsU),f=a.knotsV[0],g=P.last(a.knotsV);this.corners=[ia.fromUv(d,f),ia.fromUv(e,f),ia.fromUv(e,g),ia.fromUv(d,g)]}};g["verb.eval.AdaptiveRefinementNode"]=Ra,Ra.__name__=["verb","eval","AdaptiveRefinementNode"],Ra.prototype={isLeaf:function(){return null==this.children},center:function(){return null!=this.centerPoint?this.centerPoint:this.evalSrf(this.u05,this.v05)},evalCorners:function(){this.u05=(this.corners[0].uv[0]+this.corners[2].uv[0])/2,this.v05=(this.corners[0].uv[1]+this.corners[2].uv[1])/2;for(var a=0;4>a;){var b=a++;if(null==this.corners[b].point){var c=this.corners[b];this.evalSrf(c.uv[0],c.uv[1],c)}}},evalSrf:function(a,b,c){var d=Ia.rationalSurfaceDerivatives(this.srf,a,b,1),e=d[0][0],f=Ca.cross(d[0][1],d[1][0]),g=Ca.isZero(f);return g||(f=Ca.normalized(f)),null!=c?(c.degen=g,c.point=e,c.normal=f,c):new ia(e,f,[a,b],-1,g)},getEdgeCorners:function(a){if(this.isLeaf())return[this.corners[a]];if(this.horizontal)switch(a){case 0:return this.children[0].getEdgeCorners(0);case 1:return this.children[0].getEdgeCorners(1).concat(this.children[1].getEdgeCorners(1));case 2:return this.children[1].getEdgeCorners(2);case 3:return this.children[1].getEdgeCorners(3).concat(this.children[0].getEdgeCorners(3))}switch(a){case 0:return this.children[0].getEdgeCorners(0).concat(this.children[1].getEdgeCorners(0));case 1:return this.children[1].getEdgeCorners(1);case 2:return this.children[1].getEdgeCorners(2).concat(this.children[0].getEdgeCorners(2));case 3:return this.children[0].getEdgeCorners(3)}return null},getAllCorners:function(a){var b=[this.corners[a]];if(null==this.neighbors[a])return b;var c=this.neighbors[a].getEdgeCorners((a+2)%4),d=a%2,e=S.EPSILON,f=this,g=[function(a){return a.uv[0]>f.corners[0].uv[0]+e&&a.uv[0]f.corners[0].uv[1]+e&&a.uv[1]b;){var c=b++;this.corners[c];if(this.corners[c].degen){var d=this.corners[(c+1)%a],e=this.corners[(c+3)%a];d.degen?this.corners[c].normal=e.normal:this.corners[c].normal=d.normal}}},shouldDivide:function(a,b){if(b=a.maxDepth)return!1;if(this.hasBadNormals())return this.fixNormals(),!1;if(this.splitVert=Ca.normSquared(Ca.sub(this.corners[0].normal,this.corners[1].normal))>a.normTol||Ca.normSquared(Ca.sub(this.corners[2].normal,this.corners[3].normal))>a.normTol,this.splitHoriz=Ca.normSquared(Ca.sub(this.corners[1].normal,this.corners[2].normal))>a.normTol||Ca.normSquared(Ca.sub(this.corners[3].normal,this.corners[0].normal))>a.normTol,this.splitVert||this.splitHoriz)return!0;var c=this.center();return Ca.normSquared(Ca.sub(c.normal,this.corners[0].normal))>a.normTol||Ca.normSquared(Ca.sub(c.normal,this.corners[1].normal))>a.normTol||Ca.normSquared(Ca.sub(c.normal,this.corners[2].normal))>a.normTol||Ca.normSquared(Ca.sub(c.normal,this.corners[3].normal))>a.normTol},divide:function(a){null==a&&(a=new Qa),null==a.normTol&&(a.normTol=.085),null==a.minDepth&&(a.minDepth=0),null==a.maxDepth&&(a.maxDepth=10),this._divide(a,0,!0)},_divide:function(a,b,c){if(this.evalCorners(),this.shouldDivide(a,b)){if(b++,this.splitVert&&!this.splitHoriz?c=!1:!this.splitVert&&this.splitHoriz&&(c=!0),this.horizontal=c,this.horizontal){var d=[this.corners[0],this.corners[1],this.midpoint(1),this.midpoint(3)],e=[this.midpoint(3),this.midpoint(1),this.corners[2],this.corners[3]];this.children=[new Ra(this.srf,d),new Ra(this.srf,e)],this.children[0].neighbors=[this.neighbors[0],this.neighbors[1],this.children[1],this.neighbors[3]],this.children[1].neighbors=[this.children[0],this.neighbors[1],this.neighbors[2],this.neighbors[3]]}else{var f=[this.corners[0],this.midpoint(0),this.midpoint(2),this.corners[3]],g=[this.midpoint(0),this.corners[1],this.corners[2],this.midpoint(2)];this.children=[new Ra(this.srf,f),new Ra(this.srf,g)],this.children[0].neighbors=[this.neighbors[0],this.children[1],this.neighbors[2],this.neighbors[3]],this.children[1].neighbors=[this.neighbors[0],this.neighbors[1],this.neighbors[2],this.children[0]]}for(var h=0,i=this.children;hf;){var g=f++,h=this.getAllCorners(g);2==h.length&&(e=g+1);for(var i=0,j=h.length;j>i;){var k=i++;c.push(h[k])}}for(var l=0;lc;){var d;c++;try{d=new Worker(Ta.basePath+b)}catch(e){e instanceof C&&(e=e.val),d=new Worker(Ta.basePath+b.substring(0,-3)+".min.js")}this._pool.push(d)}};g["verb.exe.WorkerPool"]=Ta,Ta.__name__=["verb","exe","WorkerPool"],Ta.prototype={addWork:function(a,b,c,d){var e=new Ua(a,b,c);this._callbacks.set(e.id,d),this._queue.push(e),this.processQueue()},processQueue:function(){for(var b=this;this._queue.length>0&&this._pool.length>0;){var c=this._queue.shift(),d=[c.id],e=[this._pool.shift()];this._working.h[d[0]]=e[0],e[0].onmessage=function(c,d){return function(e){b._working.remove(d[0]),b._pool.push(c[0]);try{b._callbacks.h.hasOwnProperty(d[0])&&(b._callbacks.h[d[0]](e.data.result),b._callbacks.remove(d[0]))}catch(f){f instanceof C&&(f=f.val),a.log(f)}b.processQueue()}}(e,d),e[0].postMessage(c)}},__class__:Ta};var Ua=function(a,b,c){this.className=a,this.methodName=b,this.args=c,this.id=Ua.uuid++};g["verb.exe._WorkerPool.Work"]=Ua,Ua.__name__=["verb","exe","_WorkerPool","Work"],Ua.prototype={__class__:Ua};var Va=function(){};g["verb.geom.ICurve"]=Va,Va.__name__=["verb","geom","ICurve"],Va.__interfaces__=[za],Va.prototype={__class__:Va};var Wa=b.geom.NurbsCurve=function(a){this._data=Fa.isValidNurbsCurveData(a)};g["verb.geom.NurbsCurve"]=Wa,Wa.__name__=["verb","geom","NurbsCurve"],Wa.__interfaces__=[Va],Wa.byKnotsControlPointsWeights=function(a,b,c,d){return new Wa(new W(a,b.slice(),Ia.homogenize1d(c,d)))},Wa.byPoints=function(a,b){return null==b&&(b=3),new Wa(Ka.rationalInterpCurve(a,b))},Wa.__super__=T,Wa.prototype=d(T.prototype,{degree:function(){return this._data.degree},knots:function(){return this._data.knots.slice(0)},controlPoints:function(){return Ia.dehomogenize1d(this._data.controlPoints)},weights:function(){return Ia.weight1d(this._data.controlPoints)},asNurbs:function(){return new W(this.degree(),this.knots(),Ia.homogenize1d(this.controlPoints(),this.weights()))},clone:function(){return new Wa(this._data)},domain:function(){return new aa(P.first(this._data.knots),P.last(this._data.knots))},transform:function(a){return new Wa(La.rationalCurveTransform(this._data,a))},transformAsync:function(a){return Sa.dispatchMethod(La,"rationalCurveTransform",[this._data,a]).then(function(a){return new Wa(a)})},point:function(a){return Ia.rationalCurvePoint(this._data,a)},pointAsync:function(a){return Sa.dispatchMethod(Ia,"rationalCurvePoint",[this._data,a])},tangent:function(a){return Ia.rationalCurveTangent(this._data,a)},tangentAsync:function(a){return Sa.dispatchMethod(Ia,"rationalCurveTangent",[this._data,a])},derivatives:function(a,b){return null==b&&(b=1),Ia.rationalCurveDerivatives(this._data,a,b)},derivativesAsync:function(a,b){return null==b&&(b=1),Sa.dispatchMethod(Ia,"rationalCurveDerivatives",[this._data,a,b])},closestPoint:function(a){return Da.rationalCurveClosestPoint(this._data,a)},closestPointAsync:function(a){return Sa.dispatchMethod(Da,"rationalCurveClosestPoint",[this._data,a])},closestParam:function(a){return Da.rationalCurveClosestParam(this._data,a)},closestParamAsync:function(a){return Sa.dispatchMethod(Da,"rationalCurveClosestParam",[this._data,a])},length:function(){return Da.rationalCurveArcLength(this._data)},lengthAsync:function(){return Sa.dispatchMethod(Da,"rationalCurveArcLength",[this._data])},lengthAtParam:function(a){return Da.rationalCurveArcLength(this._data,a)},lengthAtParamAsync:function(){return Sa.dispatchMethod(Da,"rationalCurveArcLength",[this._data])},paramAtLength:function(a,b){return Da.rationalCurveParamAtArcLength(this._data,a,b)},paramAtLengthAsync:function(a,b){return Sa.dispatchMethod(Da,"rationalCurveParamAtArcLength",[this._data,a,b])},divideByEqualArcLength:function(a){return Ga.rationalCurveByEqualArcLength(this._data,a)},divideByEqualArcLengthAsync:function(a){return Sa.dispatchMethod(Ga,"rationalCurveByEqualArcLength",[this._data,a])},divideByArcLength:function(a){return Ga.rationalCurveByArcLength(this._data,a)},divideByArcLengthAsync:function(a){return Sa.dispatchMethod(Ga,"rationalCurveByArcLength",[this._data,a])},split:function(a){return Ga.curveSplit(this._data,a).map(function(a){return new Wa(a)})},splitAsync:function(a){return Sa.dispatchMethod(Ga,"curveSplit",[this._data,a]).then(function(a){return a.map(function(a){return new Wa(a)})})},reverse:function(){return new Wa(La.curveReverse(this._data))},reverseAsync:function(){return Sa.dispatchMethod(La,"curveReverse",[this._data]).then(function(a){return new Wa(a)})},tessellate:function(a){return null==a&&(a=.001),Pa.rationalCurveAdaptiveSample(this._data,a,!1)},tessellateAsync:function(a){return null==a&&(a=.001),Sa.dispatchMethod(Pa,"rationalCurveAdaptiveSample",[this._data,a,!1])},__class__:Wa});var Xa=b.geom.Arc=function(a,b,c,d,e,f){Wa.call(this,Ka.arc(a,b,c,d,e,f)),this._center=a,this._xaxis=b,this._yaxis=c,this._radius=d,this._minAngle=e,this._maxAngle=f};g["verb.geom.Arc"]=Xa,Xa.__name__=["verb","geom","Arc"],Xa.__super__=Wa,Xa.prototype=d(Wa.prototype,{center:function(){return this._center},xaxis:function(){return this._xaxis},yaxis:function(){return this._yaxis},radius:function(){ +return this._radius},minAngle:function(){return this._minAngle},maxAngle:function(){return this._maxAngle},__class__:Xa});var Ya=b.geom.BezierCurve=function(a,b){Wa.call(this,Ka.rationalBezierCurve(a,b))};g["verb.geom.BezierCurve"]=Ya,Ya.__name__=["verb","geom","BezierCurve"],Ya.__super__=Wa,Ya.prototype=d(Wa.prototype,{__class__:Ya});var Za=b.geom.Circle=function(a,b,c,d){Xa.call(this,a,b,c,d,0,2*Math.PI)};g["verb.geom.Circle"]=Za,Za.__name__=["verb","geom","Circle"],Za.__super__=Xa,Za.prototype=d(Xa.prototype,{__class__:Za});var $a=function(){};g["verb.geom.ISurface"]=$a,$a.__name__=["verb","geom","ISurface"],$a.__interfaces__=[za],$a.prototype={__class__:$a};var _a=b.geom.NurbsSurface=function(a){this._data=Fa.isValidNurbsSurfaceData(a)};g["verb.geom.NurbsSurface"]=_a,_a.__name__=["verb","geom","NurbsSurface"],_a.__interfaces__=[$a],_a.byKnotsControlPointsWeights=function(a,b,c,d,e,f){return new _a(new X(a,b,c,d,Ia.homogenize2d(e,f)))},_a.byCorners=function(a,b,c,d){return new _a(Ka.fourPointSurface(a,b,c,d))},_a.byLoftingCurves=function(a,b){return new _a(Ka.loftedSurface(function(b){for(var c,d=[],e=0;ec;){var e=c++;b[e]=a(this[e])}return b}),null==Array.prototype.filter&&(Array.prototype.filter=function(a){for(var b=[],c=0,d=this.length;d>c;){var e=c++,f=this[e];a(f)&&b.push(f)}return b});var sb={},tb=c.ArrayBuffer||E;null==tb.prototype.slice&&(tb.prototype.slice=E.sliceImpl);var ub=(c.DataView||F,c.Uint8Array||G._new);!function(a,b){function c(a){return o[n]=d.apply(b,a),n++}function d(a){var c=[].slice.call(arguments,1);return function(){"function"==typeof a?a.apply(b,c):new Function(""+a)()}}function e(a){if(p)setTimeout(d(e,a),0);else{var b=o[a];if(b){p=!0;try{b()}finally{f(a),p=!1}}}}function f(a){delete o[a]}function g(){m=function(){var a=c(arguments);return process.nextTick(d(e,a)),a}}function h(){if(a.postMessage&&!a.importScripts){var b=!0,c=a.onmessage;return a.onmessage=function(){b=!1},a.postMessage("","*"),a.onmessage=c,b}}function i(){var b="setImmediate$"+Math.random()+"$",d=function(c){c.source===a&&"string"==typeof c.data&&0===c.data.indexOf(b)&&e(+c.data.slice(b.length))};a.addEventListener?a.addEventListener("message",d,!1):a.attachEvent("onmessage",d),m=function(){var d=c(arguments);return a.postMessage(b+d,"*"),d}}function j(){var a=new MessageChannel;a.port1.onmessage=function(a){var b=a.data;e(b)},m=function(){var b=c(arguments);return a.port2.postMessage(b),b}}function k(){var a=q.documentElement;m=function(){var b=c(arguments),d=q.createElement("script");return d.onreadystatechange=function(){e(b),d.onreadystatechange=null,a.removeChild(d),d=null},a.appendChild(d),b}}function l(){m=function(){var a=c(arguments);return setTimeout(d(e,a),0),a}}if(!a.setImmediate){var m,n=1,o={},p=!1,q=a.document,r=Object.getPrototypeOf&&Object.getPrototypeOf(a);r=r&&r.setTimeout?r:a,"[object process]"==={}.toString.call(a.process)?g():h()?i():a.MessageChannel?j():q&&"onreadystatechange"in q.createElement("script")?k():l(),r.setImmediate=m,r.clearImmediate=f}}(new Function("return this")()),t.USE_CACHE=!1,t.USE_ENUM_INDEX=!1,t.BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:",u.DEFAULT_RESOLVER=q,u.BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:",w.count=0,B.i64tmp=function(a){var b,c=new s(0,0);return b=c}(this),D.__toStr={}.toString,G.BYTES_PER_ELEMENT=1,M.queue=new k,Q.memo=new v,S.TOLERANCE=1e-6,S.EPSILON=1e-10,S.VERSION="2.0.0",Da.Tvalues=[[],[],[-.5773502691896257,.5773502691896257],[0,-.7745966692414834,.7745966692414834],[-.33998104358485626,.33998104358485626,-.8611363115940526,.8611363115940526],[0,-.5384693101056831,.5384693101056831,-.906179845938664,.906179845938664],[.6612093864662645,-.6612093864662645,-.2386191860831969,.2386191860831969,-.932469514203152,.932469514203152],[0,.4058451513773972,-.4058451513773972,-.7415311855993945,.7415311855993945,-.9491079123427585,.9491079123427585],[-.1834346424956498,.1834346424956498,-.525532409916329,.525532409916329,-.7966664774136267,.7966664774136267,-.9602898564975363,.9602898564975363],[0,-.8360311073266358,.8360311073266358,-.9681602395076261,.9681602395076261,-.3242534234038089,.3242534234038089,-.6133714327005904,.6133714327005904],[-.14887433898163122,.14887433898163122,-.4333953941292472,.4333953941292472,-.6794095682990244,.6794095682990244,-.8650633666889845,.8650633666889845,-.9739065285171717,.9739065285171717],[0,-.26954315595234496,.26954315595234496,-.5190961292068118,.5190961292068118,-.7301520055740494,.7301520055740494,-.8870625997680953,.8870625997680953,-.978228658146057,.978228658146057],[-.1252334085114689,.1252334085114689,-.3678314989981802,.3678314989981802,-.5873179542866175,.5873179542866175,-.7699026741943047,.7699026741943047,-.9041172563704749,.9041172563704749,-.9815606342467192,.9815606342467192],[0,-.2304583159551348,.2304583159551348,-.44849275103644687,.44849275103644687,-.6423493394403402,.6423493394403402,-.8015780907333099,.8015780907333099,-.9175983992229779,.9175983992229779,-.9841830547185881,.9841830547185881],[-.10805494870734367,.10805494870734367,-.31911236892788974,.31911236892788974,-.5152486363581541,.5152486363581541,-.6872929048116855,.6872929048116855,-.827201315069765,.827201315069765,-.9284348836635735,.9284348836635735,-.9862838086968123,.9862838086968123],[0,-.20119409399743451,.20119409399743451,-.3941513470775634,.3941513470775634,-.5709721726085388,.5709721726085388,-.7244177313601701,.7244177313601701,-.8482065834104272,.8482065834104272,-.937273392400706,.937273392400706,-.9879925180204854,.9879925180204854],[-.09501250983763744,.09501250983763744,-.2816035507792589,.2816035507792589,-.45801677765722737,.45801677765722737,-.6178762444026438,.6178762444026438,-.755404408355003,.755404408355003,-.8656312023878318,.8656312023878318,-.9445750230732326,.9445750230732326,-.9894009349916499,.9894009349916499],[0,-.17848418149584785,.17848418149584785,-.3512317634538763,.3512317634538763,-.5126905370864769,.5126905370864769,-.6576711592166907,.6576711592166907,-.7815140038968014,.7815140038968014,-.8802391537269859,.8802391537269859,-.9506755217687678,.9506755217687678,-.9905754753144174,.9905754753144174],[-.0847750130417353,.0847750130417353,-.2518862256915055,.2518862256915055,-.41175116146284263,.41175116146284263,-.5597708310739475,.5597708310739475,-.6916870430603532,.6916870430603532,-.8037049589725231,.8037049589725231,-.8926024664975557,.8926024664975557,-.9558239495713977,.9558239495713977,-.9915651684209309,.9915651684209309],[0,-.16035864564022537,.16035864564022537,-.31656409996362983,.31656409996362983,-.46457074137596094,.46457074137596094,-.600545304661681,.600545304661681,-.7209661773352294,.7209661773352294,-.8227146565371428,.8227146565371428,-.9031559036148179,.9031559036148179,-.96020815213483,.96020815213483,-.9924068438435844,.9924068438435844],[-.07652652113349734,.07652652113349734,-.22778585114164507,.22778585114164507,-.37370608871541955,.37370608871541955,-.5108670019508271,.5108670019508271,-.636053680726515,.636053680726515,-.7463319064601508,.7463319064601508,-.8391169718222188,.8391169718222188,-.912234428251326,.912234428251326,-.9639719272779138,.9639719272779138,-.9931285991850949,.9931285991850949],[0,-.1455618541608951,.1455618541608951,-.2880213168024011,.2880213168024011,-.4243421202074388,.4243421202074388,-.5516188358872198,.5516188358872198,-.6671388041974123,.6671388041974123,-.7684399634756779,.7684399634756779,-.8533633645833173,.8533633645833173,-.9200993341504008,.9200993341504008,-.9672268385663063,.9672268385663063,-.9937521706203895,.9937521706203895],[-.06973927331972223,.06973927331972223,-.20786042668822127,.20786042668822127,-.34193582089208424,.34193582089208424,-.469355837986757,.469355837986757,-.5876404035069116,.5876404035069116,-.6944872631866827,.6944872631866827,-.7878168059792081,.7878168059792081,-.8658125777203002,.8658125777203002,-.926956772187174,.926956772187174,-.9700604978354287,.9700604978354287,-.9942945854823992,.9942945854823992],[0,-.1332568242984661,.1332568242984661,-.26413568097034495,.26413568097034495,-.3903010380302908,.3903010380302908,-.5095014778460075,.5095014778460075,-.6196098757636461,.6196098757636461,-.7186613631319502,.7186613631319502,-.8048884016188399,.8048884016188399,-.8767523582704416,.8767523582704416,-.9329710868260161,.9329710868260161,-.9725424712181152,.9725424712181152,-.9947693349975522,.9947693349975522],[-.06405689286260563,.06405689286260563,-.1911188674736163,.1911188674736163,-.3150426796961634,.3150426796961634,-.4337935076260451,.4337935076260451,-.5454214713888396,.5454214713888396,-.6480936519369755,.6480936519369755,-.7401241915785544,.7401241915785544,-.820001985973903,.820001985973903,-.8864155270044011,.8864155270044011,-.9382745520027328,.9382745520027328,-.9747285559713095,.9747285559713095,-.9951872199970213,.9951872199970213]],Da.Cvalues=[[],[],[1,1],[.8888888888888888,.5555555555555556,.5555555555555556],[.6521451548625461,.6521451548625461,.34785484513745385,.34785484513745385],[.5688888888888889,.47862867049936647,.47862867049936647,.23692688505618908,.23692688505618908],[.3607615730481386,.3607615730481386,.46791393457269104,.46791393457269104,.17132449237917036,.17132449237917036],[.4179591836734694,.3818300505051189,.3818300505051189,.27970539148927664,.27970539148927664,.1294849661688697,.1294849661688697],[.362683783378362,.362683783378362,.31370664587788727,.31370664587788727,.22238103445337448,.22238103445337448,.10122853629037626,.10122853629037626],[.3302393550012598,.1806481606948574,.1806481606948574,.08127438836157441,.08127438836157441,.31234707704000286,.31234707704000286,.26061069640293544,.26061069640293544],[.29552422471475287,.29552422471475287,.26926671930999635,.26926671930999635,.21908636251598204,.21908636251598204,.1494513491505806,.1494513491505806,.06667134430868814,.06667134430868814],[.2729250867779006,.26280454451024665,.26280454451024665,.23319376459199048,.23319376459199048,.18629021092773426,.18629021092773426,.1255803694649046,.1255803694649046,.05566856711617366,.05566856711617366],[.24914704581340277,.24914704581340277,.2334925365383548,.2334925365383548,.20316742672306592,.20316742672306592,.16007832854334622,.16007832854334622,.10693932599531843,.10693932599531843,.04717533638651183,.04717533638651183],[.2325515532308739,.22628318026289723,.22628318026289723,.2078160475368885,.2078160475368885,.17814598076194574,.17814598076194574,.13887351021978725,.13887351021978725,.09212149983772845,.09212149983772845,.04048400476531588,.04048400476531588],[.2152638534631578,.2152638534631578,.2051984637212956,.2051984637212956,.18553839747793782,.18553839747793782,.15720316715819355,.15720316715819355,.12151857068790319,.12151857068790319,.08015808715976021,.08015808715976021,.03511946033175186,.03511946033175186],[.2025782419255613,.19843148532711158,.19843148532711158,.1861610000155622,.1861610000155622,.16626920581699392,.16626920581699392,.13957067792615432,.13957067792615432,.10715922046717194,.10715922046717194,.07036604748810812,.07036604748810812,.03075324199611727,.03075324199611727],[.1894506104550685,.1894506104550685,.18260341504492358,.18260341504492358,.16915651939500254,.16915651939500254,.14959598881657674,.14959598881657674,.12462897125553388,.12462897125553388,.09515851168249279,.09515851168249279,.062253523938647894,.062253523938647894,.027152459411754096,.027152459411754096],[.17944647035620653,.17656270536699264,.17656270536699264,.16800410215645004,.16800410215645004,.15404576107681028,.15404576107681028,.13513636846852548,.13513636846852548,.11188384719340397,.11188384719340397,.08503614831717918,.08503614831717918,.0554595293739872,.0554595293739872,.02414830286854793,.02414830286854793],[.1691423829631436,.1691423829631436,.16427648374583273,.16427648374583273,.15468467512626524,.15468467512626524,.14064291467065065,.14064291467065065,.12255520671147846,.12255520671147846,.10094204410628717,.10094204410628717,.07642573025488905,.07642573025488905,.0497145488949698,.0497145488949698,.02161601352648331,.02161601352648331],[.1610544498487837,.15896884339395434,.15896884339395434,.15276604206585967,.15276604206585967,.1426067021736066,.1426067021736066,.12875396253933621,.12875396253933621,.11156664554733399,.11156664554733399,.09149002162245,.09149002162245,.06904454273764123,.06904454273764123,.0448142267656996,.0448142267656996,.019461788229726478,.019461788229726478],[.15275338713072584,.15275338713072584,.14917298647260374,.14917298647260374,.14209610931838204,.14209610931838204,.13168863844917664,.13168863844917664,.11819453196151841,.11819453196151841,.10193011981724044,.10193011981724044,.08327674157670475,.08327674157670475,.06267204833410907,.06267204833410907,.04060142980038694,.04060142980038694,.017614007139152118,.017614007139152118],[.14608113364969041,.14452440398997005,.14452440398997005,.13988739479107315,.13988739479107315,.13226893863333747,.13226893863333747,.12183141605372853,.12183141605372853,.10879729916714838,.10879729916714838,.09344442345603386,.09344442345603386,.0761001136283793,.0761001136283793,.057134425426857205,.057134425426857205,.036953789770852494,.036953789770852494,.016017228257774335,.016017228257774335],[.13925187285563198,.13925187285563198,.13654149834601517,.13654149834601517,.13117350478706238,.13117350478706238,.12325237681051242,.12325237681051242,.11293229608053922,.11293229608053922,.10041414444288096,.10041414444288096,.08594160621706773,.08594160621706773,.06979646842452049,.06979646842452049,.052293335152683286,.052293335152683286,.03377490158481415,.03377490158481415,.0146279952982722,.0146279952982722],[.13365457218610619,.1324620394046966,.1324620394046966,.12890572218808216,.12890572218808216,.12304908430672953,.12304908430672953,.11499664022241136,.11499664022241136,.10489209146454141,.10489209146454141,.09291576606003515,.09291576606003515,.07928141177671895,.07928141177671895,.06423242140852585,.06423242140852585,.04803767173108467,.04803767173108467,.030988005856979445,.030988005856979445,.013411859487141771,.013411859487141771],[.12793819534675216,.12793819534675216,.1258374563468283,.1258374563468283,.12167047292780339,.12167047292780339,.1155056680537256,.1155056680537256,.10744427011596563,.10744427011596563,.09761865210411388,.09761865210411388,.08619016153195327,.08619016153195327,.0733464814110803,.0733464814110803,.05929858491543678,.05929858491543678,.04427743881741981,.04427743881741981,.028531388628933663,.028531388628933663,.0123412297999872,.0123412297999872]],Sa.THREADS=1,Sa._init=!1,Ta.basePath="",Ua.uuid=0,O.main()}("undefined"!=typeof console?console:{log:function(){}},a,"undefined"!=typeof c?c:"undefined"!=typeof b?b:"undefined"!=typeof self?self:this),a}); +======= /*! verb 2017-01-16 */ !function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.verb=a()}}(function(){var a={},b=this,c=(new Function("try {return this===window;}catch(e){ return false;}"),new Function("try {return this===global;}catch(e){return false;}")),d=new Function("try {return typeof importScripts === 'function';}catch(e){return false;}");if(c()&&!d()&&(console.log(typeof e),Worker=require("webworker-threads").Worker),c()||d()){var e=b;if(d()){var f=function(a,c){var d=b;return a.split(".").forEach(function(a){d&&(d=d[a])}),d?d[c]:null};onmessage=function(a){if(a.data.className&&a.data.methodName){var b=f(a.data.className,a.data.methodName);return b?void postMessage({result:b.apply(null,a.data.args),id:a.data.id}):console.error("could not find "+a.data.className+"."+a.data.methodName)}}}}return function(a,b,c){"use strict";function d(a,b){function c(){}c.prototype=a;var d=new c;for(var e in b)d[e]=b[e];return b.toString!==Object.prototype.toString&&(d.toString=b.toString),d}function e(a){return a instanceof Array?function(){return i.iter(a)}:"function"==typeof a.iterator?f(a,a.iterator):a.iterator}function f(a,b){if(null==b)return null;null==b.__id__&&(b.__id__=ib++);var c;return null==a.hx__closures__?a.hx__closures__={}:c=a.hx__closures__[b.__id__],null==c&&(c=function(){return c.method.apply(c.scope,arguments)},c.scope=a,c.method=b,a.hx__closures__[b.__id__]=c),c}b.geom=b.geom||{},b.exe=b.exe||{},b.eval=b.eval||{},b.core=b.core||{},b.promhx=b.promhx||{};var g={},h=function(){return D.__string_rec(this,"")},i=function(){};g.HxOverrides=i,i.__name__=["HxOverrides"],i.strDate=function(a){var b=a.length;switch(b){case 8:var c=a.split(":"),d=new Date;return d.setTime(0),d.setUTCHours(c[0]),d.setUTCMinutes(c[1]),d.setUTCSeconds(c[2]),d;case 10:var e=a.split("-");return new Date(e[0],e[1]-1,e[2],0,0,0);case 19:var f=a.split(" "),g=f[0].split("-"),h=f[1].split(":");return new Date(g[0],g[1]-1,g[2],h[0],h[1],h[2]);default:throw new C("Invalid date format : "+a)}},i.cca=function(a,b){var c=a.charCodeAt(b);if(c==c)return c},i.substr=function(a,b,c){return null!=b&&0!=b&&null!=c&&c<0?"":(null==c&&(c=a.length),b<0?(b=a.length+b,b<0&&(b=0)):c<0&&(c=a.length+c-b),a.substr(b,c))},i.iter=function(a){return{cur:0,arr:a,hasNext:function(){return this.cur0&&(1==f?this.buf.b+="n":(this.buf.b+="u",null==f?this.buf.b+="null":this.buf.b+=""+f),f=0),this.serialize(a[i]))}f>0&&(1==f?this.buf.b+="n":(this.buf.b+="u",null==f?this.buf.b+="null":this.buf.b+=""+f)),this.buf.b+="h";break;case k:this.buf.b+="l";for(var j=a,o=j.h,p=null;null!=o;){var r;p=o[0],o=o[1],r=p,this.serialize(r)}this.buf.b+="h";break;case Date:var s=a;this.buf.b+="v",this.buf.add(s.getTime());break;case y:this.buf.b+="b";for(var u=a,x=u.keys();x.hasNext();){var A=x.next();this.serializeString(A),this.serialize(null!=pb[A]?u.getReserved(A):u.h[A])}this.buf.b+="h";break;case v:this.buf.b+="q";for(var B=a,E=B.keys();E.hasNext();){var F=E.next();this.buf.b+=":",null==F?this.buf.b+="null":this.buf.b+=""+F,this.serialize(B.h[F])}this.buf.b+="h";break;case w:this.buf.b+="M";for(var G=a,H=G.keys();H.hasNext();){var I=H.next(),J=l.field(I,"__id__");l.deleteField(I,"__id__"),this.serialize(I),I.__id__=J,this.serialize(G.h[I.__id__])}this.buf.b+="h";break;case z:for(var K=a,L=0,M=K.length-2,N=new n,O=t.BASE64;L>2)),N.add(O.charAt(63&(P<<4|Q>>4))),N.add(O.charAt(63&(Q<<2|R>>6))),N.add(O.charAt(63&R))}if(L==M){var S=K.get(L++),T=K.get(L++);N.add(O.charAt(S>>2)),N.add(O.charAt(63&(S<<4|T>>4))),N.add(O.charAt(T<<2&63))}else if(L==M+1){var U=K.get(L++);N.add(O.charAt(U>>2)),N.add(O.charAt(U<<4&63))}var V=N.b;this.buf.b+="s",null==V.length?this.buf.b+="null":this.buf.b+=""+V.length,this.buf.b+=":",null==V?this.buf.b+="null":this.buf.b+=""+V;break;default:this.useCache&&this.cache.pop(),null!=a.hxSerialize?(this.buf.b+="C",this.serializeString(q.getClassName(e)),this.useCache&&this.cache.push(a),a.hxSerialize(this),this.buf.b+="g"):(this.buf.b+="c",this.serializeString(q.getClassName(e)),this.useCache&&this.cache.push(a),this.serializeFields(a))}break;case 4:if(D.__instanceof(a,nb)){var W=q.getClassName(a);this.buf.b+="A",this.serializeString(W)}else if(D.__instanceof(a,ob))this.buf.b+="B",this.serializeString(q.getEnumName(a));else{if(this.useCache&&this.serializeRef(a))return;this.buf.b+="o",this.serializeFields(a)}break;case 7:var X=b[2];if(this.useCache){if(this.serializeRef(a))return;this.cache.pop()}this.useEnumIndex?this.buf.b+="j":this.buf.b+="w",this.serializeString(q.getEnumName(X)),this.useEnumIndex?(this.buf.b+=":",this.buf.b+=m.string(a[1])):this.serializeString(a[0]),this.buf.b+=":";var Y=a.length;this.buf.b+=m.string(Y-2);for(var Z=2;Z57)break;a=10*a+(d-48),this.pos++}else{if(this.pos!=c)break;b=!0,this.pos++}}return b&&(a*=-1),a},readFloat:function(){for(var a=this.pos;;){var b=this.buf.charCodeAt(this.pos);if(!(b>=43&&b<58||101==b||69==b))break;this.pos++}return m.parseFloat(i.substr(this.buf,a,this.pos-a))},unserializeObject:function(a){for(;;){if(this.pos>=this.length)throw new C("Invalid object");if(103==this.buf.charCodeAt(this.pos))break;var b=this.unserialize();if("string"!=typeof b)throw new C("Invalid object key");var c=this.unserialize();a[b]=c}this.pos++},unserializeEnum:function(a,b){if(58!=this.get(this.pos++))throw new C("Invalid enum format");var c=this.readDigits();if(0==c)return q.createEnum(a,b);for(var d=[];c-- >0;)d.push(this.unserialize());return q.createEnum(a,b,d)},unserialize:function(){var a=this.get(this.pos++);switch(a){case 110:return null;case 116:return!0;case 102:return!1;case 122:return 0;case 105:return this.readDigits();case 100:return this.readFloat();case 121:var b=this.readDigits();if(58!=this.get(this.pos++)||this.length-this.pos=this.cache.length)throw new C("Invalid reference");return this.cache[h];case 82:var j=this.readDigits();if(j<0||j>=this.scache.length)throw new C("Invalid string reference");return this.scache[j];case 120:throw new C(this.unserialize());case 99:var l=this.unserialize(),m=this.resolver.resolveClass(l);if(null==m)throw new C("Class not found "+l);var n=q.createEmptyInstance(m);return this.cache.push(n),this.unserializeObject(n),n;case 119:var p=this.unserialize(),r=this.resolver.resolveEnum(p);if(null==r)throw new C("Enum not found "+p);var s=this.unserializeEnum(r,this.unserialize());return this.cache.push(s),s;case 106:var t=this.unserialize(),x=this.resolver.resolveEnum(t);if(null==x)throw new C("Enum not found "+t);this.pos++;var A=this.readDigits(),B=q.getEnumConstructs(x)[A];if(null==B)throw new C("Unknown enum index "+t+"@"+A);var D=this.unserializeEnum(x,B);return this.cache.push(D),D;case 108:var E=new k;this.cache.push(E);for(this.buf;104!=this.buf.charCodeAt(this.pos);)E.add(this.unserialize());return this.pos++,E;case 98:var F=new y;this.cache.push(F);for(this.buf;104!=this.buf.charCodeAt(this.pos);){var G=this.unserialize();F.set(G,this.unserialize())}return this.pos++,F;case 113:var H=new v;this.cache.push(H);for(var I=(this.buf,this.get(this.pos++));58==I;){var J=this.readDigits();H.set(J,this.unserialize()),I=this.get(this.pos++)}if(104!=I)throw new C("Invalid IntMap format");return H;case 77:var K=new w;this.cache.push(K);for(this.buf;104!=this.buf.charCodeAt(this.pos);){var L=this.unserialize();K.set(L,this.unserialize())}return this.pos++,K;case 118:var M;if(this.buf.charCodeAt(this.pos)>=48&&this.buf.charCodeAt(this.pos)<=57&&this.buf.charCodeAt(this.pos+1)>=48&&this.buf.charCodeAt(this.pos+1)<=57&&this.buf.charCodeAt(this.pos+2)>=48&&this.buf.charCodeAt(this.pos+2)<=57&&this.buf.charCodeAt(this.pos+3)>=48&&this.buf.charCodeAt(this.pos+3)<=57&&45==this.buf.charCodeAt(this.pos+4)){var N=i.substr(this.buf,this.pos,19);M=i.strDate(N),this.pos+=19}else{var O=this.readFloat(),P=new Date;P.setTime(O),M=P}return this.cache.push(M),M;case 115:var Q=this.readDigits(),R=this.buf;if(58!=this.get(this.pos++)||this.length-this.pos>2)+(V>=2?V-1:0);for(var W=U+(Q-V),X=z.alloc(T),Y=0;U>4);var _=S[o.fastCodeAt(R,U++)];X.set(Y++,$<<4|_>>2);var aa=S[o.fastCodeAt(R,U++)];X.set(Y++,_<<6|aa)}if(V>=2){var ba=S[o.fastCodeAt(R,U++)],ca=S[o.fastCodeAt(R,U++)];if(X.set(Y++,ba<<2|ca>>4),3==V){var da=S[o.fastCodeAt(R,U++)];X.set(Y++,ca<<4|da>>2)}}return this.pos+=Q,this.cache.push(X),X;case 67:var ea=this.unserialize(),fa=this.resolver.resolveClass(ea);if(null==fa)throw new C("Class not found "+ea);var ga=q.createEmptyInstance(fa);if(this.cache.push(ga),ga.hxUnserialize(this),103!=this.get(this.pos++))throw new C("Invalid custom data");return ga;case 65:var ha=this.unserialize(),ia=this.resolver.resolveClass(ha);if(null==ia)throw new C("Class not found "+ha);return ia;case 66:var ja=this.unserialize(),ka=this.resolver.resolveEnum(ja);if(null==ka)throw new C("Enum not found "+ja);return ka}throw this.pos--,new C("Invalid char "+this.buf.charAt(this.pos)+" at position "+this.pos)},__class__:u};var v=function(){this.h={}};g["haxe.ds.IntMap"]=v,v.__name__=["haxe","ds","IntMap"],v.__interfaces__=[r],v.prototype={set:function(a,b){this.h[a]=b},remove:function(a){return!!this.h.hasOwnProperty(a)&&(delete this.h[a],!0)},keys:function(){var a=[];for(var b in this.h)this.h.hasOwnProperty(b)&&a.push(0|b);return i.iter(a)},__class__:v};var w=function(){this.h={},this.h.__keys__={}};g["haxe.ds.ObjectMap"]=w,w.__name__=["haxe","ds","ObjectMap"],w.__interfaces__=[r],w.prototype={set:function(a,b){var c=a.__id__||(a.__id__=++w.count);this.h[c]=b,this.h.__keys__[c]=a},keys:function(){var a=[];for(var b in this.h.__keys__)this.h.hasOwnProperty(b)&&a.push(this.h.__keys__[b]);return i.iter(a)},__class__:w};var x=g["haxe.ds.Option"]={__ename__:["haxe","ds","Option"],__constructs__:["Some","None"]};x.Some=function(a){var b=["Some",0,a];return b.__enum__=x,b.toString=h,b},x.None=["None",1],x.None.toString=h,x.None.__enum__=x;var y=function(){this.h={}};g["haxe.ds.StringMap"]=y,y.__name__=["haxe","ds","StringMap"],y.__interfaces__=[r],y.prototype={set:function(a,b){null!=pb[a]?this.setReserved(a,b):this.h[a]=b},get:function(a){return null!=pb[a]?this.getReserved(a):this.h[a]},setReserved:function(a,b){null==this.rh&&(this.rh={}),this.rh["$"+a]=b},getReserved:function(a){return null==this.rh?null:this.rh["$"+a]},keys:function(){var a=this.arrayKeys();return i.iter(a)},arrayKeys:function(){var a=[];for(var b in this.h)this.h.hasOwnProperty(b)&&a.push(b);if(null!=this.rh)for(var b in this.rh)36==b.charCodeAt(0)&&a.push(b.substr(1));return a},__class__:y};var z=function(a){this.length=a.byteLength,this.b=new rb(a),this.b.bufferValue=a,a.hxBytes=this,a.bytes=this.b};g["haxe.io.Bytes"]=z,z.__name__=["haxe","io","Bytes"],z.alloc=function(a){return new z(new qb(a))},z.prototype={get:function(a){return this.b[a]},set:function(a,b){this.b[a]=255&b},__class__:z};var A=g["haxe.io.Error"]={__ename__:["haxe","io","Error"],__constructs__:["Blocked","Overflow","OutsideBounds","Custom"]};A.Blocked=["Blocked",0],A.Blocked.toString=h,A.Blocked.__enum__=A,A.Overflow=["Overflow",1],A.Overflow.toString=h,A.Overflow.__enum__=A,A.OutsideBounds=["OutsideBounds",2],A.OutsideBounds.toString=h,A.OutsideBounds.__enum__=A,A.Custom=function(a){var b=["Custom",3,a];return b.__enum__=A,b.toString=h,b};var B=function(){};g["haxe.io.FPHelper"]=B,B.__name__=["haxe","io","FPHelper"],B.i32ToFloat=function(a){var b=1-(a>>>31<<1),c=a>>>23&255,d=8388607&a;return 0==d&&0==c?0:b*(1+Math.pow(2,-23)*d)*Math.pow(2,c-127)},B.floatToI32=function(a){if(0==a)return 0;var b;b=a<0?-a:a;var c=Math.floor(Math.log(b)/.6931471805599453);c<-127?c=-127:c>128&&(c=128);var d=8388607&Math.round(8388608*(b/Math.pow(2,c)-1));return(a<0?-2147483648:0)|c+127<<23|d},B.i64ToDouble=function(a,b){var c=1-(b>>>31<<1),d=(b>>20&2047)-1023,e=4294967296*(1048575&b)+2147483648*(a>>>31)+(2147483647&a);return 0==e&&d==-1023?0:c*(1+Math.pow(2,-52)*e)*Math.pow(2,d)},B.doubleToI64=function(a){var b=B.i64tmp;if(0==a)b.low=0,b.high=0;else{var c;c=a<0?-a:a;var d,e=Math.floor(Math.log(c)/.6931471805599453),f=4503599627370496*(c/Math.pow(2,e)-1);d=Math.round(f);var g=0|d,h=d/4294967296|0;b.low=g,b.high=(a<0?-2147483648:0)|e+1023<<20|h}return b};var C=function(a){Error.call(this),this.val=a,this.message=String(a),Error.captureStackTrace&&Error.captureStackTrace(this,C)};g["js._Boot.HaxeError"]=C,C.__name__=["js","_Boot","HaxeError"],C.__super__=Error,C.prototype=d(Error.prototype,{__class__:C});var D=function(){};g["js.Boot"]=D,D.__name__=["js","Boot"],D.getClass=function(a){if(a instanceof Array&&null==a.__enum__)return Array;var b=a.__class__;if(null!=b)return b;var c=D.__nativeClassName(a);return null!=c?D.__resolveNativeClass(c):null},D.__string_rec=function(a,b){if(null==a)return"null";if(b.length>=5)return"<...>";var c=typeof a;switch("function"==c&&(a.__name__||a.__ename__)&&(c="object"),c){case"object":if(a instanceof Array){if(a.__enum__){if(2==a.length)return a[0];var d=a[0]+"(";b+="\t";for(var e=2,f=a.length;e0?",":"")+D.__string_rec(a[k],b)}return i+="]"}var l;try{l=a.toString}catch(m){return m instanceof C&&(m=m.val),"???"}if(null!=l&&l!=Object.toString&&"function"==typeof l){var n=a.toString();if("[object Object]"!=n)return n}var o=null,p="{\n";b+="\t";var q=null!=a.hasOwnProperty;for(var o in a)q&&!a.hasOwnProperty(o)||"prototype"!=o&&"__class__"!=o&&"__super__"!=o&&"__interfaces__"!=o&&"__properties__"!=o&&(2!=p.length&&(p+=", \n"),p+=b+o+" : "+D.__string_rec(a[o],b));return b=b.substring(1),p+="\n"+b+"}";case"function":return"";case"string":return a;default:return String(a)}},D.__interfLoop=function(a,b){if(null==a)return!1;if(a==b)return!0;var c=a.__interfaces__;if(null!=c)for(var d=0,e=c.length;da.byteLength)throw new C(A.OutsideBounds)};g["js.html.compat.DataView"]=F,F.__name__=["js","html","compat","DataView"],F.prototype={getInt8:function(a){var b=this.buf.a[this.offset+a];return b>=128?b-256:b},getUint8:function(a){return this.buf.a[this.offset+a]},getInt16:function(a,b){var c=this.getUint16(a,b);return c>=32768?c-65536:c},getUint16:function(a,b){return b?this.buf.a[this.offset+a]|this.buf.a[this.offset+a+1]<<8:this.buf.a[this.offset+a]<<8|this.buf.a[this.offset+a+1]},getInt32:function(a,b){var c=this.offset+a,d=this.buf.a[c++],e=this.buf.a[c++],f=this.buf.a[c++],g=this.buf.a[c++];return b?d|e<<8|f<<16|g<<24:g|f<<8|e<<16|d<<24},getUint32:function(a,b){var c=this.getInt32(a,b);return c<0?c+4294967296:c},getFloat32:function(a,b){return B.i32ToFloat(this.getInt32(a,b))},getFloat64:function(a,b){var c=this.getInt32(a,b),d=this.getInt32(a+4,b);return B.i64ToDouble(b?c:d,b?d:c)},setInt8:function(a,b){b<0?this.buf.a[a+this.offset]=b+128&255:this.buf.a[a+this.offset]=255&b},setUint8:function(a,b){this.buf.a[a+this.offset]=255&b},setInt16:function(a,b,c){this.setUint16(a,b<0?b+65536:b,c)},setUint16:function(a,b,c){var d=a+this.offset;c?(this.buf.a[d]=255&b,this.buf.a[d++]=b>>8&255):(this.buf.a[d++]=b>>8&255,this.buf.a[d]=255&b)},setInt32:function(a,b,c){this.setUint32(a,b,c)},setUint32:function(a,b,c){var d=a+this.offset;c?(this.buf.a[d++]=255&b,this.buf.a[d++]=b>>8&255,this.buf.a[d++]=b>>16&255,this.buf.a[d++]=b>>>24):(this.buf.a[d++]=b>>>24,this.buf.a[d++]=b>>16&255,this.buf.a[d++]=b>>8&255,this.buf.a[d++]=255&b)},setFloat32:function(a,b,c){this.setUint32(a,B.floatToI32(b),c)},setFloat64:function(a,b,c){var d=B.doubleToI64(b);c?(this.setUint32(a,d.low),this.setUint32(a,d.high)):(this.setUint32(a,d.high),this.setUint32(a,d.low))},__class__:F};var G=function(){};g["js.html.compat.Uint8Array"]=G,G.__name__=["js","html","compat","Uint8Array"],G._new=function(a,b,c){var d;if("number"==typeof a){d=[];for(var e=0;ec.byteLength)throw new C("set() outside of range");for(var e=0,f=a.byteLength;ec.byteLength)throw new C("set() outside of range");for(var i=0,j=h.length;i0||b.handleError(a._errorVal),a._resolved&&!a._pending)try{b.handleResolve(c(a._val))}catch(d){d instanceof C&&(d=d.val),b.handleError(d)}},H.linkAll=function(a,b){for(var c=function(c,d,f){if(0==c.length||H.allFulfilled(c)){for(var g,h=[],i=e(a)();i.hasNext();){var j=i.next();h.push(j==d?f:j._val)}g=h,b.handleResolve(g)}},d=e(a)();d.hasNext();){var f=d.next();f._update.push({async:b,linkf:function(a,b,c){return function(d){a(b,c,d)}}(c,function(b){for(var c,d=[],g=e(a)();g.hasNext();){var h=g.next();h!=f&&d.push(h)}return c=d}(this),f)})}H.allFulfilled(a)&&b.handleResolve(function(b){for(var c,d=[],f=e(a)();f.hasNext();){var g=f.next();d.push(g._val)}return c=d}(this))},H.pipeLink=function(a,b,c){var d=!1,e=function(a){if(!d){d=!0;var e=c(a);e._update.push({async:b,linkf:f(b,b.handleResolve)}),H.immediateLinkUpdate(e,b,function(a){return a})}};if(a._update.push({async:b,linkf:e}),a._resolved&&!a._pending)try{e(a._val)}catch(g){g instanceof C&&(g=g.val),b.handleError(g)}},H.allResolved=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._resolved)return!1}return!0},H.allFulfilled=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._fulfilled)return!1}return!0},H.prototype={catchError:function(a){return this._error.push(a),this},errorThen:function(a){return this._errorMap=a,this},isResolved:function(){return this._resolved},isErrored:function(){return this._errored},isErrorHandled:function(){return this._error.length>0},isErrorPending:function(){return this._errorPending},isFulfilled:function(){return this._fulfilled},isPending:function(){return this._pending},handleResolve:function(a){this._resolve(a)},_resolve:function(a){var b=this;this._pending?M.enqueue(function(a,b){return function(){a(b)}}(f(this,this._resolve),a)):(this._resolved=!0,this._pending=!0,M.queue.add(function(){b._val=a;for(var c=0,d=b._update;c0)for(var c=0,d=b._error;c0))throw new C(a);for(var f=0,g=b._update;f0&&null!=(b=M.queue.pop());)b();return M.queue.isEmpty()},M.clear=function(){M.queue=new k},M.f=function(){var a=M.queue.pop();null!=a&&a(),M.queue.isEmpty()||M.continueOnNextLoop()},M.continueOnNextLoop=function(){null!=M.nextLoop?M.nextLoop(M.f):setImmediate(M.f)};var N=g["promhx.error.PromiseError"]={__ename__:["promhx","error","PromiseError"],__constructs__:["AlreadyResolved","DownstreamNotFullfilled"]};N.AlreadyResolved=function(a){var b=["AlreadyResolved",0,a];return b.__enum__=N,b.toString=h,b},N.DownstreamNotFullfilled=function(a){var b=["DownstreamNotFullfilled",1,a];return b.__enum__=N,b.toString=h,b};var O=function(){};g["verb.Verb"]=O,O.__name__=["verb","Verb"],O.main=function(){a.log("verb 2.0.0")};var P=function(){};g["verb.core.ArrayExtensions"]=P,P.__name__=["verb","core","ArrayExtensions"],P.alloc=function(a,b){if(!(b<0))for(;a.length0;){for(var d=a.pop(),e=!0,f=0;fa)return 0;if(b>a-b&&(b=a-b),Q.memo_exists(a,b))return Q.get_memo(a,b);for(var c=1,d=a,e=1,f=b+1;ea)return 0;b>a-b&&(b=a-b);for(var c=1,d=1,e=b+1;d=i&&g<=j||h>=i&&h<=j||i>=g&&i<=h||j>=g&&j<=h},R.prototype={fromPoint:function(a){return new R([a])},add:function(a){if(!this.initialized)return this.dim=a.length,this.min=a.slice(0),this.max=a.slice(0),this.initialized=!0,this;for(var b=0,c=this.dim;bthis.max[d]&&(this.max[d]=a[d]),a[d]a&&(a=f,b=e)}return b},getAxisLength:function(a){return a<0||a>this.dim-1?0:Math.abs(this.min[a]-this.max[a])},intersect:function(a,b){if(!this.initialized)return null;var c=this.min,d=this.max,e=a.min,f=a.max;if(!this.intersects(a,b))return null;for(var g=[],h=[],i=0,j=this.dim;i0?1:-1}),d=Math.floor(a.length/2),e=new na(a[d],f,c),e.left=this.buildTree(a.slice(0,d),b+1,e),e.right=this.buildTree(a.slice(d+1),b+1,e),e)},nearest:function(a,b,c){var d,e=this,f=new la(function(a){return-a.item1}),g=null;g=function(c){for(var d,h,i=c.dimension,j=e.distanceFunction(a,c.kdPoint.point),k=[],l=0,m=e.dim;lb&&f.pop()},q=0,r=e.dim;q0&&(this.content[0]=b,this.sinkDown(0)),a},peek:function(){return this.content[0]},remove:function(a){for(var b=this.content.length,c=0;c0;){var c=Math.floor((a+1)/2)-1,d=this.content[c];if(!(this.scoreFunction(b)=0;){for(g=[],h=a[k],m=e-1;m>=0;){for(i=h[d-1]*b[d-1][m],l=d-2;l>=1;)j=l-1,i+=h[l]*b[l][m]+h[j]*b[j][m],l-=2;0==l&&(i+=h[0]*b[0][m]),g[m]=i,m--}f[k]=g,k--}return f},ta.add=function(a,b){for(var c=[],d=0,e=a.length;d=0;){for(f=h[c],d=c+1;dd?1:-1});for(var i=[],j=0,k=e.length;j=.1*q*f||isNaN(i));)q*=.5,++t;if(q*r20)throw new C("Numerical gradient fails");if(n[s]=b[s]+t,e=a(n),n[s]=b[s]-t,f=a(n),n[s]=b[s],isNaN(e)||isNaN(f))t/=16;else{if(o[s]=(e-f)/(2*t),h=b[s]-t,i=b[s],j=b[s]+t,k=(e-d)/t,l=(d-f)/t,m=Ca.max([Math.abs(o[s]),Math.abs(d),Math.abs(e),Math.abs(f),Math.abs(h),Math.abs(i),Math.abs(j),1e-8]),g=Math.min(Ca.max([Math.abs(k-o[s]),Math.abs(l-o[s]),Math.abs(k-l)])/m,t/m),!(g>p))break;t/=16}}return o},xa.tensor=function(a,b){for(var c,d,e=a.length,f=b.length,g=[],h=e-1;h>=0;){c=[],d=a[h];for(var i=f-1;i>=3;)c[i]=d*b[i],--i,c[i]=d*b[i],--i,c[i]=d*b[i],--i,c[i]=d*b[i],--i;for(;i>=0;)c[i]=d*b[i],--i;g[h]=c,h--}return g};var ya=function(a,b,c,d,e,f){this.solution=a,this.value=b,this.gradient=c,this.invHessian=d,this.iterations=e,this.message=f};g["verb.core.MinimizationResult"]=ya,ya.__name__=["verb","core","MinimizationResult"],ya.prototype={__class__:ya};var za=function(){};g["verb.core.ISerializable"]=za,za.__name__=["verb","core","ISerializable"],za.prototype={__class__:za};var Aa=b.core.Deserializer=function(){};g["verb.core.Deserializer"]=Aa,Aa.__name__=["verb","core","Deserializer"],Aa.deserialize=function(a){var b=new u(a),c=b.unserialize();return c};var Ba=b.core.Trig=function(){};g["verb.core.Trig"]=Ba,Ba.__name__=["verb","core","Trig"],Ba.isPointInPlane=function(a,b,c){return Math.abs(Ca.dot(Ca.sub(a,b.origin),b.normal))g?{u:e,pt:c}:{u:d+(e-d)*k/g,pt:Ca.add(h,Ca.mul(k,i))}};var Ca=b.core.Vec=function(){};g["verb.core.Vec"]=Ca,Ca.__name__=["verb","core","Vec"],Ca.angleBetween=function(a,b){return Math.acos(Ca.dot(a,b)/(Ca.norm(a)*Ca.norm(b)))},Ca.positiveAngleBetween=function(a,b,c){var d=Ca.cross(a,b),e=Ca.norm(a),f=Ca.norm(b),g=e*f,h=Ca.dot(a,b),i=Ca.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=Ca.dot(c,d);return Math.abs(l)0?k:-k},Ca.signedAngleBetween=function(a,b,c){var d=Ca.cross(a,b),e=Ca.norm(a),f=Ca.norm(b),g=e*f,h=Ca.dot(a,b),i=Ca.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=Ca.dot(c,d);return l>0?k:2*Math.PI-k},Ca.angleBetweenNormalized2d=function(a,b){var c=a[0]*b[1]-a[1]*b[0];return Math.atan2(c,Ca.dot(a,b))},Ca.domain=function(a){return P.last(a)-P.first(a)},Ca.range=function(a){for(var b=[],c=0,d=0;db&&c>0)return[];if(b>a&&c<0)return[];for(var d=[],e=a;e<=b;)d.push(e),e+=c;return d},Ca.neg=function(a){return a.map(function(a){return-a})},Ca.min=function(a){return j.fold(a,function(a,b){return Math.min(a,b)},1/0)},Ca.max=function(a){return j.fold(a,function(a,b){return Math.max(a,b)},-(1/0))},Ca.all=function(a){return j.fold(a,function(a,b){return b&&a},!0)},Ca.finite=function(a){return a.map(function(a){return isFinite(a)})},Ca.onRay=function(a,b,c){return Ca.add(a,Ca.mul(c,b))},Ca.lerp=function(a,b,c){return Ca.add(Ca.mul(a,b),Ca.mul(1-a,c))},Ca.normalized=function(a){return Ca.div(a,Ca.norm(a))},Ca.cross=function(a,b){return[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]},Ca.dist=function(a,b){return Ca.norm(Ca.sub(a,b))},Ca.distSquared=function(a,b){return Ca.normSquared(Ca.sub(a,b))},Ca.sum=function(a){return j.fold(a,function(a,b){return b+a},0)},Ca.addAll=function(a){var b=e(a)();if(!b.hasNext())return null;var c=b.next().length;return j.fold(a,function(a,b){return Ca.add(b,a)},Ca.rep(c,0))},Ca.norm=function(a){var b=Ca.normSquared(a);return 0!=b?Math.sqrt(b):b},Ca.normSquared=function(a){return j.fold(a,function(a,b){return b+a*a},0)},Ca.rep=function(a,b){for(var c=[],d=0;dS.TOLERANCE)return!1}return!0},Ca.sortedSetUnion=function(a,b){for(var c=[],d=0,e=0;d=a.length)c.push(b[e]),e++;else if(e>=b.length)c.push(a[d]),d++;else{var f=a[d]-b[e];Math.abs(f)0?(c.push(b[e]),e++):(c.push(a[d]),d++)}return c},Ca.sortedSetSub=function(a,b){for(var c=[],d=0,e=0;d=b.length?(c.push(a[d]),d++):Math.abs(a[d]-b[e])S.EPSILON&&(c=new Ea(e,0),b.push(c)),c.inc()}return b},Da.isRationalSurfaceClosed=function(a,b){null==b&&(b=!0);var c;c=b?a.controlPoints:ta.transpose(a.controlPoints);for(var d=0,e=c[0].length;dk&&(I=n?[j+(I[0]-k),I[1]]:[k-S.EPSILON,I[1]]),I[1]m&&(I=o?[I[0],l+(I[0]-m)]:[I[0],m-S.EPSILON]);var J=Ca.norm(Ca.mul(I[0]-e[0],c[1][0])),K=Ca.norm(Ca.mul(I[1]-e[1],c[0][1]));if(J+Kv&&(G=w?u+(G-v):v);var H=Ca.norm(Ca.mul(G-x,o[1]));if(He)return P.last(a.knots);var f,g=a.knots[0],h=0,i=P.last(a.knots),j=e,k=0,l=0;for(f=null!=c?c:2*S.TOLERANCE;j-h>f;)k=(g+i)/2,l=Da.rationalBezierCurveArcLength(a,k),l>b?(i=k,j=l):(g=k,h=l);return(g+i)/2},Da.rationalCurveArcLength=function(a,b,c){null==c&&(c=16),b=null==b?P.last(a.knots):b;for(var d=La.decomposeCurveIntoBeziers(a),e=0,f=d[0],g=0;eS.EPSILON)return!1}c=P.last(a);for(var g=a.length-b-1,h=a.length;gS.EPSILON)return!1}return Fa.isNonDecreasing(a)},Fa.isNonDecreasing=function(a){for(var b=P.first(a),c=0,d=a.length;ce)return f;for(var g,h=b,i=0,j=h,k=0,l=0;i=G&&(q[s][0]=q[r][0]/f[v+1][u],t=q[s][0]*f[u][v]),w=u>=-1?1:-u,x=D-1<=v?G-1:c-D;for(var H=w,I=x+1;Hd[a+1]-S.EPSILON)return a;if(c=d[g+1];)cS.EPSILON}),function(a,b){var c=Ca.sub(a.min.uv0,b.min.uv0),d=Ca.dot(c,c),e=Ca.sub(a.max.uv0,b.max.uv0),f=Ca.dot(e,e),g=Ca.sub(a.min.uv0,b.max.uv0),h=Ca.dot(g,g),i=Ca.sub(a.max.uv0,b.min.uv0),j=Ca.dot(i,i);return d0&&(p.push(p[p.length-1].opp),l.push(p))}if(0==k.length&&e.length>0&&(n||m0;){var g=d.pop(),h=e.pop();if(!g.empty()&&!h.empty()&&g.boundingBox().intersects(h.boundingBox(),c)){var i=g.indivisible(c),j=h.indivisible(c);if(i&&j)f.push(new _(g.yield(),h.yield()));else if(!i||j)if(i||!j){var k=g.split(),l=h.split();d.push(k.item1),e.push(l.item1),d.push(k.item1),e.push(l.item0),d.push(k.item0),e.push(l.item1),d.push(k.item0),e.push(l.item0)}else{var m=g.split();d.push(m.item1),e.push(h),d.push(m.item0),e.push(h)}else{var n=h.split();d.push(g),e.push(n.item1),d.push(g),e.push(n.item0)}}}return f},Ja.curves=function(a,b,c){var d=Ja.boundingBoxTrees(new pa(a),new pa(b),0);return P.unique(d.map(function(d){return Ja.curvesWithEstimate(a,b,P.first(d.item0.knots),P.first(d.item1.knots),c)}).filter(function(a){return Ca.distSquared(a.point0,a.point1)j[n]+S.EPSILON||((null==k||sl.u)&&(l=new ha(s,Ca.onRay(a.origin,a.dir,s),Ca.onRay(f[n],g[n],r/j[n]))))}}return null==l||null==k?null:new aa(k,l)},Ja.mergeTriangleClipIntervals=function(a,b,c,d,e,f){if(b.min.u>a.max.u+S.EPSILON||a.min.u>b.max.u+S.EPSILON)return null;var g;g=a.min.u>b.min.u?new _(a.min,0):new _(b.min,1);var h;h=a.max.ug&&(f=1,g=h),i>g&&(f=2,g=i);var j,k,l,m;0==f?(j=b[1],k=b[2],l=d[1],m=d[2]):1==f?(j=b[0],k=b[2],l=d[0],m=d[2]):(j=b[0],k=b[1],l=d[0],m=d[1]);var n,o=-Ca.dot(a,b),p=-Ca.dot(c,d),q=j*m-k*l,r=(k*p-o*m)/q,s=(o*l-j*p)/q;return n=0==f?[0,r,s]:1==f?[r,0,s]:[r,s,0],new V(n,Ca.normalized(e))},Ja.threePlanes=function(a,b,c,d,e,f){var g=Ca.cross(c,e),h=Ca.dot(a,g);if(Math.abs(h)1)return null;var p=Ca.add(a,Ca.mul(o,k)),q=Ca.dot(h,i),r=Ca.dot(h,h),s=Ca.dot(i,i),t=Ca.sub(p,e),u=Ca.dot(t,h),v=Ca.dot(t,i),w=q*q-r*s;if(Math.abs(w)1+S.EPSILON||y>1+S.EPSILON||y<-S.EPSILON||x<-S.EPSILON||x+y>1+S.EPSILON?null:new ga(p,x,y,o)},Ja.segmentAndPlane=function(a,b,c,d){var e=Ca.dot(d,Ca.sub(b,a));if(Math.abs(e)1+S.EPSILON||g<-S.EPSILON?null:{p:g}};var Ka=b.eval.Make=function(){};g["verb.eval.Make"]=Ka,Ka.__name__=["verb","eval","Make"],Ka.rationalTranslationalSurface=function(a,b){for(var c=Ia.rationalCurvePoint(b,P.first(b.knots)),d=P.first(b.knots),e=P.last(b.knots),f=2*b.controlPoints.length,g=(e-d)/(f-1),h=[],i=0;i=0&&(k-=f[g].mult);var l;l=k>0?La.surfaceKnotRefine(a,Ca.rep(k,b),c):a;var m=Ia.knotSpan(e,b,d);return Math.abs(b-P.first(d))a.length-1&&(b=a.length-1);for(var d=a[0].knots,e=[],f=[],g=0,h=a[0].controlPoints.length;gS.EPSILON&&(z=Ca.mul(1/A,z),B=Ca.mul(1/A,B)),q[0][x]=g[x];var C=g[x];r[0][x]=h[x];for(var D=B,E=0,F=1,G=e+1;Fb?a:b},La.curveElevateDegree=function(a,b){if(b<=a.degree)return a;var c,d=a.knots.length-a.degree-2,e=a.degree,f=a.knots,g=a.controlPoints,h=b-a.degree,i=a.controlPoints[0].length,j=Ca.zeros2d(e+h+1,e+1),k=[],l=[],m=[],n=d+e+1,o=b,p=Math.floor(o/2),q=[],r=[];j[0][0]=1,j[o][e]=1;for(var s=1,t=p+1;s0?Math.floor((Y+2)/2):1;var $;if($=I>0?Math.floor(o-(I+1)/2):o,I>0){for(var _=X-M,aa=[],ba=e;ba>V;)aa[ba-V-1]=_/(f[J+ba]-M),ba--;for(var ca=1,da=I+1;ca=ga;)k[ha]=Ca.add(Ca.mul(aa[ha-ga],k[ha]),Ca.mul(1-aa[ha-ga],k[ha-1])),ha--;m[fa]=k[e]}}for(var ia=Z,ja=o+1;ia1)for(var pa=H-2,qa=H,ra=X-M,sa=(X-r[H-1])/ra,ta=1;taua;){if(va=Z){if(wa-ua<=H-o+Y){var za=(X-r[wa-ua])/ra;l[xa]=Ca.lerp(za,l[xa],l[xa+1])}}else l[xa]=Ca.lerp(sa,l[xa],l[xa+1]);va+=1,wa-=1,xa-=1}pa-=1,qa+=1}if(J!=e)for(var Aa=0,Ba=o-Y;Aa=0;){for(;b[A]<=e[y]&&y>i;)k[z-c-1]=d[y-c-1],l[z]=e[y],z-=1,y-=1;k[z-c-1]=k[z-c];for(var B=1,C=c+1;Bd||!Ba.threePointsAreFlat(f,j,g,d)){var m=b+.5*(c-b),n=Ma.rationalCurveAdaptiveSampleRange(a,b,m,d,e),o=Ma.rationalCurveAdaptiveSampleRange(a,m,c,d,e);return n.slice(0,-1).concat(o)}return e?[[b].concat(f),[c].concat(g)]:[f,g]},Ma.rationalSurfaceNaive=function(a,b,c){b<1&&(b=1),c<1&&(c=1);for(var d=(a.degreeU,a.degreeV,a.controlPoints,a.knotsU),e=a.knotsV,f=P.last(d)-d[0],g=P.last(e)-e[0],h=f/b,i=g/c,j=[],k=[],l=[],m=0,n=b+1;md?b.minDivsU=b.minDivsU:b.minDivsU=d;var f;f=b.minDivsV>e?b.minDivsV=b.minDivsV:b.minDivsV=e;for(var g=P.last(a.knotsU),h=a.knotsU[0],i=P.last(a.knotsV),j=a.knotsV[0],k=(g-h)/c,l=(i-j)/f,m=[],n=[],o=0,p=f+1;of.corners[0].uv[0]+e&&a.uv[0]f.corners[0].uv[1]+e&&a.uv[1]=a.maxDepth)return!1;if(this.hasBadNormals())return this.fixNormals(),!1;if(this.splitVert=Ca.normSquared(Ca.sub(this.corners[0].normal,this.corners[1].normal))>a.normTol||Ca.normSquared(Ca.sub(this.corners[2].normal,this.corners[3].normal))>a.normTol,this.splitHoriz=Ca.normSquared(Ca.sub(this.corners[1].normal,this.corners[2].normal))>a.normTol||Ca.normSquared(Ca.sub(this.corners[3].normal,this.corners[0].normal))>a.normTol,this.splitVert||this.splitHoriz)return!0;var c=this.center();return Ca.normSquared(Ca.sub(c.normal,this.corners[0].normal))>a.normTol||Ca.normSquared(Ca.sub(c.normal,this.corners[1].normal))>a.normTol||Ca.normSquared(Ca.sub(c.normal,this.corners[2].normal))>a.normTol||Ca.normSquared(Ca.sub(c.normal,this.corners[3].normal))>a.normTol},divide:function(a){null==a&&(a=new Na),null==a.normTol&&(a.normTol=.085),null==a.minDepth&&(a.minDepth=0),null==a.maxDepth&&(a.maxDepth=10),this._divide(a,0,!0)},_divide:function(a,b,c){if(this.evalCorners(),this.shouldDivide(a,b)){if(b++,this.splitVert&&!this.splitHoriz?c=!1:!this.splitVert&&this.splitHoriz&&(c=!0),this.horizontal=c,this.horizontal){var d=[this.corners[0],this.corners[1],this.midpoint(1),this.midpoint(3)],e=[this.midpoint(3),this.midpoint(1),this.corners[2],this.corners[3]];this.children=[new Oa(this.srf,d),new Oa(this.srf,e)],this.children[0].neighbors=[this.neighbors[0],this.neighbors[1],this.children[1],this.neighbors[3]],this.children[1].neighbors=[this.children[0],this.neighbors[1],this.neighbors[2],this.neighbors[3]]}else{var f=[this.corners[0],this.midpoint(0),this.midpoint(2),this.corners[3]],g=[this.midpoint(0),this.corners[1],this.corners[2],this.midpoint(2)];this.children=[new Oa(this.srf,f),new Oa(this.srf,g)],this.children[0].neighbors=[this.neighbors[0],this.children[1],this.neighbors[2],this.neighbors[3]],this.children[1].neighbors=[this.neighbors[0],this.neighbors[1],this.neighbors[2],this.children[0]]}for(var h=0,i=this.children;h0&&this._pool.length>0;){var c=this._queue.shift(),d=[c.id],e=[this._pool.shift()];this._working.h[d[0]]=e[0],e[0].onmessage=function(c,d){return function(e){b._working.remove(d[0]),b._pool.push(c[0]);try{b._callbacks.h.hasOwnProperty(d[0])&&(b._callbacks.h[d[0]](e.data.result),b._callbacks.remove(d[0]))}catch(f){f instanceof C&&(f=f.val),a.log(f)}b.processQueue()}}(e,d),e[0].postMessage(c)}},__class__:Qa};var Ra=function(a,b,c){this.className=a,this.methodName=b,this.args=c,this.id=Ra.uuid++};g["verb.exe._WorkerPool.Work"]=Ra,Ra.__name__=["verb","exe","_WorkerPool","Work"],Ra.prototype={__class__:Ra};var Sa=function(){};g["verb.geom.ICurve"]=Sa,Sa.__name__=["verb","geom","ICurve"],Sa.__interfaces__=[za],Sa.prototype={__class__:Sa};var Ta=b.geom.NurbsCurve=function(a){this._data=Fa.isValidNurbsCurveData(a)};g["verb.geom.NurbsCurve"]=Ta,Ta.__name__=["verb","geom","NurbsCurve"],Ta.__interfaces__=[Sa],Ta.byKnotsControlPointsWeights=function(a,b,c,d){return new Ta(new W(a,b.slice(),Ia.homogenize1d(c,d)))},Ta.byPoints=function(a,b){return null==b&&(b=3),new Ta(Ka.rationalInterpCurve(a,b))},Ta.__super__=T,Ta.prototype=d(T.prototype,{degree:function(){return this._data.degree},knots:function(){return this._data.knots.slice(0)},controlPoints:function(){return Ia.dehomogenize1d(this._data.controlPoints)},weights:function(){return Ia.weight1d(this._data.controlPoints)},asNurbs:function(){return new W(this.degree(),this.knots(),Ia.homogenize1d(this.controlPoints(),this.weights()))},clone:function(){return new Ta(this._data)},domain:function(){return new aa(P.first(this._data.knots),P.last(this._data.knots))},transform:function(a){return new Ta(La.rationalCurveTransform(this._data,a))},transformAsync:function(a){return Pa.dispatchMethod(La,"rationalCurveTransform",[this._data,a]).then(function(a){return new Ta(a)})},point:function(a){return Ia.rationalCurvePoint(this._data,a)},pointAsync:function(a){return Pa.dispatchMethod(Ia,"rationalCurvePoint",[this._data,a])},tangent:function(a){return Ia.rationalCurveTangent(this._data,a)},tangentAsync:function(a){return Pa.dispatchMethod(Ia,"rationalCurveTangent",[this._data,a])},derivatives:function(a,b){return null==b&&(b=1),Ia.rationalCurveDerivatives(this._data,a,b)},derivativesAsync:function(a,b){return null==b&&(b=1),Pa.dispatchMethod(Ia,"rationalCurveDerivatives",[this._data,a,b])},closestPoint:function(a){return Da.rationalCurveClosestPoint(this._data,a)},closestPointAsync:function(a){return Pa.dispatchMethod(Da,"rationalCurveClosestPoint",[this._data,a])},closestParam:function(a){return Da.rationalCurveClosestParam(this._data,a)},closestParamAsync:function(a){return Pa.dispatchMethod(Da,"rationalCurveClosestParam",[this._data,a])},length:function(){return Da.rationalCurveArcLength(this._data)},lengthAsync:function(){return Pa.dispatchMethod(Da,"rationalCurveArcLength",[this._data])},lengthAtParam:function(a){return Da.rationalCurveArcLength(this._data,a)},lengthAtParamAsync:function(){return Pa.dispatchMethod(Da,"rationalCurveArcLength",[this._data])},paramAtLength:function(a,b){return Da.rationalCurveParamAtArcLength(this._data,a,b)},paramAtLengthAsync:function(a,b){return Pa.dispatchMethod(Da,"rationalCurveParamAtArcLength",[this._data,a,b])},divideByEqualArcLength:function(a){return Ga.rationalCurveByEqualArcLength(this._data,a)},divideByEqualArcLengthAsync:function(a){return Pa.dispatchMethod(Ga,"rationalCurveByEqualArcLength",[this._data,a])},divideByArcLength:function(a){return Ga.rationalCurveByArcLength(this._data,a)},divideByArcLengthAsync:function(a){return Pa.dispatchMethod(Ga,"rationalCurveByArcLength",[this._data,a])},split:function(a){return Ga.curveSplit(this._data,a).map(function(a){return new Ta(a)})},splitAsync:function(a){return Pa.dispatchMethod(Ga,"curveSplit",[this._data,a]).then(function(a){return a.map(function(a){return new Ta(a)})})},reverse:function(){return new Ta(La.curveReverse(this._data))},reverseAsync:function(){return Pa.dispatchMethod(La,"curveReverse",[this._data]).then(function(a){return new Ta(a)})},tessellate:function(a){return Ma.rationalCurveAdaptiveSample(this._data,a,!1)},tessellateAsync:function(a){return Pa.dispatchMethod(Ma,"rationalCurveAdaptiveSample",[this._data,a,!1])},__class__:Ta});var Ua=b.geom.Arc=function(a,b,c,d,e,f){Ta.call(this,Ka.arc(a,b,c,d,e,f)),this._center=a,this._xaxis=b,this._yaxis=c,this._radius=d,this._minAngle=e,this._maxAngle=f};g["verb.geom.Arc"]=Ua,Ua.__name__=["verb","geom","Arc"],Ua.__super__=Ta,Ua.prototype=d(Ta.prototype,{center:function(){return this._center},xaxis:function(){return this._xaxis},yaxis:function(){return this._yaxis},radius:function(){return this._radius},minAngle:function(){return this._minAngle},maxAngle:function(){return this._maxAngle},__class__:Ua});var Va=b.geom.BezierCurve=function(a,b){Ta.call(this,Ka.rationalBezierCurve(a,b))};g["verb.geom.BezierCurve"]=Va,Va.__name__=["verb","geom","BezierCurve"],Va.__super__=Ta,Va.prototype=d(Ta.prototype,{__class__:Va});var Wa=b.geom.Circle=function(a,b,c,d){Ua.call(this,a,b,c,d,0,2*Math.PI)};g["verb.geom.Circle"]=Wa,Wa.__name__=["verb","geom","Circle"],Wa.__super__=Ua,Wa.prototype=d(Ua.prototype,{__class__:Wa});var Xa=function(){};g["verb.geom.ISurface"]=Xa,Xa.__name__=["verb","geom","ISurface"],Xa.__interfaces__=[za],Xa.prototype={__class__:Xa};var Ya=b.geom.NurbsSurface=function(a){this._data=Fa.isValidNurbsSurfaceData(a)};g["verb.geom.NurbsSurface"]=Ya,Ya.__name__=["verb","geom","NurbsSurface"],Ya.__interfaces__=[Xa],Ya.byKnotsControlPointsWeights=function(a,b,c,d,e,f){return new Ya(new X(a,b,c,d,Ia.homogenize2d(e,f)))},Ya.byCorners=function(a,b,c,d){return new Ya(Ka.fourPointSurface(a,b,c,d))},Ya.byLoftingCurves=function(a,b){return new Ya(Ka.loftedSurface(function(b){for(var c,d=[],e=0;e>>>>>> master diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 7a55b642..b41c12df 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -1868,7 +1868,7 @@ var verb_Verb = function() { }; $hxClasses["verb.Verb"] = verb_Verb; verb_Verb.__name__ = ["verb","Verb"]; verb_Verb.main = function() { - console.log("verb 2.0.0"); + console.log("verb 2.1.0"); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -3402,6 +3402,55 @@ verb_core_Vec.addAll = function(a) { return verb_core_Vec.add(a1,x); },verb_core_Vec.rep(f,0.0)); }; +verb_core_Vec.addAllMutate = function(a) { + var f = a[0]; + var _g1 = 1; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + verb_core_Vec.addMutate(f,a[i]); + } +}; +verb_core_Vec.addMulMutate = function(a,s,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] + s * b[i]; + } +}; +verb_core_Vec.subMulMutate = function(a,s,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] - s * b[i]; + } +}; +verb_core_Vec.addMutate = function(a,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] + b[i]; + } +}; +verb_core_Vec.subMutate = function(a,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] - b[i]; + } +}; +verb_core_Vec.mulMutate = function(a,b) { + var _g1 = 0; + var _g = b.length; + while(_g1 < _g) { + var i = _g1++; + b[i] = b[i] * a; + } +}; verb_core_Vec.norm = function(a) { var norm2 = verb_core_Vec.normSquared(a); if(norm2 != 0.0) return Math.sqrt(norm2); else return norm2; @@ -3676,11 +3725,12 @@ verb_eval_Analyze.rationalCurveClosestParam = function(curve,p) { var _g = pts.length - 1; while(_g1 < _g) { var i1 = _g1++; - var u0 = pts[i1][0]; - var u11 = pts[i1 + 1][0]; - var p0 = pts[i1].slice(1); - var p1 = pts[i1 + 1].slice(1); - var proj = verb_core_Trig.segmentClosestPoint(p,p0,p1,u0,u11); + var u0 = pts[i1].pop(); + var u11 = pts[i1 + 1].pop(); + var p0 = pts[i1]; + var p01 = pts[i1]; + var p1 = pts[i1 + 1]; + var proj = verb_core_Trig.segmentClosestPoint(p,p01,p1,u0,u11); var d1 = verb_core_Vec.norm(verb_core_Vec.sub(p,proj.pt)); if(d1 < min) { min = d1; @@ -4009,23 +4059,24 @@ verb_eval_Eval.rationalSurfaceDerivatives = function(surface,u,v,numDerivs) { var _g4 = l + 1; while(_g5 < _g4) { var j = _g5++; - v1 = verb_core_Vec.sub(v1,verb_core_Vec.mul(verb_core_Binomial.get(l,j) * wders[0][j],SKL[k][l - j])); + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(l,j) * wders[0][j],SKL[k][l - j]); } var _g51 = 1; var _g41 = k + 1; while(_g51 < _g41) { var i = _g51++; - v1 = verb_core_Vec.sub(v1,verb_core_Vec.mul(verb_core_Binomial.get(k,i) * wders[i][0],SKL[k - i][l])); + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(k,i) * wders[i][0],SKL[k - i][l]); var v2 = verb_core_Vec.zeros1d(dim); var _g7 = 1; var _g6 = l + 1; while(_g7 < _g6) { var j1 = _g7++; - v2 = verb_core_Vec.add(v2,verb_core_Vec.mul(verb_core_Binomial.get(l,j1) * wders[i][j1],SKL[k - i][l - j1])); + verb_core_Vec.addMulMutate(v2,verb_core_Binomial.get(l,j1) * wders[i][j1],SKL[k - i][l - j1]); } - v1 = verb_core_Vec.sub(v1,verb_core_Vec.mul(verb_core_Binomial.get(k,i),v2)); + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(k,i),v2); } - SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],v1)); + verb_core_Vec.mulMutate(1 / wders[0][0],v1); + SKL[k].push(v1); } } return SKL; @@ -4050,9 +4101,10 @@ verb_eval_Eval.rationalCurveDerivatives = function(curve,u,numDerivs) { var _g2 = k1 + 1; while(_g3 < _g2) { var i1 = _g3++; - v = verb_core_Vec.sub(v,verb_core_Vec.mul(verb_core_Binomial.get(k1,i1) * wders[i1],CK[k1 - i1])); + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k1,i1) * wders[i1],CK[k1 - i1]); } - CK.push(verb_core_Vec.mul(1 / wders[0],v)); + verb_core_Vec.mulMutate(1 / wders[0],v); + CK.push(v); } return CK; }; @@ -4076,7 +4128,7 @@ verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { if(numDerivs < degreeU) du = numDerivs; else du = degreeU; var dv; if(numDerivs < degreeV) dv = numDerivs; else dv = degreeV; - var SKL = verb_core_Vec.zeros3d(numDerivs + 1,numDerivs + 1,dim); + var SKL = verb_core_Vec.zeros3d(du + 1,dv + 1,dim); var knotSpan_index_u = verb_eval_Eval.knotSpanGivenN(n,degreeU,u,knotsU); var knotSpan_index_v = verb_eval_Eval.knotSpanGivenN(m,degreeV,v,knotsV); var uders = verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index_u,u,degreeU,n,knotsU); @@ -4096,7 +4148,7 @@ verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { var _g4 = degreeU + 1; while(_g5 < _g4) { var r = _g5++; - temp[s] = verb_core_Vec.add(temp[s],verb_core_Vec.mul(uders[k][r],controlPoints[knotSpan_index_u - degreeU + r][knotSpan_index_v - degreeV + s])); + verb_core_Vec.addMulMutate(temp[s],uders[k][r],controlPoints[knotSpan_index_u - degreeU + r][knotSpan_index_v - degreeV + s]); } } var nk = numDerivs - k; @@ -4110,7 +4162,7 @@ verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { var _g41 = degreeV + 1; while(_g51 < _g41) { var s1 = _g51++; - SKL[k][l] = verb_core_Vec.add(SKL[k][l],verb_core_Vec.mul(vders[l][s1],temp[s1])); + verb_core_Vec.addMulMutate(SKL[k][l],vders[l][s1],temp[s1]); } } } @@ -4147,12 +4199,199 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { var _g2 = degreeU + 1; while(_g3 < _g2) { var k = _g3++; - temp = verb_core_Vec.add(temp,verb_core_Vec.mul(u_basis_vals[k],controlPoints[uind + k][vind])); + verb_core_Vec.addMulMutate(temp,u_basis_vals[k],controlPoints[uind + k][vind]); } - position = verb_core_Vec.add(position,verb_core_Vec.mul(v_basis_vals[l],temp)); + verb_core_Vec.addMulMutate(position,v_basis_vals[l],temp); } return position; }; +verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { + var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); + var allratders = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var numDerivs1 = numDerivs + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var rowders = []; + allratders.push(rowders); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + var ders = allders[i][j]; + var Aders = verb_eval_Eval.rational2d(ders); + var wders = verb_eval_Eval.weight2d(ders); + var SKL = []; + var dim = Aders[0][0].length; + var _g2 = 0; + while(_g2 < numDerivs1) { + var k = _g2++; + SKL.push([]); + var _g4 = 0; + var _g3 = numDerivs1 - k; + while(_g4 < _g3) { + var l = _g4++; + var v = Aders[k][l]; + var _g6 = 1; + var _g5 = l + 1; + while(_g6 < _g5) { + var j1 = _g6++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(l,j1) * wders[0][j1],SKL[k][l - j1]); + } + var _g61 = 1; + var _g51 = k + 1; + while(_g61 < _g51) { + var i1 = _g61++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1) * wders[i1][0],SKL[k - i1][l]); + var v2 = verb_core_Vec.zeros1d(dim); + var _g8 = 1; + var _g7 = l + 1; + while(_g8 < _g7) { + var j2 = _g8++; + verb_core_Vec.addMulMutate(v2,verb_core_Binomial.get(l,j2) * wders[i1][j2],SKL[k - i1][l - j2]); + } + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1),v2); + } + verb_core_Vec.mulMutate(1 / wders[0][0],v); + SKL[k].push(v); + } + } + rowders.push(SKL); + } + } + return allratders; +}; +verb_eval_Eval.surfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var dim = controlPoints[0][0].length; + var spanU = (verb_core_ArrayExtensions.last(knotsU) - knotsU[0]) / divsU; + var spanV = (verb_core_ArrayExtensions.last(knotsV) - knotsV[0]) / divsV; + var knotSpansBasesU = verb_eval_Eval.regularlySpacedDerivativeBasisFunctions(degreeU,knotsU,divsU); + var knotSpansU = knotSpansBasesU.item0; + var basesU = knotSpansBasesU.item1; + var knotSpansBasesV = verb_eval_Eval.regularlySpacedDerivativeBasisFunctions(degreeV,knotsV,divsV); + var knotSpansV = knotSpansBasesV.item0; + var basesV = knotSpansBasesV.item1; + var pts = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var ptsi = []; + pts.push(ptsi); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + ptsi.push(verb_eval_Eval.surfaceDerivativesGivenBasesKnotSpans(degreeU,degreeV,controlPoints,knotSpansU[i],knotSpansV[j],basesU[i],basesV[j],dim,numDerivs)); + } + } + return pts; +}; +verb_eval_Eval.regularlySpacedBasisFunctions = function(degree,knots,divs) { + var n = knots.length - degree - 2; + var span = (verb_core_ArrayExtensions.last(knots) - knots[0]) / divs; + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var div1 = divs + 1; + var _g = 0; + while(_g < div1) { + var i = _g++; + while(u >= knots[knotIndex + 1]) knotIndex++; + knotspans.push(knotIndex); + bases.push(verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotIndex,u,degree,knots)); + u += span; + } + return new verb_core_Pair(knotspans,bases); +}; +verb_eval_Eval.regularlySpacedDerivativeBasisFunctions = function(degree,knots,divs) { + var n = knots.length - degree - 2; + var span = (verb_core_ArrayExtensions.last(knots) - knots[0]) / divs; + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var div1 = divs + 1; + var _g = 0; + while(_g < div1) { + var i = _g++; + while(u >= knots[knotIndex + 1]) knotIndex++; + knotspans.push(knotIndex); + bases.push(verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotIndex,u,degree,n,knots)); + u += span; + } + return new verb_core_Pair(knotspans,bases); +}; +verb_eval_Eval.surfacePointGivenBasesKnotSpans = function(degreeU,degreeV,controlPoints,knotSpanU,knotSpanV,basesU,basesV,dim) { + var position = verb_core_Vec.zeros1d(dim); + var temp; + var uind = knotSpanU - degreeU; + var vind = knotSpanV - degreeV; + var _g1 = 0; + var _g = degreeV + 1; + while(_g1 < _g) { + var l = _g1++; + temp = verb_core_Vec.zeros1d(dim); + var _g3 = 0; + var _g2 = degreeU + 1; + while(_g3 < _g2) { + var k = _g3++; + verb_core_Vec.addMulMutate(temp,basesU[k],controlPoints[uind + k][vind]); + } + vind++; + verb_core_Vec.addMulMutate(position,basesV[l],temp); + } + return position; +}; +verb_eval_Eval.surfaceDerivativesGivenBasesKnotSpans = function(degreeU,degreeV,controlPoints,knotSpanU,knotSpanV,basesU,basesV,dim,numDerivs) { + var dim1 = controlPoints[0][0].length; + var du; + if(numDerivs < degreeU) du = numDerivs; else du = degreeU; + var dv; + if(numDerivs < degreeV) dv = numDerivs; else dv = degreeV; + var SKL = verb_core_Vec.zeros3d(du + 1,dv + 1,dim1); + var temp = verb_core_Vec.zeros2d(degreeV + 1,dim1); + var dd = 0; + var _g1 = 0; + var _g = du + 1; + while(_g1 < _g) { + var k = _g1++; + var _g3 = 0; + var _g2 = degreeV + 1; + while(_g3 < _g2) { + var s = _g3++; + temp[s] = verb_core_Vec.zeros1d(dim1); + var _g5 = 0; + var _g4 = degreeU + 1; + while(_g5 < _g4) { + var r = _g5++; + verb_core_Vec.addMulMutate(temp[s],basesU[k][r],controlPoints[knotSpanU - degreeU + r][knotSpanV - degreeV + s]); + } + } + var nk = numDerivs - k; + if(nk < dv) dd = nk; else dd = dv; + var _g31 = 0; + var _g21 = dd + 1; + while(_g31 < _g21) { + var l = _g31++; + SKL[k][l] = verb_core_Vec.zeros1d(dim1); + var _g51 = 0; + var _g41 = degreeV + 1; + while(_g51 < _g41) { + var s1 = _g51++; + verb_core_Vec.addMulMutate(SKL[k][l],basesV[l][s1],temp[s1]); + } + } + } + return SKL; +}; verb_eval_Eval.curveDerivatives = function(crv,u,numDerivs) { var n = crv.knots.length - crv.degree - 2; return verb_eval_Eval.curveDerivativesGivenN(n,crv,u,numDerivs); @@ -4178,7 +4417,7 @@ verb_eval_Eval.curveDerivativesGivenN = function(n,curve,u,numDerivs) { var _g2 = degree + 1; while(_g3 < _g2) { var j1 = _g3++; - CK[k1] = verb_core_Vec.add(CK[k1],verb_core_Vec.mul(nders[k1][j1],controlPoints[knotSpan_index - degree + j1])); + verb_core_Vec.addMulMutate(CK[k1],nders[k1][j1],controlPoints[knotSpan_index - degree + j1]); } } return CK; @@ -4205,7 +4444,7 @@ verb_eval_Eval.curvePointGivenN = function(n,curve,u) { var _g = degree + 1; while(_g1 < _g) { var j = _g1++; - position = verb_core_Vec.add(position,verb_core_Vec.mul(basis_values[j],controlPoints[knotSpan_index - degree + j])); + verb_core_Vec.addMulMutate(position,basis_values[j],controlPoints[knotSpan_index - degree + j]); } return position; }; @@ -4251,11 +4490,11 @@ verb_eval_Eval.volumePointGivenNML = function(volume,n,m,l,u,v,w) { var _g4 = degreeU + 1; while(_g5 < _g4) { var k = _g5++; - temp = verb_core_Vec.add(temp,verb_core_Vec.mul(u_basis_vals[k],controlPoints[uind + k][vind][wind])); + verb_core_Vec.addMulMutate(temp,u_basis_vals[k],controlPoints[uind + k][vind][wind]); } - temp2 = verb_core_Vec.add(temp2,verb_core_Vec.mul(v_basis_vals[j],temp)); + verb_core_Vec.addMulMutate(temp2,v_basis_vals[j],temp); } - position = verb_core_Vec.add(position,verb_core_Vec.mul(w_basis_vals[i],temp2)); + verb_core_Vec.addMulMutate(position,w_basis_vals[i],temp2); } return position; }; @@ -4265,7 +4504,7 @@ verb_eval_Eval.derivativeBasisFunctions = function(u,degree,knots) { var n = m - degree - 1; return verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index,u,degree,n,knots); }; -verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotSpan_index,u,p,n,knots) { +verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotIndex,u,p,n,knots) { var ndu = verb_core_Vec.zeros2d(p + 1,p + 1); var left = verb_core_Vec.zeros1d(p + 1); var right = verb_core_Vec.zeros1d(p + 1); @@ -4276,8 +4515,8 @@ verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotSpan_index,u,p,n,k var _g = p + 1; while(_g1 < _g) { var j = _g1++; - left[j] = u - knots[knotSpan_index + 1 - j]; - right[j] = knots[knotSpan_index + j] - u; + left[j] = u - knots[knotIndex + 1 - j]; + right[j] = knots[knotIndex + j] - u; saved = 0.0; var _g2 = 0; while(_g2 < j) { @@ -5115,6 +5354,25 @@ verb_eval_Make.clonedCurve = function(curve) { return x.slice(); })); }; +verb_eval_Make.clonedSurface = function(surface) { + var newpts = []; + var newrow; + var _g = 0; + var _g1 = surface.controlPoints; + while(_g < _g1.length) { + var row = _g1[_g]; + ++_g; + newrow = []; + newpts.push(newrow); + var _g2 = 0; + while(_g2 < row.length) { + var pt = row[_g2]; + ++_g2; + newrow.push(pt.slice()); + } + } + return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),surface.knotsV.slice(),newpts); +}; verb_eval_Make.rationalBezierCurve = function(controlPoints,weights) { var degree = controlPoints.length - 1; var knots = []; @@ -5794,32 +6052,205 @@ verb_eval_Modify.rationalCurveTransform = function(curve,mat) { return new verb_core_NurbsCurveData(curve.degree,curve.knots.slice(),verb_eval_Eval.homogenize1d(pts,verb_eval_Eval.weight1d(curve.controlPoints))); }; verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { - var newPts = []; - var knots; + if(knotsToInsert.length == 0) return verb_eval_Make.clonedSurface(surface); var degree; - var ctrlPts; - if(!useV) { - ctrlPts = verb_core_Mat.transpose(surface.controlPoints); - knots = surface.knotsU; + var controlPoints = surface.controlPoints; + var knots; + if(useV) { + degree = surface.degreeV; + knots = surface.knotsV; + } else { degree = surface.degreeU; + knots = surface.knotsU; + } + var n; + if(useV) n = controlPoints[0].length - 1; else n = controlPoints.length - 1; + var m = n + degree + 1; + var r = knotsToInsert.length - 1; + var a = verb_eval_Eval.knotSpan(degree,knotsToInsert[0],knots); + var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); + var controlPoints_post = []; + var knots_post = []; + if(useV) { + var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); + var _g1 = 0; + var _g = controlPoints.length + km.length - 1; + while(_g1 < _g) { + var i1 = _g1++; + controlPoints_post.push([]); + } + var _g11 = 0; + var _g2 = a - degree + 1; + while(_g11 < _g2) { + var i2 = _g11++; + var _g3 = 0; + var _g21 = controlPoints.length; + while(_g3 < _g21) { + var j1 = _g3++; + controlPoints_post[j1][i2] = controlPoints[j1][i2]; + } + } + var _g12 = b - 1; + var _g4 = n + 1; + while(_g12 < _g4) { + var i3 = _g12++; + var l = i3 + r + 1; + var _g31 = 0; + var _g22 = controlPoints.length; + while(_g31 < _g22) { + var j2 = _g31++; + controlPoints_post[j2][l] = controlPoints[j2][i3]; + } + } } else { - ctrlPts = surface.controlPoints; - knots = surface.knotsV; - degree = surface.degreeV; + var _g13 = 0; + var _g5 = a - degree + 1; + while(_g13 < _g5) { + var i4 = _g13++; + controlPoints_post[i4] = controlPoints[i4].slice(0); + } + var _g14 = b - 1; + var _g6 = n + 1; + while(_g14 < _g6) { + var i5 = _g14++; + controlPoints_post[i5 + r + 1] = controlPoints[i5].slice(0); + } } - var c = null; + var _g15 = 0; + var _g7 = a + 1; + while(_g15 < _g7) { + var i6 = _g15++; + knots_post[i6] = knots[i6]; + } + var _g16 = b + degree; + var _g8 = m + 1; + while(_g16 < _g8) { + var i7 = _g16++; + knots_post[i7 + r + 1] = knots[i7]; + } + var i = b + degree - 1; + var k = b + degree + r; + var j = r; + var ci; + while(j >= 0) { + while(knotsToInsert[j] <= knots[i] && i > a) { + var wi = k - degree - 1; + var xi = i - degree - 1; + if(useV) { + var _g17 = 0; + var _g9 = controlPoints_post.length; + while(_g17 < _g9) { + var ci1 = _g17++; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi].slice(0); + } + } else controlPoints_post[wi] = controlPoints[xi].slice(0); + knots_post[k] = knots[i]; + k = k - 1; + i = i - 1; + } + if(useV) { + var _g18 = 0; + var _g10 = controlPoints_post.length; + while(_g18 < _g10) { + var ci2 = _g18++; + controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree].slice(0); + } + } else controlPoints_post[k - degree - 1] = controlPoints_post[k - degree].slice(0); + var _g19 = 1; + var _g20 = degree + 1; + while(_g19 < _g20) { + var l1 = _g19++; + var ind = k - degree + l1; + var alfa = knots_post[k + l1] - knotsToInsert[j]; + if(Math.abs(alfa) < verb_core_Constants.EPSILON) { + if(useV) { + var _g32 = 0; + var _g23 = controlPoints_post.length; + while(_g32 < _g23) { + var ci3 = _g32++; + controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; + } + } else controlPoints_post[ind - 1] = controlPoints_post[ind].slice(0); + } else { + alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); + if(useV) { + var _g33 = 0; + var _g24 = controlPoints_post.length; + while(_g33 < _g24) { + var wi1 = _g33++; + controlPoints_post[wi1][ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[wi1][ind - 1],controlPoints_post[wi1][ind]); + } + } else { + var _g34 = 0; + var _g25 = controlPoints_post[ind].length; + while(_g34 < _g25) { + var wi2 = _g34++; + controlPoints_post[ind - 1][wi2] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1][wi2],controlPoints_post[ind][wi2]); + } + } + } + } + knots_post[k] = knotsToInsert[j]; + k = k - 1; + j--; + } + if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),knots_post,controlPoints_post); else return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,knots_post,surface.knotsV.slice(),controlPoints_post); +}; +verb_eval_Modify.decomposeSurfaceIntoBeziers = function(surface) { + var knotmultsU = verb_eval_Analyze.knotMultiplicities(surface.knotsU); + var reqMultU = surface.degreeU + 1; var _g = 0; - while(_g < ctrlPts.length) { - var cptrow = ctrlPts[_g]; + while(_g < knotmultsU.length) { + var knotmult = knotmultsU[_g]; ++_g; - c = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,cptrow),knotsToInsert); - newPts.push(c.controlPoints); + if(knotmult.mult < reqMultU) { + var knotsInsert = verb_core_Vec.rep(reqMultU - knotmult.mult,knotmult.knot); + if(knotsInsert.length == 0) continue; + surface = verb_eval_Modify.surfaceKnotRefine(surface,knotsInsert,false); + } } - var newknots = c.knots; - if(!useV) { - newPts = verb_core_Mat.transpose(newPts); - return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,newknots,surface.knotsV.slice(),newPts); - } else return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),newknots,newPts); + var knotmultsV = verb_eval_Analyze.knotMultiplicities(surface.knotsV); + var reqMultV = surface.degreeV + 1; + var _g1 = 0; + while(_g1 < knotmultsV.length) { + var knotmult1 = knotmultsV[_g1]; + ++_g1; + if(knotmult1.mult < reqMultV) { + var knotsInsert1 = verb_core_Vec.rep(reqMultV - knotmult1.mult,knotmult1.knot); + if(knotsInsert1.length == 0) continue; + surface = verb_eval_Modify.surfaceKnotRefine(surface,knotsInsert1,true); + } + } + var numU = surface.knotsU.length / reqMultU - 1; + var numV = surface.knotsV.length / reqMultV - 1; + var knotLengthU = reqMultU * 2; + var knotLengthV = reqMultV * 2; + var subSurfaces = []; + var i = 0; + while(i < surface.controlPoints.length) { + var row = []; + subSurfaces.push(row); + var ktsU = surface.knotsU.slice(i,i + knotLengthU); + var j = 0; + while(j < surface.controlPoints[i].length) { + var ktsV = surface.knotsV.slice(j,j + knotLengthV); + var pts = verb_eval_Modify.submatrix(surface.controlPoints,i,j,reqMultV,reqMultU); + row.push(new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,ktsU,ktsV,pts)); + j += reqMultV; + } + i += reqMultU; + } + return subSurfaces; +}; +verb_eval_Modify.submatrix = function(mat,startRow,startCol,rows,cols) { + var newmat = []; + var _g1 = startRow; + var _g = startRow + rows; + while(_g1 < _g) { + var i = _g1++; + newmat.push(mat[i].slice(startCol,startCol + cols)); + } + return newmat; }; verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { var degree = curve.degree; @@ -5833,6 +6264,7 @@ verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { ++_g; if(knotmult.mult < reqMult) { var knotsInsert = verb_core_Vec.rep(reqMult - knotmult.mult,knotmult.knot); + if(knotsInsert.length == 0) continue; var res = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,controlPoints),knotsInsert); knots = res.knots; controlPoints = res.controlPoints; @@ -5905,7 +6337,7 @@ verb_eval_Modify.curveKnotRefine = function(curve,knotsToInsert) { var alfa = knots_post[k + l] - knotsToInsert[j]; if(Math.abs(alfa) < verb_core_Constants.EPSILON) controlPoints_post[ind - 1] = controlPoints_post[ind]; else { alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); - controlPoints_post[ind - 1] = verb_core_Vec.add(verb_core_Vec.mul(alfa,controlPoints_post[ind - 1]),verb_core_Vec.mul(1.0 - alfa,controlPoints_post[ind])); + controlPoints_post[ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1],controlPoints_post[ind]); } } knots_post[k] = knotsToInsert[j]; @@ -5973,7 +6405,7 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { while(_g31 < _g21) { var i7 = _g31++; alpha = (u - knots[L + i7]) / (knots[i7 + k + 1] - knots[L + i7]); - controlPoints_temp[i7] = verb_core_Vec.add(verb_core_Vec.mul(alpha,controlPoints_temp[i7 + 1]),verb_core_Vec.mul(1.0 - alpha,controlPoints_temp[i7])); + controlPoints_temp[i7] = verb_core_Vec.add(verb_core_Vec.mul(1.0 - alpha,controlPoints_temp[i7]),verb_core_Vec.mul(alpha,controlPoints_temp[i7 + 1])); } controlPoints_post[L] = controlPoints_temp[0]; controlPoints_post[k + r - j - s] = controlPoints_temp[degree - j - s]; @@ -5986,56 +6418,629 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { } return new verb_core_NurbsCurveData(degree,knots_post,controlPoints_post); }; +var verb_eval_NewMeshData = function() { }; +$hxClasses["verb.eval.NewMeshData"] = verb_eval_NewMeshData; +verb_eval_NewMeshData.__name__ = ["verb","eval","NewMeshData"]; +verb_eval_NewMeshData.prototype = { + __class__: verb_eval_NewMeshData +}; +var verb_eval_BezierEdgeIndices = function() { +}; +$hxClasses["verb.eval.BezierEdgeIndices"] = verb_eval_BezierEdgeIndices; +verb_eval_BezierEdgeIndices.__name__ = ["verb","eval","BezierEdgeIndices"]; +verb_eval_BezierEdgeIndices.prototype = { + __class__: verb_eval_BezierEdgeIndices +}; +var verb_eval_EdgeSide = $hxClasses["verb.eval.EdgeSide"] = { __ename__ : ["verb","eval","EdgeSide"], __constructs__ : ["North","South","East","West"] }; +verb_eval_EdgeSide.North = ["North",0]; +verb_eval_EdgeSide.North.toString = $estr; +verb_eval_EdgeSide.North.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.South = ["South",1]; +verb_eval_EdgeSide.South.toString = $estr; +verb_eval_EdgeSide.South.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.East = ["East",2]; +verb_eval_EdgeSide.East.toString = $estr; +verb_eval_EdgeSide.East.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.West = ["West",3]; +verb_eval_EdgeSide.West.toString = $estr; +verb_eval_EdgeSide.West.__enum__ = verb_eval_EdgeSide; var verb_eval_Tess = $hx_exports.eval.Tess = function() { }; $hxClasses["verb.eval.Tess"] = verb_eval_Tess; verb_eval_Tess.__name__ = ["verb","eval","Tess"]; -verb_eval_Tess.rationalCurveRegularSample = function(curve,numSamples,includeU) { - return verb_eval_Tess.rationalCurveRegularSampleRange(curve,curve.knots[0],verb_core_ArrayExtensions.last(curve.knots),numSamples,includeU); -}; -verb_eval_Tess.rationalCurveRegularSampleRange = function(curve,start,end,numSamples,includeU) { - if(numSamples < 1) numSamples = 2; - var p = []; - var span = (end - start) / (numSamples - 1); - var u = 0; +verb_eval_Tess.rationalBezierSurfaceRegularSample = function(surface,divsU,divsV) { + var pts = []; + var u = surface.knotsU[0]; + var t = (verb_core_ArrayExtensions.last(surface.knotsU) - surface.knotsU[0]) / divsU; var _g = 0; - while(_g < numSamples) { + while(_g < divsU) { var i = _g++; - u = start + span * i; - if(includeU) p.push([u].concat(verb_eval_Eval.rationalCurvePoint(curve,u))); else p.push(verb_eval_Eval.rationalCurvePoint(curve,u)); + var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); + var v = (verb_core_ArrayExtensions.last(iso.knots) - iso.knots[0]) / divsV; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(iso,pts,iso.knots[0],t,divsV,false); + u += t; + } + return pts; +}; +verb_eval_Tess.northIndex = function(i,j,divs) { + if(i <= 0) return null; + return divs[i - 1][j]; +}; +verb_eval_Tess.southIndex = function(i,j,divs) { + if(i >= divs.length - 1) return null; + return divs[i + 1][j]; +}; +verb_eval_Tess.eastIndex = function(i,j,divs) { + if(j >= divs[i].length - 1) return null; + return divs[i][j + 1]; +}; +verb_eval_Tess.westIndex = function(i,j,divs) { + if(j <= 0) return null; + return divs[i][j - 1]; +}; +verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { + var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); + var stepLengths = []; + var stepLengthRow; + var _g = 0; + while(_g < beziers.length) { + var bezierrow = beziers[_g]; + ++_g; + stepLengthRow = []; + stepLengths.push(stepLengthRow); + var _g1 = 0; + while(_g1 < bezierrow.length) { + var bezier = bezierrow[_g1]; + ++_g1; + var ls = verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol); + ls.item0 = Math.min(ls.item0,(verb_core_ArrayExtensions.last(bezier.knotsU) - verb_core_ArrayExtensions.first(bezier.knotsU)) / 2); + ls.item1 = Math.min(ls.item1,(verb_core_ArrayExtensions.last(bezier.knotsV) - verb_core_ArrayExtensions.first(bezier.knotsV)) / 2); + stepLengthRow.push(ls); + } + } + var pts = []; + var uvs = []; + var edgeRow; + var n; + var s; + var e; + var w; + var empty = new verb_core_Pair(Infinity,Infinity); + var beis = []; + var beir; + var bei; + var e0; + var e1; + var srf; + var _g11 = 0; + var _g2 = beziers.length; + while(_g11 < _g2) { + var i = _g11++; + beir = []; + beis.push(beir); + var _g3 = 0; + var _g21 = beziers[i].length; + while(_g3 < _g21) { + var j = _g3++; + srf = beziers[i][j]; + bei = new verb_eval_BezierEdgeIndices(); + beir.push(bei); + s = verb_eval_Tess.southIndex(i,j,stepLengths); + if(s == null) s = empty; + e = verb_eval_Tess.eastIndex(i,j,stepLengths); + if(e == null) e = empty; + if(i == 0) { + var ne = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.first(srf.knotsU),false); + e0 = pts.length; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(ne,pts,stepLengths[i][j].item1); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(ne.knots),stepLengths[i][j].item1,uvs,verb_core_ArrayExtensions.first(srf.knotsU),true); + bei.n = new verb_core_Pair(e0,e1); + } else bei.n = beis[i - 1][j].s; + if(j == 0) { + e0 = pts.length; + var we = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.first(srf.knotsV),true); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(we,pts,stepLengths[i][j].item0); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(we.knots),stepLengths[i][j].item0,uvs,verb_core_ArrayExtensions.first(srf.knotsV),false); + bei.w = new verb_core_Pair(e0,e1); + } else bei.w = beis[i][j - 1].e; + e0 = pts.length; + var se = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.last(srf.knotsU),false); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(se,pts,Math.min(s.item1,stepLengths[i][j].item1)); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(se.knots),Math.min(s.item1,stepLengths[i][j].item1),uvs,verb_core_ArrayExtensions.last(srf.knotsU),true); + bei.s = new verb_core_Pair(e0,e1); + e0 = pts.length; + var ee = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.last(srf.knotsV),true); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(ee,pts,Math.min(e.item0,stepLengths[i][j].item0)); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(ee.knots),Math.min(e.item0,stepLengths[i][j].item0),uvs,verb_core_ArrayExtensions.last(srf.knotsV),false); + bei.e = new verb_core_Pair(e0,e1); + } + } + var faces = []; + var p0; + var _g12 = 0; + var _g4 = beziers.length; + while(_g12 < _g4) { + var i1 = _g12++; + var _g31 = 0; + var _g22 = beziers[i1].length; + while(_g31 < _g22) { + var j1 = _g31++; + p0 = pts.length; + var bezier1 = beziers[i1][j1]; + var divsU = Math.ceil(1.0 / stepLengths[i1][j1].item0); + var domainV = verb_core_ArrayExtensions.last(bezier1.knotsV) - bezier1.knotsV[0]; + var domainU = verb_core_ArrayExtensions.last(bezier1.knotsU) - bezier1.knotsU[0]; + var divsV = Math.ceil(1.0 / stepLengths[i1][j1].item1); + var tessStepV = domainV / divsV; + var tessStepU = domainU / divsU; + var u = bezier1.knotsU[0] + tessStepU; + var _g5 = 0; + var _g41 = divsU - 1; + while(_g5 < _g41) { + var k = _g5++; + var iso = verb_eval_Make.surfaceIsocurve(bezier1,u,false); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(iso,pts,iso.knots[0] + tessStepV,tessStepV,divsV - 1,false); + verb_eval_Tess.regularUvsMutate(divsV - 1,iso.knots[0] + tessStepV,tessStepV,uvs,u,true); + u += tessStepU; + } + divsU = divsU - 2; + divsV = divsV - 2; + var _g42 = 0; + while(_g42 < divsU) { + var k1 = _g42++; + var _g51 = 0; + while(_g51 < divsV) { + var l = _g51++; + var a_k = p0 + k1 * (divsV + 1) + l; + var b_k = p0 + (k1 + 1) * (divsV + 1) + l; + var c_k = b_k + 1; + var d_k = a_k + 1; + var abc = [a_k,b_k,c_k]; + var acd = [a_k,c_k,d_k]; + faces.push(abc); + faces.push(acd); + } + } + bei = beis[i1][j1]; + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainV,p0,tessStepV,verb_eval_EdgeSide.North); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainV,p0,tessStepV,verb_eval_EdgeSide.South); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.East); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.West); + } + } + return new verb_core_MeshData(faces,pts,null,uvs); +}; +verb_eval_Tess.regularUvsMutate = function(count,start,step,uvs,constant,uConstant) { + var i = 0; + var u = start; + if(uConstant) while(i < count) { + uvs.push([constant,u]); + u += step; + i++; + } else while(i < count) { + uvs.push([u,constant]); + u += step; + i++; } - return p; }; -verb_eval_Tess.rationalCurveAdaptiveSample = function(curve,tol,includeU) { +verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tessStep,edgeSide) { + var edgeIndices; + var knots; + var reverseFace = false; + var tessIStep = 1; + var tessDivCount = 1; + switch(edgeSide[1]) { + case 0: + edgeIndices = bei.n; + knots = bezier.knotsV; + tessDivCount = divsV; + break; + case 1: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV + 1); + reverseFace = true; + tessDivCount = divsV; + break; + case 2: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV + 1; + p0 += divsV; + tessDivCount = divsU; + break; + case 3: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV + 1; + reverseFace = true; + tessDivCount = divsU; + break; + } + var edgeCount = edgeIndices.item1 - edgeIndices.item0 - 1; + var edgeStep = domain / edgeCount; + var edgeU = verb_core_ArrayExtensions.first(knots); + var tessU = verb_core_ArrayExtensions.first(knots) + 1.5 * tessStep; + var edgeI = 0; + var tessI = 0; + var tessDivI = 1; + while(edgeI < edgeCount) { + while(edgeU < tessU && edgeI < edgeCount || edgeI < edgeCount && tessDivI > tessDivCount) { + var ei = edgeIndices.item0 + edgeI; + var ei2 = ei + 1; + if(reverseFace) faces.push([ei,ei2,p0 + tessI]); else faces.push([ei,p0 + tessI,ei2]); + edgeI++; + edgeU += edgeStep; + } + if(edgeI < edgeCount) { + var ei1 = edgeIndices.item0 + edgeI; + if(reverseFace) faces.push([p0 + tessI,ei1,p0 + tessI + tessIStep]); else faces.push([p0 + tessI,p0 + tessI + tessIStep,ei1]); + } + tessDivI++; + tessI += tessIStep; + tessU += tessStep; + } +}; +verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2 = function(crv,pts,step,includeU) { if(includeU == null) includeU = false; - if(tol == null) tol = 1e-6; - if(curve.degree == 1) { - if(!includeU) return curve.controlPoints.map(verb_eval_Eval.dehomogenize); else { - var _g = []; - var _g2 = 0; - var _g1 = curve.controlPoints.length; - while(_g2 < _g1) { - var i = _g2++; - _g.push([curve.knots[i + 1]].concat(verb_eval_Eval.dehomogenize(curve.controlPoints[i]))); + var domain = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var steps = Math.ceil(1.0 / step); + var len = domain / steps; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(crv,pts,crv.knots[0],len,steps + 1,false); +}; +verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { + var dehomo = verb_eval_Eval.dehomogenize2d(surface.controlPoints); + var bb = new verb_core_BoundingBox(); + var _g = 0; + while(_g < dehomo.length) { + var row = dehomo[_g]; + ++_g; + bb.addRange(row); + } + var avgPt = verb_core_Vec.mul(0.5,verb_core_Vec.add(bb.min,bb.max)); + var m = verb_core_Mat.identity(4); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + var ts = verb_eval_Modify.rationalSurfaceTransform(surface,m); + dehomo = verb_eval_Eval.dehomogenize2d(ts.controlPoints); + var r = 0.0; + var n; + var _g1 = 0; + var _g2 = dehomo.length; + while(_g1 < _g2) { + var i = _g1++; + var _g3 = 0; + var _g21 = dehomo[i].length; + while(_g3 < _g21) { + var j = _g3++; + n = verb_core_Vec.norm(dehomo[i][j]); + if(n > r) r = n; + } + } + var duu = -Infinity; + var iduu; + var _g11 = 0; + var _g4 = surface.controlPoints.length - 2; + while(_g11 < _g4) { + var i1 = _g11++; + var _g31 = 0; + var _g22 = surface.controlPoints[i1].length; + while(_g31 < _g22) { + var j1 = _g31++; + iduu = verb_core_Vec.norm(verb_core_Vec.add(dehomo[i1 + 2][j1],verb_core_Vec.add(verb_core_Vec.mul(-2.0,dehomo[i1 + 1][j1]),dehomo[i1][j1]))) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i1 + 2][j1]) - 2 * verb_core_ArrayExtensions.last(ts.controlPoints[i1 + 1][j1]) + verb_core_ArrayExtensions.last(ts.controlPoints[i1][j1])); + if(iduu > duu) duu = iduu; + } + } + var dvv = -Infinity; + var idvv; + var _g12 = 0; + var _g5 = surface.controlPoints.length; + while(_g12 < _g5) { + var i2 = _g12++; + var _g32 = 0; + var _g23 = surface.controlPoints[i2].length - 2; + while(_g32 < _g23) { + var j2 = _g32++; + idvv = verb_core_Vec.norm(verb_core_Vec.add(dehomo[i2][j2 + 2],verb_core_Vec.add(verb_core_Vec.mul(-2.0,dehomo[i2][j2 + 1]),dehomo[i2][j2]))) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2 + 2]) - 2 * verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2 + 1]) + verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2])); + if(idvv > dvv) dvv = idvv; + } + } + var duv = -Infinity; + var iduv; + var _g13 = 0; + var _g6 = surface.controlPoints.length - 1; + while(_g13 < _g6) { + var i3 = _g13++; + var _g33 = 0; + var _g24 = surface.controlPoints[i3].length - 1; + while(_g33 < _g24) { + var j3 = _g33++; + iduv = verb_core_Vec.norm(verb_core_Vec.addAll([dehomo[i3 + 1][j3 + 1],verb_core_Vec.mul(-1.0,dehomo[i3][j3 + 1]),verb_core_Vec.mul(-1.0,dehomo[i3 + 1][j3]),dehomo[i3][j3]])) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i3 + 1][j3 + 1]) - verb_core_ArrayExtensions.last(ts.controlPoints[i3][j3 + 1]) - verb_core_ArrayExtensions.last(ts.controlPoints[i3 + 1][j3]) + verb_core_ArrayExtensions.last(ts.controlPoints[i3][j3])); + if(iduv > duv) duv = iduv; + } + } + duu *= surface.degreeU * (surface.degreeU - 1); + dvv *= surface.degreeV * (surface.degreeV - 1); + duv *= surface.degreeU * surface.degreeV; + var minw = Infinity; + var w; + var _g14 = 0; + var _g7 = surface.controlPoints.length; + while(_g14 < _g7) { + var i4 = _g14++; + var _g34 = 0; + var _g25 = surface.controlPoints[i4].length; + while(_g34 < _g25) { + var j4 = _g34++; + w = verb_core_ArrayExtensions.last(surface.controlPoints[i4][j4]); + if(w < minw) minw = w; + } + } + var stepu; + var stepv; + if(Math.abs(duu) < verb_core_Constants.TOLERANCE) { + stepu = 1.0; + if(Math.abs(dvv) < verb_core_Constants.TOLERANCE) { + stepv = 1.0; + return new verb_core_Pair(stepu,stepv); + } + stepv = (Math.sqrt(duv * duv + 8 * dvv * tol * minw) - duv) / dvv; + } + if(Math.abs(dvv) < verb_core_Constants.TOLERANCE) { + stepv = 1.0; + stepu = (Math.sqrt(duv * duv + 8 * duu * tol * minw) - duv) / duu; + return new verb_core_Pair(stepu,stepv); + } + var unum; + var vnum; + var denom; + unum = 4 * dvv * tol * minw; + denom = duu * dvv + duv * Math.sqrt(duu * dvv); + stepu = Math.sqrt(unum / denom); + vnum = 4 * duu * tol * minw; + stepv = Math.sqrt(vnum / denom); + return new verb_core_Pair(stepu,stepv); +}; +verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { + if(includeU == null) includeU = false; + if(crv.degree == 1) { + var pts1 = []; + var _g1 = 0; + var _g = crv.controlPoints.length; + while(_g1 < _g) { + var i = _g1++; + pts1.push(verb_eval_Eval.dehomogenize(crv.controlPoints[i])); + } + if(includeU) { + var _g11 = 0; + var _g2 = crv.controlPoints.length; + while(_g11 < _g2) { + var i1 = _g11++; + pts1[i1].push(crv.knots[i1 + 1]); } - return _g; - } - } - return verb_eval_Tess.rationalCurveAdaptiveSampleRange(curve,curve.knots[0],verb_core_ArrayExtensions.last(curve.knots),tol,includeU); -}; -verb_eval_Tess.rationalCurveAdaptiveSampleRange = function(curve,start,end,tol,includeU) { - var p1 = verb_eval_Eval.rationalCurvePoint(curve,start); - var p3 = verb_eval_Eval.rationalCurvePoint(curve,end); - var t = 0.5 + 0.2 * Math.random(); - var mid = start + (end - start) * t; - var p2 = verb_eval_Eval.rationalCurvePoint(curve,mid); - var diff = verb_core_Vec.sub(p1,p3); - var diff2 = verb_core_Vec.sub(p1,p2); - if(verb_core_Vec.dot(diff,diff) < tol && verb_core_Vec.dot(diff2,diff2) > tol || !verb_core_Trig.threePointsAreFlat(p1,p2,p3,tol)) { - var exact_mid = start + (end - start) * 0.5; - var left_pts = verb_eval_Tess.rationalCurveAdaptiveSampleRange(curve,start,exact_mid,tol,includeU); - var right_pts = verb_eval_Tess.rationalCurveAdaptiveSampleRange(curve,exact_mid,end,tol,includeU); - return left_pts.slice(0,-1).concat(right_pts); - } else if(includeU) return [[start].concat(p1),[end].concat(p3)]; else return [p1,p3]; + } + return pts1; + } + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var beziers; + if(crv.knots.length == (crv.degree + 1) * 2) beziers = [crv]; else beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var brange; + var fraction; + var currentU = crv.knots[0]; + var step = range / divs; + var brange1; + var bsteps; + var nextU; + var _g12 = 0; + var _g3 = beziers.length; + while(_g12 < _g3) { + var i2 = _g12++; + brange1 = verb_core_ArrayExtensions.last(beziers[i2].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i2].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,currentU,step,bsteps + 1,includeU); + currentU = nextU + step; + } + return pts; +}; +verb_eval_Tess.rationalCurveAdaptiveSample = function(crv,tol,includeU) { + if(includeU == null) includeU = false; + if(crv.degree == 1) { + var pts1 = []; + var _g1 = 0; + var _g = crv.controlPoints.length; + while(_g1 < _g) { + var i = _g1++; + pts1.push(verb_eval_Eval.dehomogenize(crv.controlPoints[i])); + } + if(includeU) { + var _g11 = 0; + var _g2 = crv.controlPoints.length; + while(_g11 < _g2) { + var i1 = _g11++; + pts1[i1].push(crv.knots[i1 + 1]); + } + } + return pts1; + } + var beziers; + if(crv.knots.length == (crv.degree + 1) * 2) beziers = [crv]; else beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var steps; + var domain; + var len; + var _g12 = 0; + var _g3 = beziers.length; + while(_g12 < _g3) { + var i2 = _g12++; + domain = verb_core_ArrayExtensions.last(beziers[i2].knots) - beziers[i2].knots[0]; + len = verb_eval_Tess.rationalBezierCurveStepLength(beziers[i2],tol); + steps = Math.ceil(domain / len); + len = domain / steps; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,beziers[i2].knots[0],len,steps + 1,includeU); + if(i2 == beziers.length - 1) break; + pts.pop(); + } + return pts; +}; +verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps,includeU) { + if(includeU == null) includeU = false; + var its = []; + var ts = [its]; + var u = startU; + var degree1 = crv.degree + 1; + if(numSteps <= crv.degree + 1) { + var _g = 0; + while(_g < numSteps) { + var i = _g++; + pts.push(verb_eval_Eval.rationalCurvePoint(crv,u)); + u += step; + } + return; + } + var _g1 = 0; + while(_g1 < degree1) { + var i1 = _g1++; + its.push(verb_eval_Eval.curvePoint(crv,u)); + u += step; + } + var prev; + var _g2 = 1; + while(_g2 < degree1) { + var i2 = _g2++; + its = []; + ts.push(its); + prev = ts[i2 - 1]; + var _g21 = 1; + var _g11 = prev.length; + while(_g21 < _g11) { + var j = _g21++; + its.push(verb_core_Vec.sub(prev[j],prev[j - 1])); + } + } + var _g3 = 0; + var _g12 = ts[0]; + while(_g3 < _g12.length) { + var pt = _g12[_g3]; + ++_g3; + pts.push(verb_eval_Eval.dehomogenize(pt)); + } + var front; + var _g4 = []; + var _g13 = 0; + while(_g13 < ts.length) { + var r = ts[_g13]; + ++_g13; + _g4.push(verb_core_ArrayExtensions.last(r)); + } + front = _g4; + var k; + var frlen2 = front.length - 2; + var _g22 = 0; + var _g14 = numSteps - degree1; + while(_g22 < _g14) { + var i3 = _g22++; + var _g41 = 0; + var _g31 = front.length - 1; + while(_g41 < _g31) { + var j1 = _g41++; + k = frlen2 - j1; + verb_core_Vec.addMutate(front[k],front[k + 1]); + } + pts.push(verb_eval_Eval.dehomogenize(front[0])); + } + u = startU; + if(includeU) { + var _g15 = 0; + while(_g15 < pts.length) { + var pt1 = pts[_g15]; + ++_g15; + pt1.push(u); + u += step; + } + } +}; +verb_eval_Tess.rationalBezierCurveStepLength = function(curve,tol) { + var dehomo = verb_eval_Eval.dehomogenize1d(curve.controlPoints); + var bb = new verb_core_BoundingBox(dehomo); + var avgPt = verb_core_Vec.mul(0.5,verb_core_Vec.add(bb.min,bb.max)); + var m = verb_core_Mat.identity(4); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + var tc = verb_eval_Modify.rationalCurveTransform(curve,m); + dehomo = verb_eval_Eval.dehomogenize1d(tc.controlPoints); + var r = 0.0; + var n; + var _g1 = 0; + var _g = dehomo.length; + while(_g1 < _g) { + var i = _g1++; + n = verb_core_Vec.norm(dehomo[i]); + if(n > r) r = n; + } + var wts = verb_eval_Eval.weight1d(curve.controlPoints); + var w = verb_core_Vec.min(wts); + var domain = verb_core_ArrayExtensions.last(curve.knots) - curve.knots[0]; + if(tol < r) { + var numer = 8 * w * tol; + var ws = verb_eval_Tess.secondForwardDiff(wts); + var pts = verb_eval_Tess.secondForwardDiff2(dehomo); + var fs; + var _g2 = []; + var _g21 = 0; + var _g11 = pts.length; + while(_g21 < _g11) { + var i1 = _g21++; + _g2.push(verb_core_Vec.norm(pts[i1]) + (r - tol) * ws[i1]); + } + fs = _g2; + var f = verb_core_Vec.max(fs); + var denom = curve.degree * (curve.degree - 1.0) * f; + return domain * Math.sqrt(numer / denom); + } else if(r >= tol && tol < 2.0 * r) { + var numer1 = 8 * w * tol; + var pts1 = verb_eval_Tess.secondForwardDiff2(dehomo); + var fs1; + var _g3 = []; + var _g22 = 0; + var _g12 = pts1.length; + while(_g22 < _g12) { + var i2 = _g22++; + _g3.push(verb_core_Vec.norm(pts1[i2])); + } + fs1 = _g3; + var f1 = verb_core_Vec.max(fs1); + var denom1 = curve.degree * (curve.degree - 1.0) * f1; + return domain * Math.sqrt(numer1 / denom1); + } else return domain; +}; +verb_eval_Tess.secondForwardDiff = function(array) { + var i = 0; + var res = []; + while(i < array.length - 2) { + res.push(array[i + 2] - 2.0 * array[i + 1] + array[i]); + i++; + } + return res; +}; +verb_eval_Tess.secondForwardDiff2 = function(array) { + var i = 0; + var res = []; + while(i < array.length - 2) { + res.push(verb_core_Vec.add(array[i + 2],verb_core_Vec.add(verb_core_Vec.mul(-2.0,array[i + 1]),array[i]))); + i++; + } + return res; }; verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { if(divs_u < 1) divs_u = 1; @@ -6060,8 +7065,8 @@ verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { var _g2 = divs_v + 1; while(_g3 < _g2) { var j = _g3++; - var pt_u = i * span_u; - var pt_v = j * span_v; + var pt_u = knotsU[0] + i * span_u; + var pt_v = knotsV[0] + j * span_v; uvs.push([pt_u,pt_v]); var derivs = verb_eval_Eval.rationalSurfaceDerivatives(surface,pt_u,pt_v,1); var pt = derivs[0][0]; @@ -6184,6 +7189,53 @@ verb_eval_Tess.rationalSurfaceAdaptive = function(surface,options) { var arrTrees = verb_eval_Tess.divideRationalSurfaceAdaptive(surface,options); return verb_eval_Tess.triangulateAdaptiveRefinementNodeTree(arrTrees); }; +verb_eval_Tess.rationalSurfaceRegularSample = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSample(surface,divsU,divsV)); +}; +verb_eval_Tess.surfaceRegularSample = function(surface,divsU,divsV) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var dim = controlPoints[0][0].length; + var spanU = (verb_core_ArrayExtensions.last(knotsU) - knotsU[0]) / divsU; + var spanV = (verb_core_ArrayExtensions.last(knotsV) - knotsV[0]) / divsV; + var knotSpansBasesU = verb_eval_Eval.regularlySpacedBasisFunctions(degreeU,knotsU,divsU); + var knotSpansU = knotSpansBasesU.item0; + var basesU = knotSpansBasesU.item1; + var knotSpansBasesV = verb_eval_Eval.regularlySpacedBasisFunctions(degreeV,knotsV,divsV); + var knotSpansV = knotSpansBasesV.item0; + var basesV = knotSpansBasesV.item1; + var pts = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var ptsi = []; + pts.push(ptsi); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + ptsi.push(verb_eval_Eval.surfacePointGivenBasesKnotSpans(degreeU,degreeV,controlPoints,knotSpansU[i],knotSpansV[j],basesU[i],basesV[j],dim)); + } + } + return pts; +}; +verb_eval_Tess.surfaceRegularSample2 = function(surface,divsU,divsV) { + var pts = []; + var u = surface.knotsU[0]; + var t = (verb_core_ArrayExtensions.last(surface.knotsU) - surface.knotsU[0]) / divsU; + var _g = 0; + while(_g < divsU) { + var i = _g++; + var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); + pts.push(verb_eval_Tess.rationalCurveRegularSample(iso,divsV)); + u += t; + } + return pts; +}; var verb_eval_AdaptiveRefinementOptions = $hx_exports.core.AdaptiveRefinementOptions = function() { this.minDivsV = 1; this.minDivsU = 1; @@ -6655,9 +7707,11 @@ verb_geom_NurbsCurve.prototype = $extend(verb_core_SerializableBase.prototype,{ }); } ,tessellate: function(tolerance) { + if(tolerance == null) tolerance = 1e-3; return verb_eval_Tess.rationalCurveAdaptiveSample(this._data,tolerance,false); } ,tessellateAsync: function(tolerance) { + if(tolerance == null) tolerance = 1e-3; return verb_exe_Dispatcher.dispatchMethod(verb_eval_Tess,"rationalCurveAdaptiveSample",[this._data,tolerance,false]); } ,__class__: verb_geom_NurbsCurve diff --git a/examples/build/.gitignore b/examples/build/.gitignore new file mode 100644 index 00000000..ce59b957 --- /dev/null +++ b/examples/build/.gitignore @@ -0,0 +1,5 @@ +cpp +cs +python.py +php +java diff --git a/examples/build/js/verb.js b/examples/build/js/verb.js new file mode 100644 index 00000000..e9a4be8d --- /dev/null +++ b/examples/build/js/verb.js @@ -0,0 +1,8470 @@ +// Header for verb for JavaScript +// Borrowed from browserify, this header supports AMD (define) and common js (require) style modules + +(function(f){ + if(typeof exports==="object"&&typeof module!=="undefined"){ + module.exports=f() + } else if(typeof define==="function"&&define.amd){ + define([],f) + } else { + var g; + if(typeof window!=="undefined"){ + g=window + } else if(typeof global!=="undefined"){ + g=global + } else if(typeof self!=="undefined"){ + g=self + } else{ + g=this + } + + g.verb = f() + } +})(function(){ + + var verb = {}; + + // node.js context, but not WebWorker + if ( typeof window !== 'object' && typeof require === "function"){ + Worker = require('webworker-threads').Worker; + } + + // WebWorker or node.js context + if ( typeof window !== 'object' ){ + + var global = this; + var window = global; // required for promhx + + // WebWorker + if ( typeof importScripts === "function"){ + + var lookup = function(className, methodName){ + + var obj = global; + + className.split(".").forEach(function(x){ + if (obj) obj = obj[ x ]; + }); + + if (!obj) return null; + + return obj[ methodName ]; + } + + onmessage = function( e ){ + + if (!e.data.className || !e.data.methodName) return; + + var method = lookup( e.data.className, e.data.methodName ); + + if (!method){ + return console.error("could not find " + e.data.className + "." + e.data.methodName) + } + + postMessage( { result: method.apply( null, e.data.args ), id: e.data.id } ); + + }; + } + } + +(function (console, $hx_exports, $global) { "use strict"; +$hx_exports.geom = $hx_exports.geom || {}; +$hx_exports.exe = $hx_exports.exe || {}; +$hx_exports.eval = $hx_exports.eval || {}; +$hx_exports.core = $hx_exports.core || {}; +$hx_exports.promhx = $hx_exports.promhx || {}; +var $hxClasses = {},$estr = function() { return js_Boot.__string_rec(this,''); }; +function $extend(from, fields) { + function Inherit() {} Inherit.prototype = from; var proto = new Inherit(); + for (var name in fields) proto[name] = fields[name]; + if( fields.toString !== Object.prototype.toString ) proto.toString = fields.toString; + return proto; +} +var HxOverrides = function() { }; +$hxClasses["HxOverrides"] = HxOverrides; +HxOverrides.__name__ = ["HxOverrides"]; +HxOverrides.strDate = function(s) { + var _g = s.length; + switch(_g) { + case 8: + var k = s.split(":"); + var d = new Date(); + d.setTime(0); + d.setUTCHours(k[0]); + d.setUTCMinutes(k[1]); + d.setUTCSeconds(k[2]); + return d; + case 10: + var k1 = s.split("-"); + return new Date(k1[0],k1[1] - 1,k1[2],0,0,0); + case 19: + var k2 = s.split(" "); + var y = k2[0].split("-"); + var t = k2[1].split(":"); + return new Date(y[0],y[1] - 1,y[2],t[0],t[1],t[2]); + default: + throw new js__$Boot_HaxeError("Invalid date format : " + s); + } +}; +HxOverrides.cca = function(s,index) { + var x = s.charCodeAt(index); + if(x != x) return undefined; + return x; +}; +HxOverrides.substr = function(s,pos,len) { + if(pos != null && pos != 0 && len != null && len < 0) return ""; + if(len == null) len = s.length; + if(pos < 0) { + pos = s.length + pos; + if(pos < 0) pos = 0; + } else if(len < 0) len = s.length + len - pos; + return s.substr(pos,len); +}; +HxOverrides.iter = function(a) { + return { cur : 0, arr : a, hasNext : function() { + return this.cur < this.arr.length; + }, next : function() { + return this.arr[this.cur++]; + }}; +}; +var Lambda = function() { }; +$hxClasses["Lambda"] = Lambda; +Lambda.__name__ = ["Lambda"]; +Lambda.fold = function(it,f,first) { + var $it0 = $iterator(it)(); + while( $it0.hasNext() ) { + var x = $it0.next(); + first = f(x,first); + } + return first; +}; +var List = function() { + this.length = 0; +}; +$hxClasses["List"] = List; +List.__name__ = ["List"]; +List.prototype = { + add: function(item) { + var x = [item]; + if(this.h == null) this.h = x; else this.q[1] = x; + this.q = x; + this.length++; + } + ,pop: function() { + if(this.h == null) return null; + var x = this.h[0]; + this.h = this.h[1]; + if(this.h == null) this.q = null; + this.length--; + return x; + } + ,isEmpty: function() { + return this.h == null; + } + ,__class__: List +}; +Math.__name__ = ["Math"]; +var Reflect = function() { }; +$hxClasses["Reflect"] = Reflect; +Reflect.__name__ = ["Reflect"]; +Reflect.field = function(o,field) { + try { + return o[field]; + } catch( e ) { + if (e instanceof js__$Boot_HaxeError) e = e.val; + return null; + } +}; +Reflect.callMethod = function(o,func,args) { + return func.apply(o,args); +}; +Reflect.fields = function(o) { + var a = []; + if(o != null) { + var hasOwnProperty = Object.prototype.hasOwnProperty; + for( var f in o ) { + if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) a.push(f); + } + } + return a; +}; +Reflect.isFunction = function(f) { + return typeof(f) == "function" && !(f.__name__ || f.__ename__); +}; +Reflect.deleteField = function(o,field) { + if(!Object.prototype.hasOwnProperty.call(o,field)) return false; + delete(o[field]); + return true; +}; +var Std = function() { }; +$hxClasses["Std"] = Std; +Std.__name__ = ["Std"]; +Std.string = function(s) { + return js_Boot.__string_rec(s,""); +}; +Std.parseFloat = function(x) { + return parseFloat(x); +}; +var StringBuf = function() { + this.b = ""; +}; +$hxClasses["StringBuf"] = StringBuf; +StringBuf.__name__ = ["StringBuf"]; +StringBuf.prototype = { + add: function(x) { + this.b += Std.string(x); + } + ,__class__: StringBuf +}; +var StringTools = function() { }; +$hxClasses["StringTools"] = StringTools; +StringTools.__name__ = ["StringTools"]; +StringTools.fastCodeAt = function(s,index) { + return s.charCodeAt(index); +}; +var ValueType = $hxClasses["ValueType"] = { __ename__ : ["ValueType"], __constructs__ : ["TNull","TInt","TFloat","TBool","TObject","TFunction","TClass","TEnum","TUnknown"] }; +ValueType.TNull = ["TNull",0]; +ValueType.TNull.toString = $estr; +ValueType.TNull.__enum__ = ValueType; +ValueType.TInt = ["TInt",1]; +ValueType.TInt.toString = $estr; +ValueType.TInt.__enum__ = ValueType; +ValueType.TFloat = ["TFloat",2]; +ValueType.TFloat.toString = $estr; +ValueType.TFloat.__enum__ = ValueType; +ValueType.TBool = ["TBool",3]; +ValueType.TBool.toString = $estr; +ValueType.TBool.__enum__ = ValueType; +ValueType.TObject = ["TObject",4]; +ValueType.TObject.toString = $estr; +ValueType.TObject.__enum__ = ValueType; +ValueType.TFunction = ["TFunction",5]; +ValueType.TFunction.toString = $estr; +ValueType.TFunction.__enum__ = ValueType; +ValueType.TClass = function(c) { var $x = ["TClass",6,c]; $x.__enum__ = ValueType; $x.toString = $estr; return $x; }; +ValueType.TEnum = function(e) { var $x = ["TEnum",7,e]; $x.__enum__ = ValueType; $x.toString = $estr; return $x; }; +ValueType.TUnknown = ["TUnknown",8]; +ValueType.TUnknown.toString = $estr; +ValueType.TUnknown.__enum__ = ValueType; +var Type = function() { }; +$hxClasses["Type"] = Type; +Type.__name__ = ["Type"]; +Type.getClassName = function(c) { + var a = c.__name__; + if(a == null) return null; + return a.join("."); +}; +Type.getEnumName = function(e) { + var a = e.__ename__; + return a.join("."); +}; +Type.resolveClass = function(name) { + var cl = $hxClasses[name]; + if(cl == null || !cl.__name__) return null; + return cl; +}; +Type.resolveEnum = function(name) { + var e = $hxClasses[name]; + if(e == null || !e.__ename__) return null; + return e; +}; +Type.createEmptyInstance = function(cl) { + function empty() {}; empty.prototype = cl.prototype; + return new empty(); +}; +Type.createEnum = function(e,constr,params) { + var f = Reflect.field(e,constr); + if(f == null) throw new js__$Boot_HaxeError("No such constructor " + constr); + if(Reflect.isFunction(f)) { + if(params == null) throw new js__$Boot_HaxeError("Constructor " + constr + " need parameters"); + return Reflect.callMethod(e,f,params); + } + if(params != null && params.length != 0) throw new js__$Boot_HaxeError("Constructor " + constr + " does not need parameters"); + return f; +}; +Type.getEnumConstructs = function(e) { + var a = e.__constructs__; + return a.slice(); +}; +Type["typeof"] = function(v) { + var _g = typeof(v); + switch(_g) { + case "boolean": + return ValueType.TBool; + case "string": + return ValueType.TClass(String); + case "number": + if(Math.ceil(v) == v % 2147483648.0) return ValueType.TInt; + return ValueType.TFloat; + case "object": + if(v == null) return ValueType.TNull; + var e = v.__enum__; + if(e != null) return ValueType.TEnum(e); + var c = js_Boot.getClass(v); + if(c != null) return ValueType.TClass(c); + return ValueType.TObject; + case "function": + if(v.__name__ || v.__ename__) return ValueType.TObject; + return ValueType.TFunction; + case "undefined": + return ValueType.TNull; + default: + return ValueType.TUnknown; + } +}; +var haxe_IMap = function() { }; +$hxClasses["haxe.IMap"] = haxe_IMap; +haxe_IMap.__name__ = ["haxe","IMap"]; +var haxe__$Int64__$_$_$Int64 = function(high,low) { + this.high = high; + this.low = low; +}; +$hxClasses["haxe._Int64.___Int64"] = haxe__$Int64__$_$_$Int64; +haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; +haxe__$Int64__$_$_$Int64.prototype = { + __class__: haxe__$Int64__$_$_$Int64 +}; +var haxe_Serializer = function() { + this.buf = new StringBuf(); + this.cache = []; + this.useCache = haxe_Serializer.USE_CACHE; + this.useEnumIndex = haxe_Serializer.USE_ENUM_INDEX; + this.shash = new haxe_ds_StringMap(); + this.scount = 0; +}; +$hxClasses["haxe.Serializer"] = haxe_Serializer; +haxe_Serializer.__name__ = ["haxe","Serializer"]; +haxe_Serializer.prototype = { + toString: function() { + return this.buf.b; + } + ,serializeString: function(s) { + var x = this.shash.get(s); + if(x != null) { + this.buf.b += "R"; + if(x == null) this.buf.b += "null"; else this.buf.b += "" + x; + return; + } + this.shash.set(s,this.scount++); + this.buf.b += "y"; + s = encodeURIComponent(s); + if(s.length == null) this.buf.b += "null"; else this.buf.b += "" + s.length; + this.buf.b += ":"; + if(s == null) this.buf.b += "null"; else this.buf.b += "" + s; + } + ,serializeRef: function(v) { + var vt = typeof(v); + var _g1 = 0; + var _g = this.cache.length; + while(_g1 < _g) { + var i = _g1++; + var ci = this.cache[i]; + if(typeof(ci) == vt && ci == v) { + this.buf.b += "r"; + if(i == null) this.buf.b += "null"; else this.buf.b += "" + i; + return true; + } + } + this.cache.push(v); + return false; + } + ,serializeFields: function(v) { + var _g = 0; + var _g1 = Reflect.fields(v); + while(_g < _g1.length) { + var f = _g1[_g]; + ++_g; + this.serializeString(f); + this.serialize(Reflect.field(v,f)); + } + this.buf.b += "g"; + } + ,serialize: function(v) { + { + var _g = Type["typeof"](v); + switch(_g[1]) { + case 0: + this.buf.b += "n"; + break; + case 1: + var v1 = v; + if(v1 == 0) { + this.buf.b += "z"; + return; + } + this.buf.b += "i"; + if(v1 == null) this.buf.b += "null"; else this.buf.b += "" + v1; + break; + case 2: + var v2 = v; + if(isNaN(v2)) this.buf.b += "k"; else if(!isFinite(v2)) if(v2 < 0) this.buf.b += "m"; else this.buf.b += "p"; else { + this.buf.b += "d"; + if(v2 == null) this.buf.b += "null"; else this.buf.b += "" + v2; + } + break; + case 3: + if(v) this.buf.b += "t"; else this.buf.b += "f"; + break; + case 6: + var c = _g[2]; + if(c == String) { + this.serializeString(v); + return; + } + if(this.useCache && this.serializeRef(v)) return; + switch(c) { + case Array: + var ucount = 0; + this.buf.b += "a"; + var l = v.length; + var _g1 = 0; + while(_g1 < l) { + var i = _g1++; + if(v[i] == null) ucount++; else { + if(ucount > 0) { + if(ucount == 1) this.buf.b += "n"; else { + this.buf.b += "u"; + if(ucount == null) this.buf.b += "null"; else this.buf.b += "" + ucount; + } + ucount = 0; + } + this.serialize(v[i]); + } + } + if(ucount > 0) { + if(ucount == 1) this.buf.b += "n"; else { + this.buf.b += "u"; + if(ucount == null) this.buf.b += "null"; else this.buf.b += "" + ucount; + } + } + this.buf.b += "h"; + break; + case List: + this.buf.b += "l"; + var v3 = v; + var _g1_head = v3.h; + var _g1_val = null; + while(_g1_head != null) { + var i1; + _g1_val = _g1_head[0]; + _g1_head = _g1_head[1]; + i1 = _g1_val; + this.serialize(i1); + } + this.buf.b += "h"; + break; + case Date: + var d = v; + this.buf.b += "v"; + this.buf.add(d.getTime()); + break; + case haxe_ds_StringMap: + this.buf.b += "b"; + var v4 = v; + var $it0 = v4.keys(); + while( $it0.hasNext() ) { + var k = $it0.next(); + this.serializeString(k); + this.serialize(__map_reserved[k] != null?v4.getReserved(k):v4.h[k]); + } + this.buf.b += "h"; + break; + case haxe_ds_IntMap: + this.buf.b += "q"; + var v5 = v; + var $it1 = v5.keys(); + while( $it1.hasNext() ) { + var k1 = $it1.next(); + this.buf.b += ":"; + if(k1 == null) this.buf.b += "null"; else this.buf.b += "" + k1; + this.serialize(v5.h[k1]); + } + this.buf.b += "h"; + break; + case haxe_ds_ObjectMap: + this.buf.b += "M"; + var v6 = v; + var $it2 = v6.keys(); + while( $it2.hasNext() ) { + var k2 = $it2.next(); + var id = Reflect.field(k2,"__id__"); + Reflect.deleteField(k2,"__id__"); + this.serialize(k2); + k2.__id__ = id; + this.serialize(v6.h[k2.__id__]); + } + this.buf.b += "h"; + break; + case haxe_io_Bytes: + var v7 = v; + var i2 = 0; + var max = v7.length - 2; + var charsBuf = new StringBuf(); + var b64 = haxe_Serializer.BASE64; + while(i2 < max) { + var b1 = v7.get(i2++); + var b2 = v7.get(i2++); + var b3 = v7.get(i2++); + charsBuf.add(b64.charAt(b1 >> 2)); + charsBuf.add(b64.charAt((b1 << 4 | b2 >> 4) & 63)); + charsBuf.add(b64.charAt((b2 << 2 | b3 >> 6) & 63)); + charsBuf.add(b64.charAt(b3 & 63)); + } + if(i2 == max) { + var b11 = v7.get(i2++); + var b21 = v7.get(i2++); + charsBuf.add(b64.charAt(b11 >> 2)); + charsBuf.add(b64.charAt((b11 << 4 | b21 >> 4) & 63)); + charsBuf.add(b64.charAt(b21 << 2 & 63)); + } else if(i2 == max + 1) { + var b12 = v7.get(i2++); + charsBuf.add(b64.charAt(b12 >> 2)); + charsBuf.add(b64.charAt(b12 << 4 & 63)); + } + var chars = charsBuf.b; + this.buf.b += "s"; + if(chars.length == null) this.buf.b += "null"; else this.buf.b += "" + chars.length; + this.buf.b += ":"; + if(chars == null) this.buf.b += "null"; else this.buf.b += "" + chars; + break; + default: + if(this.useCache) this.cache.pop(); + if(v.hxSerialize != null) { + this.buf.b += "C"; + this.serializeString(Type.getClassName(c)); + if(this.useCache) this.cache.push(v); + v.hxSerialize(this); + this.buf.b += "g"; + } else { + this.buf.b += "c"; + this.serializeString(Type.getClassName(c)); + if(this.useCache) this.cache.push(v); + this.serializeFields(v); + } + } + break; + case 4: + if(js_Boot.__instanceof(v,Class)) { + var className = Type.getClassName(v); + this.buf.b += "A"; + this.serializeString(className); + } else if(js_Boot.__instanceof(v,Enum)) { + this.buf.b += "B"; + this.serializeString(Type.getEnumName(v)); + } else { + if(this.useCache && this.serializeRef(v)) return; + this.buf.b += "o"; + this.serializeFields(v); + } + break; + case 7: + var e = _g[2]; + if(this.useCache) { + if(this.serializeRef(v)) return; + this.cache.pop(); + } + if(this.useEnumIndex) this.buf.b += "j"; else this.buf.b += "w"; + this.serializeString(Type.getEnumName(e)); + if(this.useEnumIndex) { + this.buf.b += ":"; + this.buf.b += Std.string(v[1]); + } else this.serializeString(v[0]); + this.buf.b += ":"; + var l1 = v.length; + this.buf.b += Std.string(l1 - 2); + var _g11 = 2; + while(_g11 < l1) { + var i3 = _g11++; + this.serialize(v[i3]); + } + if(this.useCache) this.cache.push(v); + break; + case 5: + throw new js__$Boot_HaxeError("Cannot serialize function"); + break; + default: + throw new js__$Boot_HaxeError("Cannot serialize " + Std.string(v)); + } + } + } + ,__class__: haxe_Serializer +}; +var haxe_Unserializer = function(buf) { + this.buf = buf; + this.length = buf.length; + this.pos = 0; + this.scache = []; + this.cache = []; + var r = haxe_Unserializer.DEFAULT_RESOLVER; + if(r == null) { + r = Type; + haxe_Unserializer.DEFAULT_RESOLVER = r; + } + this.setResolver(r); +}; +$hxClasses["haxe.Unserializer"] = haxe_Unserializer; +haxe_Unserializer.__name__ = ["haxe","Unserializer"]; +haxe_Unserializer.initCodes = function() { + var codes = []; + var _g1 = 0; + var _g = haxe_Unserializer.BASE64.length; + while(_g1 < _g) { + var i = _g1++; + codes[haxe_Unserializer.BASE64.charCodeAt(i)] = i; + } + return codes; +}; +haxe_Unserializer.prototype = { + setResolver: function(r) { + if(r == null) this.resolver = { resolveClass : function(_) { + return null; + }, resolveEnum : function(_1) { + return null; + }}; else this.resolver = r; + } + ,get: function(p) { + return this.buf.charCodeAt(p); + } + ,readDigits: function() { + var k = 0; + var s = false; + var fpos = this.pos; + while(true) { + var c = this.buf.charCodeAt(this.pos); + if(c != c) break; + if(c == 45) { + if(this.pos != fpos) break; + s = true; + this.pos++; + continue; + } + if(c < 48 || c > 57) break; + k = k * 10 + (c - 48); + this.pos++; + } + if(s) k *= -1; + return k; + } + ,readFloat: function() { + var p1 = this.pos; + while(true) { + var c = this.buf.charCodeAt(this.pos); + if(c >= 43 && c < 58 || c == 101 || c == 69) this.pos++; else break; + } + return Std.parseFloat(HxOverrides.substr(this.buf,p1,this.pos - p1)); + } + ,unserializeObject: function(o) { + while(true) { + if(this.pos >= this.length) throw new js__$Boot_HaxeError("Invalid object"); + if(this.buf.charCodeAt(this.pos) == 103) break; + var k = this.unserialize(); + if(!(typeof(k) == "string")) throw new js__$Boot_HaxeError("Invalid object key"); + var v = this.unserialize(); + o[k] = v; + } + this.pos++; + } + ,unserializeEnum: function(edecl,tag) { + if(this.get(this.pos++) != 58) throw new js__$Boot_HaxeError("Invalid enum format"); + var nargs = this.readDigits(); + if(nargs == 0) return Type.createEnum(edecl,tag); + var args = []; + while(nargs-- > 0) args.push(this.unserialize()); + return Type.createEnum(edecl,tag,args); + } + ,unserialize: function() { + var _g = this.get(this.pos++); + switch(_g) { + case 110: + return null; + case 116: + return true; + case 102: + return false; + case 122: + return 0; + case 105: + return this.readDigits(); + case 100: + return this.readFloat(); + case 121: + var len = this.readDigits(); + if(this.get(this.pos++) != 58 || this.length - this.pos < len) throw new js__$Boot_HaxeError("Invalid string length"); + var s = HxOverrides.substr(this.buf,this.pos,len); + this.pos += len; + s = decodeURIComponent(s.split("+").join(" ")); + this.scache.push(s); + return s; + case 107: + return NaN; + case 109: + return -Infinity; + case 112: + return Infinity; + case 97: + var buf = this.buf; + var a = []; + this.cache.push(a); + while(true) { + var c = this.buf.charCodeAt(this.pos); + if(c == 104) { + this.pos++; + break; + } + if(c == 117) { + this.pos++; + var n = this.readDigits(); + a[a.length + n - 1] = null; + } else a.push(this.unserialize()); + } + return a; + case 111: + var o = { }; + this.cache.push(o); + this.unserializeObject(o); + return o; + case 114: + var n1 = this.readDigits(); + if(n1 < 0 || n1 >= this.cache.length) throw new js__$Boot_HaxeError("Invalid reference"); + return this.cache[n1]; + case 82: + var n2 = this.readDigits(); + if(n2 < 0 || n2 >= this.scache.length) throw new js__$Boot_HaxeError("Invalid string reference"); + return this.scache[n2]; + case 120: + throw new js__$Boot_HaxeError(this.unserialize()); + break; + case 99: + var name = this.unserialize(); + var cl = this.resolver.resolveClass(name); + if(cl == null) throw new js__$Boot_HaxeError("Class not found " + name); + var o1 = Type.createEmptyInstance(cl); + this.cache.push(o1); + this.unserializeObject(o1); + return o1; + case 119: + var name1 = this.unserialize(); + var edecl = this.resolver.resolveEnum(name1); + if(edecl == null) throw new js__$Boot_HaxeError("Enum not found " + name1); + var e = this.unserializeEnum(edecl,this.unserialize()); + this.cache.push(e); + return e; + case 106: + var name2 = this.unserialize(); + var edecl1 = this.resolver.resolveEnum(name2); + if(edecl1 == null) throw new js__$Boot_HaxeError("Enum not found " + name2); + this.pos++; + var index = this.readDigits(); + var tag = Type.getEnumConstructs(edecl1)[index]; + if(tag == null) throw new js__$Boot_HaxeError("Unknown enum index " + name2 + "@" + index); + var e1 = this.unserializeEnum(edecl1,tag); + this.cache.push(e1); + return e1; + case 108: + var l = new List(); + this.cache.push(l); + var buf1 = this.buf; + while(this.buf.charCodeAt(this.pos) != 104) l.add(this.unserialize()); + this.pos++; + return l; + case 98: + var h = new haxe_ds_StringMap(); + this.cache.push(h); + var buf2 = this.buf; + while(this.buf.charCodeAt(this.pos) != 104) { + var s1 = this.unserialize(); + h.set(s1,this.unserialize()); + } + this.pos++; + return h; + case 113: + var h1 = new haxe_ds_IntMap(); + this.cache.push(h1); + var buf3 = this.buf; + var c1 = this.get(this.pos++); + while(c1 == 58) { + var i = this.readDigits(); + h1.set(i,this.unserialize()); + c1 = this.get(this.pos++); + } + if(c1 != 104) throw new js__$Boot_HaxeError("Invalid IntMap format"); + return h1; + case 77: + var h2 = new haxe_ds_ObjectMap(); + this.cache.push(h2); + var buf4 = this.buf; + while(this.buf.charCodeAt(this.pos) != 104) { + var s2 = this.unserialize(); + h2.set(s2,this.unserialize()); + } + this.pos++; + return h2; + case 118: + var d; + if(this.buf.charCodeAt(this.pos) >= 48 && this.buf.charCodeAt(this.pos) <= 57 && this.buf.charCodeAt(this.pos + 1) >= 48 && this.buf.charCodeAt(this.pos + 1) <= 57 && this.buf.charCodeAt(this.pos + 2) >= 48 && this.buf.charCodeAt(this.pos + 2) <= 57 && this.buf.charCodeAt(this.pos + 3) >= 48 && this.buf.charCodeAt(this.pos + 3) <= 57 && this.buf.charCodeAt(this.pos + 4) == 45) { + var s3 = HxOverrides.substr(this.buf,this.pos,19); + d = HxOverrides.strDate(s3); + this.pos += 19; + } else { + var t = this.readFloat(); + var d1 = new Date(); + d1.setTime(t); + d = d1; + } + this.cache.push(d); + return d; + case 115: + var len1 = this.readDigits(); + var buf5 = this.buf; + if(this.get(this.pos++) != 58 || this.length - this.pos < len1) throw new js__$Boot_HaxeError("Invalid bytes length"); + var codes = haxe_Unserializer.CODES; + if(codes == null) { + codes = haxe_Unserializer.initCodes(); + haxe_Unserializer.CODES = codes; + } + var i1 = this.pos; + var rest = len1 & 3; + var size; + size = (len1 >> 2) * 3 + (rest >= 2?rest - 1:0); + var max = i1 + (len1 - rest); + var bytes = haxe_io_Bytes.alloc(size); + var bpos = 0; + while(i1 < max) { + var c11 = codes[StringTools.fastCodeAt(buf5,i1++)]; + var c2 = codes[StringTools.fastCodeAt(buf5,i1++)]; + bytes.set(bpos++,c11 << 2 | c2 >> 4); + var c3 = codes[StringTools.fastCodeAt(buf5,i1++)]; + bytes.set(bpos++,c2 << 4 | c3 >> 2); + var c4 = codes[StringTools.fastCodeAt(buf5,i1++)]; + bytes.set(bpos++,c3 << 6 | c4); + } + if(rest >= 2) { + var c12 = codes[StringTools.fastCodeAt(buf5,i1++)]; + var c21 = codes[StringTools.fastCodeAt(buf5,i1++)]; + bytes.set(bpos++,c12 << 2 | c21 >> 4); + if(rest == 3) { + var c31 = codes[StringTools.fastCodeAt(buf5,i1++)]; + bytes.set(bpos++,c21 << 4 | c31 >> 2); + } + } + this.pos += len1; + this.cache.push(bytes); + return bytes; + case 67: + var name3 = this.unserialize(); + var cl1 = this.resolver.resolveClass(name3); + if(cl1 == null) throw new js__$Boot_HaxeError("Class not found " + name3); + var o2 = Type.createEmptyInstance(cl1); + this.cache.push(o2); + o2.hxUnserialize(this); + if(this.get(this.pos++) != 103) throw new js__$Boot_HaxeError("Invalid custom data"); + return o2; + case 65: + var name4 = this.unserialize(); + var cl2 = this.resolver.resolveClass(name4); + if(cl2 == null) throw new js__$Boot_HaxeError("Class not found " + name4); + return cl2; + case 66: + var name5 = this.unserialize(); + var e2 = this.resolver.resolveEnum(name5); + if(e2 == null) throw new js__$Boot_HaxeError("Enum not found " + name5); + return e2; + default: + } + this.pos--; + throw new js__$Boot_HaxeError("Invalid char " + this.buf.charAt(this.pos) + " at position " + this.pos); + } + ,__class__: haxe_Unserializer +}; +var haxe_ds_IntMap = function() { + this.h = { }; +}; +$hxClasses["haxe.ds.IntMap"] = haxe_ds_IntMap; +haxe_ds_IntMap.__name__ = ["haxe","ds","IntMap"]; +haxe_ds_IntMap.__interfaces__ = [haxe_IMap]; +haxe_ds_IntMap.prototype = { + set: function(key,value) { + this.h[key] = value; + } + ,remove: function(key) { + if(!this.h.hasOwnProperty(key)) return false; + delete(this.h[key]); + return true; + } + ,keys: function() { + var a = []; + for( var key in this.h ) { + if(this.h.hasOwnProperty(key)) a.push(key | 0); + } + return HxOverrides.iter(a); + } + ,__class__: haxe_ds_IntMap +}; +var haxe_ds_ObjectMap = function() { + this.h = { }; + this.h.__keys__ = { }; +}; +$hxClasses["haxe.ds.ObjectMap"] = haxe_ds_ObjectMap; +haxe_ds_ObjectMap.__name__ = ["haxe","ds","ObjectMap"]; +haxe_ds_ObjectMap.__interfaces__ = [haxe_IMap]; +haxe_ds_ObjectMap.prototype = { + set: function(key,value) { + var id = key.__id__ || (key.__id__ = ++haxe_ds_ObjectMap.count); + this.h[id] = value; + this.h.__keys__[id] = key; + } + ,keys: function() { + var a = []; + for( var key in this.h.__keys__ ) { + if(this.h.hasOwnProperty(key)) a.push(this.h.__keys__[key]); + } + return HxOverrides.iter(a); + } + ,__class__: haxe_ds_ObjectMap +}; +var haxe_ds_Option = $hxClasses["haxe.ds.Option"] = { __ename__ : ["haxe","ds","Option"], __constructs__ : ["Some","None"] }; +haxe_ds_Option.Some = function(v) { var $x = ["Some",0,v]; $x.__enum__ = haxe_ds_Option; $x.toString = $estr; return $x; }; +haxe_ds_Option.None = ["None",1]; +haxe_ds_Option.None.toString = $estr; +haxe_ds_Option.None.__enum__ = haxe_ds_Option; +var haxe_ds_StringMap = function() { + this.h = { }; +}; +$hxClasses["haxe.ds.StringMap"] = haxe_ds_StringMap; +haxe_ds_StringMap.__name__ = ["haxe","ds","StringMap"]; +haxe_ds_StringMap.__interfaces__ = [haxe_IMap]; +haxe_ds_StringMap.prototype = { + set: function(key,value) { + if(__map_reserved[key] != null) this.setReserved(key,value); else this.h[key] = value; + } + ,get: function(key) { + if(__map_reserved[key] != null) return this.getReserved(key); + return this.h[key]; + } + ,setReserved: function(key,value) { + if(this.rh == null) this.rh = { }; + this.rh["$" + key] = value; + } + ,getReserved: function(key) { + if(this.rh == null) return null; else return this.rh["$" + key]; + } + ,keys: function() { + var _this = this.arrayKeys(); + return HxOverrides.iter(_this); + } + ,arrayKeys: function() { + var out = []; + for( var key in this.h ) { + if(this.h.hasOwnProperty(key)) out.push(key); + } + if(this.rh != null) { + for( var key in this.rh ) { + if(key.charCodeAt(0) == 36) out.push(key.substr(1)); + } + } + return out; + } + ,__class__: haxe_ds_StringMap +}; +var haxe_io_Bytes = function(data) { + this.length = data.byteLength; + this.b = new Uint8Array(data); + this.b.bufferValue = data; + data.hxBytes = this; + data.bytes = this.b; +}; +$hxClasses["haxe.io.Bytes"] = haxe_io_Bytes; +haxe_io_Bytes.__name__ = ["haxe","io","Bytes"]; +haxe_io_Bytes.alloc = function(length) { + return new haxe_io_Bytes(new ArrayBuffer(length)); +}; +haxe_io_Bytes.prototype = { + get: function(pos) { + return this.b[pos]; + } + ,set: function(pos,v) { + this.b[pos] = v & 255; + } + ,__class__: haxe_io_Bytes +}; +var haxe_io_Error = $hxClasses["haxe.io.Error"] = { __ename__ : ["haxe","io","Error"], __constructs__ : ["Blocked","Overflow","OutsideBounds","Custom"] }; +haxe_io_Error.Blocked = ["Blocked",0]; +haxe_io_Error.Blocked.toString = $estr; +haxe_io_Error.Blocked.__enum__ = haxe_io_Error; +haxe_io_Error.Overflow = ["Overflow",1]; +haxe_io_Error.Overflow.toString = $estr; +haxe_io_Error.Overflow.__enum__ = haxe_io_Error; +haxe_io_Error.OutsideBounds = ["OutsideBounds",2]; +haxe_io_Error.OutsideBounds.toString = $estr; +haxe_io_Error.OutsideBounds.__enum__ = haxe_io_Error; +haxe_io_Error.Custom = function(e) { var $x = ["Custom",3,e]; $x.__enum__ = haxe_io_Error; $x.toString = $estr; return $x; }; +var haxe_io_FPHelper = function() { }; +$hxClasses["haxe.io.FPHelper"] = haxe_io_FPHelper; +haxe_io_FPHelper.__name__ = ["haxe","io","FPHelper"]; +haxe_io_FPHelper.i32ToFloat = function(i) { + var sign = 1 - (i >>> 31 << 1); + var exp = i >>> 23 & 255; + var sig = i & 8388607; + if(sig == 0 && exp == 0) return 0.0; + return sign * (1 + Math.pow(2,-23) * sig) * Math.pow(2,exp - 127); +}; +haxe_io_FPHelper.floatToI32 = function(f) { + if(f == 0) return 0; + var af; + if(f < 0) af = -f; else af = f; + var exp = Math.floor(Math.log(af) / 0.6931471805599453); + if(exp < -127) exp = -127; else if(exp > 128) exp = 128; + var sig = Math.round((af / Math.pow(2,exp) - 1) * 8388608) & 8388607; + return (f < 0?-2147483648:0) | exp + 127 << 23 | sig; +}; +haxe_io_FPHelper.i64ToDouble = function(low,high) { + var sign = 1 - (high >>> 31 << 1); + var exp = (high >> 20 & 2047) - 1023; + var sig = (high & 1048575) * 4294967296. + (low >>> 31) * 2147483648. + (low & 2147483647); + if(sig == 0 && exp == -1023) return 0.0; + return sign * (1.0 + Math.pow(2,-52) * sig) * Math.pow(2,exp); +}; +haxe_io_FPHelper.doubleToI64 = function(v) { + var i64 = haxe_io_FPHelper.i64tmp; + if(v == 0) { + i64.low = 0; + i64.high = 0; + } else { + var av; + if(v < 0) av = -v; else av = v; + var exp = Math.floor(Math.log(av) / 0.6931471805599453); + var sig; + var v1 = (av / Math.pow(2,exp) - 1) * 4503599627370496.; + sig = Math.round(v1); + var sig_l = sig | 0; + var sig_h = sig / 4294967296.0 | 0; + i64.low = sig_l; + i64.high = (v < 0?-2147483648:0) | exp + 1023 << 20 | sig_h; + } + return i64; +}; +var js__$Boot_HaxeError = function(val) { + Error.call(this); + this.val = val; + this.message = String(val); + if(Error.captureStackTrace) Error.captureStackTrace(this,js__$Boot_HaxeError); +}; +$hxClasses["js._Boot.HaxeError"] = js__$Boot_HaxeError; +js__$Boot_HaxeError.__name__ = ["js","_Boot","HaxeError"]; +js__$Boot_HaxeError.__super__ = Error; +js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ + __class__: js__$Boot_HaxeError +}); +var js_Boot = function() { }; +$hxClasses["js.Boot"] = js_Boot; +js_Boot.__name__ = ["js","Boot"]; +js_Boot.getClass = function(o) { + if((o instanceof Array) && o.__enum__ == null) return Array; else { + var cl = o.__class__; + if(cl != null) return cl; + var name = js_Boot.__nativeClassName(o); + if(name != null) return js_Boot.__resolveNativeClass(name); + return null; + } +}; +js_Boot.__string_rec = function(o,s) { + if(o == null) return "null"; + if(s.length >= 5) return "<...>"; + var t = typeof(o); + if(t == "function" && (o.__name__ || o.__ename__)) t = "object"; + switch(t) { + case "object": + if(o instanceof Array) { + if(o.__enum__) { + if(o.length == 2) return o[0]; + var str2 = o[0] + "("; + s += "\t"; + var _g1 = 2; + var _g = o.length; + while(_g1 < _g) { + var i1 = _g1++; + if(i1 != 2) str2 += "," + js_Boot.__string_rec(o[i1],s); else str2 += js_Boot.__string_rec(o[i1],s); + } + return str2 + ")"; + } + var l = o.length; + var i; + var str1 = "["; + s += "\t"; + var _g2 = 0; + while(_g2 < l) { + var i2 = _g2++; + str1 += (i2 > 0?",":"") + js_Boot.__string_rec(o[i2],s); + } + str1 += "]"; + return str1; + } + var tostr; + try { + tostr = o.toString; + } catch( e ) { + if (e instanceof js__$Boot_HaxeError) e = e.val; + return "???"; + } + if(tostr != null && tostr != Object.toString && typeof(tostr) == "function") { + var s2 = o.toString(); + if(s2 != "[object Object]") return s2; + } + var k = null; + var str = "{\n"; + s += "\t"; + var hasp = o.hasOwnProperty != null; + for( var k in o ) { + if(hasp && !o.hasOwnProperty(k)) { + continue; + } + if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") { + continue; + } + if(str.length != 2) str += ", \n"; + str += s + k + " : " + js_Boot.__string_rec(o[k],s); + } + s = s.substring(1); + str += "\n" + s + "}"; + return str; + case "function": + return ""; + case "string": + return o; + default: + return String(o); + } +}; +js_Boot.__interfLoop = function(cc,cl) { + if(cc == null) return false; + if(cc == cl) return true; + var intf = cc.__interfaces__; + if(intf != null) { + var _g1 = 0; + var _g = intf.length; + while(_g1 < _g) { + var i = _g1++; + var i1 = intf[i]; + if(i1 == cl || js_Boot.__interfLoop(i1,cl)) return true; + } + } + return js_Boot.__interfLoop(cc.__super__,cl); +}; +js_Boot.__instanceof = function(o,cl) { + if(cl == null) return false; + switch(cl) { + case Int: + return (o|0) === o; + case Float: + return typeof(o) == "number"; + case Bool: + return typeof(o) == "boolean"; + case String: + return typeof(o) == "string"; + case Array: + return (o instanceof Array) && o.__enum__ == null; + case Dynamic: + return true; + default: + if(o != null) { + if(typeof(cl) == "function") { + if(o instanceof cl) return true; + if(js_Boot.__interfLoop(js_Boot.getClass(o),cl)) return true; + } else if(typeof(cl) == "object" && js_Boot.__isNativeObj(cl)) { + if(o instanceof cl) return true; + } + } else return false; + if(cl == Class && o.__name__ != null) return true; + if(cl == Enum && o.__ename__ != null) return true; + return o.__enum__ == cl; + } +}; +js_Boot.__nativeClassName = function(o) { + var name = js_Boot.__toStr.call(o).slice(8,-1); + if(name == "Object" || name == "Function" || name == "Math" || name == "JSON") return null; + return name; +}; +js_Boot.__isNativeObj = function(o) { + return js_Boot.__nativeClassName(o) != null; +}; +js_Boot.__resolveNativeClass = function(name) { + return $global[name]; +}; +var js_html_compat_ArrayBuffer = function(a) { + if((a instanceof Array) && a.__enum__ == null) { + this.a = a; + this.byteLength = a.length; + } else { + var len = a; + this.a = []; + var _g = 0; + while(_g < len) { + var i = _g++; + this.a[i] = 0; + } + this.byteLength = len; + } +}; +$hxClasses["js.html.compat.ArrayBuffer"] = js_html_compat_ArrayBuffer; +js_html_compat_ArrayBuffer.__name__ = ["js","html","compat","ArrayBuffer"]; +js_html_compat_ArrayBuffer.sliceImpl = function(begin,end) { + var u = new Uint8Array(this,begin,end == null?null:end - begin); + var result = new ArrayBuffer(u.byteLength); + var resultArray = new Uint8Array(result); + resultArray.set(u); + return result; +}; +js_html_compat_ArrayBuffer.prototype = { + slice: function(begin,end) { + return new js_html_compat_ArrayBuffer(this.a.slice(begin,end)); + } + ,__class__: js_html_compat_ArrayBuffer +}; +var js_html_compat_DataView = function(buffer,byteOffset,byteLength) { + this.buf = buffer; + if(byteOffset == null) this.offset = 0; else this.offset = byteOffset; + if(byteLength == null) this.length = buffer.byteLength - this.offset; else this.length = byteLength; + if(this.offset < 0 || this.length < 0 || this.offset + this.length > buffer.byteLength) throw new js__$Boot_HaxeError(haxe_io_Error.OutsideBounds); +}; +$hxClasses["js.html.compat.DataView"] = js_html_compat_DataView; +js_html_compat_DataView.__name__ = ["js","html","compat","DataView"]; +js_html_compat_DataView.prototype = { + getInt8: function(byteOffset) { + var v = this.buf.a[this.offset + byteOffset]; + if(v >= 128) return v - 256; else return v; + } + ,getUint8: function(byteOffset) { + return this.buf.a[this.offset + byteOffset]; + } + ,getInt16: function(byteOffset,littleEndian) { + var v = this.getUint16(byteOffset,littleEndian); + if(v >= 32768) return v - 65536; else return v; + } + ,getUint16: function(byteOffset,littleEndian) { + if(littleEndian) return this.buf.a[this.offset + byteOffset] | this.buf.a[this.offset + byteOffset + 1] << 8; else return this.buf.a[this.offset + byteOffset] << 8 | this.buf.a[this.offset + byteOffset + 1]; + } + ,getInt32: function(byteOffset,littleEndian) { + var p = this.offset + byteOffset; + var a = this.buf.a[p++]; + var b = this.buf.a[p++]; + var c = this.buf.a[p++]; + var d = this.buf.a[p++]; + if(littleEndian) return a | b << 8 | c << 16 | d << 24; else return d | c << 8 | b << 16 | a << 24; + } + ,getUint32: function(byteOffset,littleEndian) { + var v = this.getInt32(byteOffset,littleEndian); + if(v < 0) return v + 4294967296.; else return v; + } + ,getFloat32: function(byteOffset,littleEndian) { + return haxe_io_FPHelper.i32ToFloat(this.getInt32(byteOffset,littleEndian)); + } + ,getFloat64: function(byteOffset,littleEndian) { + var a = this.getInt32(byteOffset,littleEndian); + var b = this.getInt32(byteOffset + 4,littleEndian); + return haxe_io_FPHelper.i64ToDouble(littleEndian?a:b,littleEndian?b:a); + } + ,setInt8: function(byteOffset,value) { + if(value < 0) this.buf.a[byteOffset + this.offset] = value + 128 & 255; else this.buf.a[byteOffset + this.offset] = value & 255; + } + ,setUint8: function(byteOffset,value) { + this.buf.a[byteOffset + this.offset] = value & 255; + } + ,setInt16: function(byteOffset,value,littleEndian) { + this.setUint16(byteOffset,value < 0?value + 65536:value,littleEndian); + } + ,setUint16: function(byteOffset,value,littleEndian) { + var p = byteOffset + this.offset; + if(littleEndian) { + this.buf.a[p] = value & 255; + this.buf.a[p++] = value >> 8 & 255; + } else { + this.buf.a[p++] = value >> 8 & 255; + this.buf.a[p] = value & 255; + } + } + ,setInt32: function(byteOffset,value,littleEndian) { + this.setUint32(byteOffset,value,littleEndian); + } + ,setUint32: function(byteOffset,value,littleEndian) { + var p = byteOffset + this.offset; + if(littleEndian) { + this.buf.a[p++] = value & 255; + this.buf.a[p++] = value >> 8 & 255; + this.buf.a[p++] = value >> 16 & 255; + this.buf.a[p++] = value >>> 24; + } else { + this.buf.a[p++] = value >>> 24; + this.buf.a[p++] = value >> 16 & 255; + this.buf.a[p++] = value >> 8 & 255; + this.buf.a[p++] = value & 255; + } + } + ,setFloat32: function(byteOffset,value,littleEndian) { + this.setUint32(byteOffset,haxe_io_FPHelper.floatToI32(value),littleEndian); + } + ,setFloat64: function(byteOffset,value,littleEndian) { + var i64 = haxe_io_FPHelper.doubleToI64(value); + if(littleEndian) { + this.setUint32(byteOffset,i64.low); + this.setUint32(byteOffset,i64.high); + } else { + this.setUint32(byteOffset,i64.high); + this.setUint32(byteOffset,i64.low); + } + } + ,__class__: js_html_compat_DataView +}; +var js_html_compat_Uint8Array = function() { }; +$hxClasses["js.html.compat.Uint8Array"] = js_html_compat_Uint8Array; +js_html_compat_Uint8Array.__name__ = ["js","html","compat","Uint8Array"]; +js_html_compat_Uint8Array._new = function(arg1,offset,length) { + var arr; + if(typeof(arg1) == "number") { + arr = []; + var _g = 0; + while(_g < arg1) { + var i = _g++; + arr[i] = 0; + } + arr.byteLength = arr.length; + arr.byteOffset = 0; + arr.buffer = new js_html_compat_ArrayBuffer(arr); + } else if(js_Boot.__instanceof(arg1,js_html_compat_ArrayBuffer)) { + var buffer = arg1; + if(offset == null) offset = 0; + if(length == null) length = buffer.byteLength - offset; + if(offset == 0) arr = buffer.a; else arr = buffer.a.slice(offset,offset + length); + arr.byteLength = arr.length; + arr.byteOffset = offset; + arr.buffer = buffer; + } else if((arg1 instanceof Array) && arg1.__enum__ == null) { + arr = arg1.slice(); + arr.byteLength = arr.length; + arr.byteOffset = 0; + arr.buffer = new js_html_compat_ArrayBuffer(arr); + } else throw new js__$Boot_HaxeError("TODO " + Std.string(arg1)); + arr.subarray = js_html_compat_Uint8Array._subarray; + arr.set = js_html_compat_Uint8Array._set; + return arr; +}; +js_html_compat_Uint8Array._set = function(arg,offset) { + var t = this; + if(js_Boot.__instanceof(arg.buffer,js_html_compat_ArrayBuffer)) { + var a = arg; + if(arg.byteLength + offset > t.byteLength) throw new js__$Boot_HaxeError("set() outside of range"); + var _g1 = 0; + var _g = arg.byteLength; + while(_g1 < _g) { + var i = _g1++; + t[i + offset] = a[i]; + } + } else if((arg instanceof Array) && arg.__enum__ == null) { + var a1 = arg; + if(a1.length + offset > t.byteLength) throw new js__$Boot_HaxeError("set() outside of range"); + var _g11 = 0; + var _g2 = a1.length; + while(_g11 < _g2) { + var i1 = _g11++; + t[i1 + offset] = a1[i1]; + } + } else throw new js__$Boot_HaxeError("TODO"); +}; +js_html_compat_Uint8Array._subarray = function(start,end) { + var t = this; + var a = js_html_compat_Uint8Array._new(t.slice(start,end)); + a.byteOffset = start; + return a; +}; +var promhx_base_AsyncBase = function(d) { + this._resolved = false; + this._pending = false; + this._errorPending = false; + this._fulfilled = false; + this._update = []; + this._error = []; + this._errored = false; + if(d != null) promhx_base_AsyncBase.link(d,this,function(x) { + return x; + }); +}; +$hxClasses["promhx.base.AsyncBase"] = promhx_base_AsyncBase; +promhx_base_AsyncBase.__name__ = ["promhx","base","AsyncBase"]; +promhx_base_AsyncBase.link = function(current,next,f) { + current._update.push({ async : next, linkf : function(x) { + next.handleResolve(f(x)); + }}); + promhx_base_AsyncBase.immediateLinkUpdate(current,next,f); +}; +promhx_base_AsyncBase.immediateLinkUpdate = function(current,next,f) { + if(current._errored && !current._errorPending && !(current._error.length > 0)) next.handleError(current._errorVal); + if(current._resolved && !current._pending) try { + next.handleResolve(f(current._val)); + } catch( e ) { + if (e instanceof js__$Boot_HaxeError) e = e.val; + next.handleError(e); + } +}; +promhx_base_AsyncBase.linkAll = function(all,next) { + var cthen = function(arr,current,v) { + if(arr.length == 0 || promhx_base_AsyncBase.allFulfilled(arr)) { + var vals; + var _g = []; + var $it0 = $iterator(all)(); + while( $it0.hasNext() ) { + var a = $it0.next(); + _g.push(a == current?v:a._val); + } + vals = _g; + next.handleResolve(vals); + } + null; + return; + }; + var $it1 = $iterator(all)(); + while( $it1.hasNext() ) { + var a1 = $it1.next(); + a1._update.push({ async : next, linkf : (function(f,a11,a2) { + return function(v1) { + f(a11,a2,v1); + return; + }; + })(cthen,(function($this) { + var $r; + var _g1 = []; + var $it2 = $iterator(all)(); + while( $it2.hasNext() ) { + var a21 = $it2.next(); + if(a21 != a1) _g1.push(a21); + } + $r = _g1; + return $r; + }(this)),a1)}); + } + if(promhx_base_AsyncBase.allFulfilled(all)) next.handleResolve((function($this) { + var $r; + var _g2 = []; + var $it3 = $iterator(all)(); + while( $it3.hasNext() ) { + var a3 = $it3.next(); + _g2.push(a3._val); + } + $r = _g2; + return $r; + }(this))); +}; +promhx_base_AsyncBase.pipeLink = function(current,ret,f) { + var linked = false; + var linkf = function(x) { + if(!linked) { + linked = true; + var pipe_ret = f(x); + pipe_ret._update.push({ async : ret, linkf : $bind(ret,ret.handleResolve)}); + promhx_base_AsyncBase.immediateLinkUpdate(pipe_ret,ret,function(x1) { + return x1; + }); + } + }; + current._update.push({ async : ret, linkf : linkf}); + if(current._resolved && !current._pending) try { + linkf(current._val); + } catch( e ) { + if (e instanceof js__$Boot_HaxeError) e = e.val; + ret.handleError(e); + } +}; +promhx_base_AsyncBase.allResolved = function($as) { + var $it0 = $iterator($as)(); + while( $it0.hasNext() ) { + var a = $it0.next(); + if(!a._resolved) return false; + } + return true; +}; +promhx_base_AsyncBase.allFulfilled = function($as) { + var $it0 = $iterator($as)(); + while( $it0.hasNext() ) { + var a = $it0.next(); + if(!a._fulfilled) return false; + } + return true; +}; +promhx_base_AsyncBase.prototype = { + catchError: function(f) { + this._error.push(f); + return this; + } + ,errorThen: function(f) { + this._errorMap = f; + return this; + } + ,isResolved: function() { + return this._resolved; + } + ,isErrored: function() { + return this._errored; + } + ,isErrorHandled: function() { + return this._error.length > 0; + } + ,isErrorPending: function() { + return this._errorPending; + } + ,isFulfilled: function() { + return this._fulfilled; + } + ,isPending: function() { + return this._pending; + } + ,handleResolve: function(val) { + this._resolve(val); + } + ,_resolve: function(val) { + var _g = this; + if(this._pending) promhx_base_EventLoop.enqueue((function(f,a1) { + return function() { + f(a1); + }; + })($bind(this,this._resolve),val)); else { + this._resolved = true; + this._pending = true; + promhx_base_EventLoop.queue.add(function() { + _g._val = val; + var _g1 = 0; + var _g2 = _g._update; + while(_g1 < _g2.length) { + var up = _g2[_g1]; + ++_g1; + try { + up.linkf(val); + } catch( e ) { + if (e instanceof js__$Boot_HaxeError) e = e.val; + up.async.handleError(e); + } + } + _g._fulfilled = true; + _g._pending = false; + }); + promhx_base_EventLoop.continueOnNextLoop(); + } + } + ,handleError: function(error) { + this._handleError(error); + } + ,_handleError: function(error) { + var _g = this; + var update_errors = function(e) { + if(_g._error.length > 0) { + var _g1 = 0; + var _g2 = _g._error; + while(_g1 < _g2.length) { + var ef = _g2[_g1]; + ++_g1; + ef(e); + } + } else if(_g._update.length > 0) { + var _g11 = 0; + var _g21 = _g._update; + while(_g11 < _g21.length) { + var up = _g21[_g11]; + ++_g11; + up.async.handleError(e); + } + } else throw new js__$Boot_HaxeError(e); + _g._errorPending = false; + }; + if(!this._errorPending) { + this._errorPending = true; + this._errored = true; + this._errorVal = error; + promhx_base_EventLoop.queue.add(function() { + if(_g._errorMap != null) try { + _g._resolve(_g._errorMap(error)); + } catch( e1 ) { + if (e1 instanceof js__$Boot_HaxeError) e1 = e1.val; + update_errors(e1); + } else update_errors(error); + }); + promhx_base_EventLoop.continueOnNextLoop(); + } + } + ,then: function(f) { + var ret = new promhx_base_AsyncBase(); + promhx_base_AsyncBase.link(this,ret,f); + return ret; + } + ,unlink: function(to) { + var _g = this; + promhx_base_EventLoop.queue.add(function() { + _g._update = _g._update.filter(function(x) { + return x.async != to; + }); + }); + promhx_base_EventLoop.continueOnNextLoop(); + } + ,isLinked: function(to) { + var updated = false; + var _g = 0; + var _g1 = this._update; + while(_g < _g1.length) { + var u = _g1[_g]; + ++_g; + if(u.async == to) return true; + } + return updated; + } + ,__class__: promhx_base_AsyncBase +}; +var promhx_Deferred = $hx_exports.promhx.Deferred = function() { + promhx_base_AsyncBase.call(this); +}; +$hxClasses["promhx.Deferred"] = promhx_Deferred; +promhx_Deferred.__name__ = ["promhx","Deferred"]; +promhx_Deferred.__super__ = promhx_base_AsyncBase; +promhx_Deferred.prototype = $extend(promhx_base_AsyncBase.prototype,{ + resolve: function(val) { + this.handleResolve(val); + } + ,throwError: function(e) { + this.handleError(e); + } + ,promise: function() { + return new promhx_Promise(this); + } + ,stream: function() { + return new promhx_Stream(this); + } + ,publicStream: function() { + return new promhx_PublicStream(this); + } + ,__class__: promhx_Deferred +}); +var promhx_Promise = $hx_exports.promhx.Promise = function(d) { + promhx_base_AsyncBase.call(this,d); + this._rejected = false; +}; +$hxClasses["promhx.Promise"] = promhx_Promise; +promhx_Promise.__name__ = ["promhx","Promise"]; +promhx_Promise.whenAll = function(itb) { + var ret = new promhx_Promise(); + promhx_base_AsyncBase.linkAll(itb,ret); + return ret; +}; +promhx_Promise.promise = function(_val) { + var ret = new promhx_Promise(); + ret.handleResolve(_val); + return ret; +}; +promhx_Promise.__super__ = promhx_base_AsyncBase; +promhx_Promise.prototype = $extend(promhx_base_AsyncBase.prototype,{ + isRejected: function() { + return this._rejected; + } + ,reject: function(e) { + this._rejected = true; + this.handleError(e); + } + ,handleResolve: function(val) { + if(this._resolved) { + var msg = "Promise has already been resolved"; + throw new js__$Boot_HaxeError(promhx_error_PromiseError.AlreadyResolved(msg)); + } + this._resolve(val); + } + ,then: function(f) { + var ret = new promhx_Promise(); + promhx_base_AsyncBase.link(this,ret,f); + return ret; + } + ,unlink: function(to) { + var _g = this; + promhx_base_EventLoop.queue.add(function() { + if(!_g._fulfilled) { + var msg = "Downstream Promise is not fullfilled"; + _g.handleError(promhx_error_PromiseError.DownstreamNotFullfilled(msg)); + } else _g._update = _g._update.filter(function(x) { + return x.async != to; + }); + }); + promhx_base_EventLoop.continueOnNextLoop(); + } + ,handleError: function(error) { + this._rejected = true; + this._handleError(error); + } + ,pipe: function(f) { + var ret = new promhx_Promise(); + promhx_base_AsyncBase.pipeLink(this,ret,f); + return ret; + } + ,errorPipe: function(f) { + var ret = new promhx_Promise(); + this.catchError(function(e) { + var piped = f(e); + piped.then($bind(ret,ret._resolve)); + }); + this.then($bind(ret,ret._resolve)); + return ret; + } + ,__class__: promhx_Promise +}); +var promhx_Stream = $hx_exports.promhx.Stream = function(d) { + promhx_base_AsyncBase.call(this,d); + this._end_deferred = new promhx_Deferred(); + this._end_promise = this._end_deferred.promise(); +}; +$hxClasses["promhx.Stream"] = promhx_Stream; +promhx_Stream.__name__ = ["promhx","Stream"]; +promhx_Stream.foreach = function(itb) { + var s = new promhx_Stream(); + var $it0 = $iterator(itb)(); + while( $it0.hasNext() ) { + var i = $it0.next(); + s.handleResolve(i); + } + s.end(); + return s; +}; +promhx_Stream.wheneverAll = function(itb) { + var ret = new promhx_Stream(); + promhx_base_AsyncBase.linkAll(itb,ret); + return ret; +}; +promhx_Stream.concatAll = function(itb) { + var ret = new promhx_Stream(); + var $it0 = $iterator(itb)(); + while( $it0.hasNext() ) { + var i = $it0.next(); + ret.concat(i); + } + return ret; +}; +promhx_Stream.mergeAll = function(itb) { + var ret = new promhx_Stream(); + var $it0 = $iterator(itb)(); + while( $it0.hasNext() ) { + var i = $it0.next(); + ret.merge(i); + } + return ret; +}; +promhx_Stream.stream = function(_val) { + var ret = new promhx_Stream(); + ret.handleResolve(_val); + return ret; +}; +promhx_Stream.__super__ = promhx_base_AsyncBase; +promhx_Stream.prototype = $extend(promhx_base_AsyncBase.prototype,{ + then: function(f) { + var ret = new promhx_Stream(); + promhx_base_AsyncBase.link(this,ret,f); + this._end_promise.then(function(x) { + ret.end(); + }); + return ret; + } + ,detachStream: function(str) { + var filtered = []; + var removed = false; + var _g = 0; + var _g1 = this._update; + while(_g < _g1.length) { + var u = _g1[_g]; + ++_g; + if(u.async == str) removed = true; else filtered.push(u); + } + this._update = filtered; + return removed; + } + ,first: function() { + var s = new promhx_Promise(); + this.then(function(x) { + if(!s._resolved) s.handleResolve(x); + }); + return s; + } + ,handleResolve: function(val) { + if(!this._end && !this._pause) this._resolve(val); + } + ,pause: function(set) { + if(set == null) set = !this._pause; + this._pause = set; + } + ,pipe: function(f) { + var ret = new promhx_Stream(); + promhx_base_AsyncBase.pipeLink(this,ret,f); + this._end_promise.then(function(x) { + ret.end(); + }); + return ret; + } + ,errorPipe: function(f) { + var ret = new promhx_Stream(); + this.catchError(function(e) { + var piped = f(e); + piped.then($bind(ret,ret._resolve)); + piped._end_promise.then(($_=ret._end_promise,$bind($_,$_._resolve))); + }); + this.then($bind(ret,ret._resolve)); + this._end_promise.then(function(x) { + ret.end(); + }); + return ret; + } + ,handleEnd: function() { + if(this._pending) { + promhx_base_EventLoop.queue.add($bind(this,this.handleEnd)); + promhx_base_EventLoop.continueOnNextLoop(); + } else if(this._end_promise._resolved) return; else { + this._end = true; + var o; + if(this._resolved) o = haxe_ds_Option.Some(this._val); else o = haxe_ds_Option.None; + this._end_promise.handleResolve(o); + this._update = []; + this._error = []; + } + } + ,end: function() { + promhx_base_EventLoop.queue.add($bind(this,this.handleEnd)); + promhx_base_EventLoop.continueOnNextLoop(); + return this; + } + ,endThen: function(f) { + return this._end_promise.then(f); + } + ,filter: function(f) { + var ret = new promhx_Stream(); + this._update.push({ async : ret, linkf : function(x) { + if(f(x)) ret.handleResolve(x); + }}); + promhx_base_AsyncBase.immediateLinkUpdate(this,ret,function(x1) { + return x1; + }); + return ret; + } + ,concat: function(s) { + var ret = new promhx_Stream(); + this._update.push({ async : ret, linkf : $bind(ret,ret.handleResolve)}); + promhx_base_AsyncBase.immediateLinkUpdate(this,ret,function(x) { + return x; + }); + this._end_promise.then(function(_) { + s.pipe(function(x1) { + ret.handleResolve(x1); + return ret; + }); + s._end_promise.then(function(_1) { + ret.end(); + }); + }); + return ret; + } + ,merge: function(s) { + var ret = new promhx_Stream(); + this._update.push({ async : ret, linkf : $bind(ret,ret.handleResolve)}); + s._update.push({ async : ret, linkf : $bind(ret,ret.handleResolve)}); + promhx_base_AsyncBase.immediateLinkUpdate(this,ret,function(x) { + return x; + }); + promhx_base_AsyncBase.immediateLinkUpdate(s,ret,function(x1) { + return x1; + }); + return ret; + } + ,__class__: promhx_Stream +}); +var promhx_PublicStream = $hx_exports.promhx.PublicStream = function(def) { + promhx_Stream.call(this,def); +}; +$hxClasses["promhx.PublicStream"] = promhx_PublicStream; +promhx_PublicStream.__name__ = ["promhx","PublicStream"]; +promhx_PublicStream.publicstream = function(val) { + var ps = new promhx_PublicStream(); + ps.handleResolve(val); + return ps; +}; +promhx_PublicStream.__super__ = promhx_Stream; +promhx_PublicStream.prototype = $extend(promhx_Stream.prototype,{ + resolve: function(val) { + this.handleResolve(val); + } + ,throwError: function(e) { + this.handleError(e); + } + ,update: function(val) { + this.handleResolve(val); + } + ,__class__: promhx_PublicStream +}); +var promhx_base_EventLoop = function() { }; +$hxClasses["promhx.base.EventLoop"] = promhx_base_EventLoop; +promhx_base_EventLoop.__name__ = ["promhx","base","EventLoop"]; +promhx_base_EventLoop.enqueue = function(eqf) { + promhx_base_EventLoop.queue.add(eqf); + promhx_base_EventLoop.continueOnNextLoop(); +}; +promhx_base_EventLoop.set_nextLoop = function(f) { + if(promhx_base_EventLoop.nextLoop != null) throw new js__$Boot_HaxeError("nextLoop has already been set"); else promhx_base_EventLoop.nextLoop = f; + return promhx_base_EventLoop.nextLoop; +}; +promhx_base_EventLoop.queueEmpty = function() { + return promhx_base_EventLoop.queue.isEmpty(); +}; +promhx_base_EventLoop.finish = function(max_iterations) { + if(max_iterations == null) max_iterations = 1000; + var fn = null; + while(max_iterations-- > 0 && (fn = promhx_base_EventLoop.queue.pop()) != null) fn(); + return promhx_base_EventLoop.queue.isEmpty(); +}; +promhx_base_EventLoop.clear = function() { + promhx_base_EventLoop.queue = new List(); +}; +promhx_base_EventLoop.f = function() { + var fn = promhx_base_EventLoop.queue.pop(); + if(fn != null) fn(); + if(!promhx_base_EventLoop.queue.isEmpty()) promhx_base_EventLoop.continueOnNextLoop(); +}; +promhx_base_EventLoop.continueOnNextLoop = function() { + if(promhx_base_EventLoop.nextLoop != null) promhx_base_EventLoop.nextLoop(promhx_base_EventLoop.f); else setImmediate(promhx_base_EventLoop.f); +}; +var promhx_error_PromiseError = $hxClasses["promhx.error.PromiseError"] = { __ename__ : ["promhx","error","PromiseError"], __constructs__ : ["AlreadyResolved","DownstreamNotFullfilled"] }; +promhx_error_PromiseError.AlreadyResolved = function(message) { var $x = ["AlreadyResolved",0,message]; $x.__enum__ = promhx_error_PromiseError; $x.toString = $estr; return $x; }; +promhx_error_PromiseError.DownstreamNotFullfilled = function(message) { var $x = ["DownstreamNotFullfilled",1,message]; $x.__enum__ = promhx_error_PromiseError; $x.toString = $estr; return $x; }; +var verb_Verb = function() { }; +$hxClasses["verb.Verb"] = verb_Verb; +verb_Verb.__name__ = ["verb","Verb"]; +verb_Verb.main = function() { + console.log("verb 2.1.0"); +}; +var verb_core_ArrayExtensions = function() { }; +$hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; +verb_core_ArrayExtensions.__name__ = ["verb","core","ArrayExtensions"]; +verb_core_ArrayExtensions.alloc = function(a,n) { + if(n < 0) return; + while(a.length < n) a.push(null); +}; +verb_core_ArrayExtensions.reversed = function(a) { + var ac = a.slice(); + ac.reverse(); + return ac; +}; +verb_core_ArrayExtensions.last = function(a) { + return a[a.length - 1]; +}; +verb_core_ArrayExtensions.first = function(a) { + return a[0]; +}; +verb_core_ArrayExtensions.spliceAndInsert = function(a,start,end,ele) { + a.splice(start,end); + a.splice(start,0,ele); +}; +verb_core_ArrayExtensions.left = function(arr) { + if(arr.length == 0) return []; + var len = Math.ceil(arr.length / 2); + return arr.slice(0,len); +}; +verb_core_ArrayExtensions.right = function(arr) { + if(arr.length == 0) return []; + var len = Math.ceil(arr.length / 2); + return arr.slice(len); +}; +verb_core_ArrayExtensions.rightWithPivot = function(arr) { + if(arr.length == 0) return []; + var len = Math.ceil(arr.length / 2); + return arr.slice(len - 1); +}; +verb_core_ArrayExtensions.unique = function(arr,comp) { + if(arr.length == 0) return []; + var uniques = [arr.pop()]; + while(arr.length > 0) { + var ele = arr.pop(); + var isUnique = true; + var _g = 0; + while(_g < uniques.length) { + var unique = uniques[_g]; + ++_g; + if(comp(ele,unique)) { + isUnique = false; + break; + } + } + if(isUnique) uniques.push(ele); + } + return uniques; +}; +var verb_core_Binomial = function() { }; +$hxClasses["verb.core.Binomial"] = verb_core_Binomial; +verb_core_Binomial.__name__ = ["verb","core","Binomial"]; +verb_core_Binomial.get = function(n,k) { + if(k == 0.0) return 1.0; + if(n == 0 || k > n) return 0.0; + if(k > n - k) k = n - k; + if(verb_core_Binomial.memo_exists(n,k)) return verb_core_Binomial.get_memo(n,k); + var r = 1; + var n_o = n; + var _g1 = 1; + var _g = k + 1; + while(_g1 < _g) { + var d = _g1++; + if(verb_core_Binomial.memo_exists(n_o,d)) { + n--; + r = verb_core_Binomial.get_memo(n_o,d); + continue; + } + r *= n--; + r /= d; + verb_core_Binomial.memoize(n_o,d,r); + } + return r; +}; +verb_core_Binomial.get_no_memo = function(n,k) { + if(k == 0) return 1; + if(n == 0 || k > n) return 0; + if(k > n - k) k = n - k; + var r = 1; + var n_o = n; + var _g1 = 1; + var _g = k + 1; + while(_g1 < _g) { + var d = _g1++; + r *= n--; + r /= d; + } + return r; +}; +verb_core_Binomial.memo_exists = function(n,k) { + return verb_core_Binomial.memo.h.hasOwnProperty(n) && verb_core_Binomial.memo.h[n].h.hasOwnProperty(k); +}; +verb_core_Binomial.get_memo = function(n,k) { + return verb_core_Binomial.memo.h[n].h[k]; +}; +verb_core_Binomial.memoize = function(n,k,val) { + if(!verb_core_Binomial.memo.h.hasOwnProperty(n)) verb_core_Binomial.memo.set(n,new haxe_ds_IntMap()); + verb_core_Binomial.memo.h[n].h[k] = val; +}; +var verb_core_BoundingBox = $hx_exports.core.BoundingBox = function(pts) { + this.max = null; + this.min = null; + this.dim = 3; + this.initialized = false; + if(pts != null) this.addRange(pts); +}; +$hxClasses["verb.core.BoundingBox"] = verb_core_BoundingBox; +verb_core_BoundingBox.__name__ = ["verb","core","BoundingBox"]; +verb_core_BoundingBox.intervalsOverlap = function(a1,a2,b1,b2,tol) { + if(tol == null) tol = -1; + var tol1; + if(tol < -0.5) tol1 = verb_core_Constants.TOLERANCE; else tol1 = tol; + var x1 = Math.min(a1,a2) - tol1; + var x2 = Math.max(a1,a2) + tol1; + var y1 = Math.min(b1,b2) - tol1; + var y2 = Math.max(b1,b2) + tol1; + return x1 >= y1 && x1 <= y2 || x2 >= y1 && x2 <= y2 || y1 >= x1 && y1 <= x2 || y2 >= x1 && y2 <= x2; +}; +verb_core_BoundingBox.prototype = { + fromPoint: function(pt) { + return new verb_core_BoundingBox([pt]); + } + ,add: function(point) { + if(!this.initialized) { + this.dim = point.length; + this.min = point.slice(0); + this.max = point.slice(0); + this.initialized = true; + return this; + } + var _g1 = 0; + var _g = this.dim; + while(_g1 < _g) { + var i = _g1++; + if(point[i] > this.max[i]) this.max[i] = point[i]; + if(point[i] < this.min[i]) this.min[i] = point[i]; + } + return this; + } + ,addRange: function(points) { + var l = points.length; + var _g = 0; + while(_g < l) { + var i = _g++; + this.add(points[i]); + } + return this; + } + ,contains: function(point,tol) { + if(tol == null) tol = -1; + if(!this.initialized) return false; + return this.intersects(new verb_core_BoundingBox([point]),tol); + } + ,intersects: function(bb,tol) { + if(tol == null) tol = -1; + if(!this.initialized || !bb.initialized) return false; + var a1 = this.min; + var a2 = this.max; + var b1 = bb.min; + var b2 = bb.max; + var _g1 = 0; + var _g = this.dim; + while(_g1 < _g) { + var i = _g1++; + if(!verb_core_BoundingBox.intervalsOverlap(a1[i],a2[i],b1[i],b2[i],tol)) return false; + } + return true; + } + ,clear: function() { + this.initialized = false; + return this; + } + ,getLongestAxis: function() { + var max = 0.0; + var id = 0; + var _g1 = 0; + var _g = this.dim; + while(_g1 < _g) { + var i = _g1++; + var l = this.getAxisLength(i); + if(l > max) { + max = l; + id = i; + } + } + return id; + } + ,getAxisLength: function(i) { + if(i < 0 || i > this.dim - 1) return 0.0; + return Math.abs(this.min[i] - this.max[i]); + } + ,intersect: function(bb,tol) { + if(!this.initialized) return null; + var a1 = this.min; + var a2 = this.max; + var b1 = bb.min; + var b2 = bb.max; + if(!this.intersects(bb,tol)) return null; + var maxbb = []; + var minbb = []; + var _g1 = 0; + var _g = this.dim; + while(_g1 < _g) { + var i = _g1++; + maxbb.push(Math.min(a2[i],b2[i])); + minbb.push(Math.max(a1[i],b1[i])); + } + return new verb_core_BoundingBox([minbb,maxbb]); + } + ,__class__: verb_core_BoundingBox +}; +var verb_core_Constants = $hx_exports.core.Constants = function() { }; +$hxClasses["verb.core.Constants"] = verb_core_Constants; +verb_core_Constants.__name__ = ["verb","core","Constants"]; +var verb_core_SerializableBase = $hx_exports.core.SerializableBase = function() { }; +$hxClasses["verb.core.SerializableBase"] = verb_core_SerializableBase; +verb_core_SerializableBase.__name__ = ["verb","core","SerializableBase"]; +verb_core_SerializableBase.prototype = { + serialize: function() { + var serializer = new haxe_Serializer(); + serializer.serialize(this); + return serializer.toString(); + } + ,__class__: verb_core_SerializableBase +}; +var verb_core_Plane = $hx_exports.core.Plane = function(origin,normal) { + this.origin = origin; + this.normal = normal; +}; +$hxClasses["verb.core.Plane"] = verb_core_Plane; +verb_core_Plane.__name__ = ["verb","core","Plane"]; +verb_core_Plane.__super__ = verb_core_SerializableBase; +verb_core_Plane.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_Plane +}); +var verb_core_Ray = $hx_exports.core.Ray = function(origin,dir) { + this.origin = origin; + this.dir = dir; +}; +$hxClasses["verb.core.Ray"] = verb_core_Ray; +verb_core_Ray.__name__ = ["verb","core","Ray"]; +verb_core_Ray.__super__ = verb_core_SerializableBase; +verb_core_Ray.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_Ray +}); +var verb_core_NurbsCurveData = $hx_exports.core.NurbsCurveData = function(degree,knots,controlPoints) { + this.degree = degree; + this.controlPoints = controlPoints; + this.knots = knots; +}; +$hxClasses["verb.core.NurbsCurveData"] = verb_core_NurbsCurveData; +verb_core_NurbsCurveData.__name__ = ["verb","core","NurbsCurveData"]; +verb_core_NurbsCurveData.__super__ = verb_core_SerializableBase; +verb_core_NurbsCurveData.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_NurbsCurveData +}); +var verb_core_NurbsSurfaceData = $hx_exports.core.NurbsSurfaceData = function(degreeU,degreeV,knotsU,knotsV,controlPoints) { + this.degreeU = degreeU; + this.degreeV = degreeV; + this.knotsU = knotsU; + this.knotsV = knotsV; + this.controlPoints = controlPoints; +}; +$hxClasses["verb.core.NurbsSurfaceData"] = verb_core_NurbsSurfaceData; +verb_core_NurbsSurfaceData.__name__ = ["verb","core","NurbsSurfaceData"]; +verb_core_NurbsSurfaceData.__super__ = verb_core_SerializableBase; +verb_core_NurbsSurfaceData.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_NurbsSurfaceData +}); +var verb_core_MeshData = $hx_exports.core.MeshData = function(faces,points,normals,uvs) { + this.faces = faces; + this.points = points; + this.normals = normals; + this.uvs = uvs; +}; +$hxClasses["verb.core.MeshData"] = verb_core_MeshData; +verb_core_MeshData.__name__ = ["verb","core","MeshData"]; +verb_core_MeshData.empty = function() { + return new verb_core_MeshData([],[],[],[]); +}; +verb_core_MeshData.__super__ = verb_core_SerializableBase; +verb_core_MeshData.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_MeshData +}); +var verb_core_PolylineData = $hx_exports.core.PolylineData = function(points,params) { + this.points = points; + this.params = params; +}; +$hxClasses["verb.core.PolylineData"] = verb_core_PolylineData; +verb_core_PolylineData.__name__ = ["verb","core","PolylineData"]; +verb_core_PolylineData.__super__ = verb_core_SerializableBase; +verb_core_PolylineData.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_PolylineData +}); +var verb_core_VolumeData = $hx_exports.core.VolumeData = function(degreeU,degreeV,degreeW,knotsU,knotsV,knotsW,controlPoints) { + this.degreeU = degreeU; + this.degreeV = degreeV; + this.degreeW = degreeW; + this.knotsU = knotsU; + this.knotsV = knotsV; + this.knotsW = knotsW; + this.controlPoints = controlPoints; +}; +$hxClasses["verb.core.VolumeData"] = verb_core_VolumeData; +verb_core_VolumeData.__name__ = ["verb","core","VolumeData"]; +verb_core_VolumeData.__super__ = verb_core_SerializableBase; +verb_core_VolumeData.prototype = $extend(verb_core_SerializableBase.prototype,{ + __class__: verb_core_VolumeData +}); +var verb_core_Pair = $hx_exports.core.Pair = function(item1,item2) { + this.item0 = item1; + this.item1 = item2; +}; +$hxClasses["verb.core.Pair"] = verb_core_Pair; +verb_core_Pair.__name__ = ["verb","core","Pair"]; +verb_core_Pair.prototype = { + __class__: verb_core_Pair +}; +var verb_core_Interval = $hx_exports.core.Interval = function(min,max) { + this.min = min; + this.max = max; +}; +$hxClasses["verb.core.Interval"] = verb_core_Interval; +verb_core_Interval.__name__ = ["verb","core","Interval"]; +verb_core_Interval.prototype = { + __class__: verb_core_Interval +}; +var verb_core_CurveCurveIntersection = $hx_exports.core.CurveCurveIntersection = function(point0,point1,u0,u1) { + this.point0 = point0; + this.point1 = point1; + this.u0 = u0; + this.u1 = u1; +}; +$hxClasses["verb.core.CurveCurveIntersection"] = verb_core_CurveCurveIntersection; +verb_core_CurveCurveIntersection.__name__ = ["verb","core","CurveCurveIntersection"]; +verb_core_CurveCurveIntersection.prototype = { + __class__: verb_core_CurveCurveIntersection +}; +var verb_core_CurveSurfaceIntersection = $hx_exports.core.CurveSurfaceIntersection = function(u,uv,curvePoint,surfacePoint) { + this.u = u; + this.uv = uv; + this.curvePoint = curvePoint; + this.surfacePoint = surfacePoint; +}; +$hxClasses["verb.core.CurveSurfaceIntersection"] = verb_core_CurveSurfaceIntersection; +verb_core_CurveSurfaceIntersection.__name__ = ["verb","core","CurveSurfaceIntersection"]; +verb_core_CurveSurfaceIntersection.prototype = { + __class__: verb_core_CurveSurfaceIntersection +}; +var verb_core_MeshIntersectionPoint = $hx_exports.core.MeshIntersectionPoint = function(uv0,uv1,point,faceIndex0,faceIndex1) { + this.visited = false; + this.adj = null; + this.opp = null; + this.uv0 = uv0; + this.uv1 = uv1; + this.point = point; + this.faceIndex0; + this.faceIndex1; +}; +$hxClasses["verb.core.MeshIntersectionPoint"] = verb_core_MeshIntersectionPoint; +verb_core_MeshIntersectionPoint.__name__ = ["verb","core","MeshIntersectionPoint"]; +verb_core_MeshIntersectionPoint.prototype = { + __class__: verb_core_MeshIntersectionPoint +}; +var verb_core_PolylineMeshIntersection = $hx_exports.core.PolylineMeshIntersection = function(point,u,uv,polylineIndex,faceIndex) { + this.point = point; + this.u = u; + this.uv = uv; + this.polylineIndex = polylineIndex; + this.faceIndex = faceIndex; +}; +$hxClasses["verb.core.PolylineMeshIntersection"] = verb_core_PolylineMeshIntersection; +verb_core_PolylineMeshIntersection.__name__ = ["verb","core","PolylineMeshIntersection"]; +verb_core_PolylineMeshIntersection.prototype = { + __class__: verb_core_PolylineMeshIntersection +}; +var verb_core_SurfaceSurfaceIntersectionPoint = $hx_exports.core.SurfaceSurfaceIntersectionPoint = function(uv0,uv1,point,dist) { + this.uv0 = uv0; + this.uv1 = uv1; + this.point = point; + this.dist = dist; +}; +$hxClasses["verb.core.SurfaceSurfaceIntersectionPoint"] = verb_core_SurfaceSurfaceIntersectionPoint; +verb_core_SurfaceSurfaceIntersectionPoint.__name__ = ["verb","core","SurfaceSurfaceIntersectionPoint"]; +verb_core_SurfaceSurfaceIntersectionPoint.prototype = { + __class__: verb_core_SurfaceSurfaceIntersectionPoint +}; +var verb_core_TriSegmentIntersection = $hx_exports.core.TriSegmentIntersection = function(point,s,t,r) { + this.point = point; + this.s = s; + this.t = t; + this.p = r; +}; +$hxClasses["verb.core.TriSegmentIntersection"] = verb_core_TriSegmentIntersection; +verb_core_TriSegmentIntersection.__name__ = ["verb","core","TriSegmentIntersection"]; +verb_core_TriSegmentIntersection.prototype = { + __class__: verb_core_TriSegmentIntersection +}; +var verb_core_CurveTriPoint = $hx_exports.core.CurveTriPoint = function(u,point,uv) { + this.u = u; + this.point = point; + this.uv = uv; +}; +$hxClasses["verb.core.CurveTriPoint"] = verb_core_CurveTriPoint; +verb_core_CurveTriPoint.__name__ = ["verb","core","CurveTriPoint"]; +verb_core_CurveTriPoint.prototype = { + __class__: verb_core_CurveTriPoint +}; +var verb_core_SurfacePoint = function(point,normal,uv,id,degen) { + if(degen == null) degen = false; + if(id == null) id = -1; + this.uv = uv; + this.point = point; + this.normal = normal; + this.id = id; + this.degen = degen; +}; +$hxClasses["verb.core.SurfacePoint"] = verb_core_SurfacePoint; +verb_core_SurfacePoint.__name__ = ["verb","core","SurfacePoint"]; +verb_core_SurfacePoint.fromUv = function(u,v) { + return new verb_core_SurfacePoint(null,null,[u,v]); +}; +verb_core_SurfacePoint.prototype = { + __class__: verb_core_SurfacePoint +}; +var verb_core_CurvePoint = $hx_exports.core.CurvePoint = function(u,pt) { + this.u = u; + this.pt = pt; +}; +$hxClasses["verb.core.CurvePoint"] = verb_core_CurvePoint; +verb_core_CurvePoint.__name__ = ["verb","core","CurvePoint"]; +verb_core_CurvePoint.prototype = { + __class__: verb_core_CurvePoint +}; +var verb_core_KdTree = $hx_exports.core.KdTree = function(points,distanceFunction) { + this.dim = 3; + this.points = points; + this.distanceFunction = distanceFunction; + this.dim = points[0].point.length; + this.root = this.buildTree(points,0,null); +}; +$hxClasses["verb.core.KdTree"] = verb_core_KdTree; +verb_core_KdTree.__name__ = ["verb","core","KdTree"]; +verb_core_KdTree.prototype = { + buildTree: function(points,depth,parent) { + var dim = depth % this.dim; + var median; + var node; + if(points.length == 0) return null; + if(points.length == 1) return new verb_core_KdNode(points[0],dim,parent); + points.sort(function(a,b) { + var diff = a.point[dim] - b.point[dim]; + if(diff == 0.0) return 0; else if(diff > 0) return 1; else return -1; + }); + median = Math.floor(points.length / 2); + node = new verb_core_KdNode(points[median],dim,parent); + node.left = this.buildTree(points.slice(0,median),depth + 1,node); + node.right = this.buildTree(points.slice(median + 1),depth + 1,node); + return node; + } + ,nearest: function(point,maxNodes,maxDistance) { + var _g = this; + var bestNodes = new verb_core_BinaryHeap(function(e) { + return -e.item1; + }); + var nearestSearch; + var nearestSearch1 = null; + nearestSearch1 = function(node) { + var bestChild; + var dimension = node.dimension; + var ownDistance = _g.distanceFunction(point,node.kdPoint.point); + var linearPoint; + var _g1 = []; + var _g3 = 0; + var _g2 = _g.dim; + while(_g3 < _g2) { + var i1 = _g3++; + _g1.push(0.0); + } + linearPoint = _g1; + var linearDistance; + var otherChild; + var i; + var saveNode = function(node1,distance) { + bestNodes.push(new verb_core_Pair(node1,distance)); + if(bestNodes.size() > maxNodes) bestNodes.pop(); + }; + var _g31 = 0; + var _g21 = _g.dim; + while(_g31 < _g21) { + var i2 = _g31++; + if(i2 == node.dimension) linearPoint[i2] = point[i2]; else linearPoint[i2] = node.kdPoint.point[i2]; + } + linearDistance = _g.distanceFunction(linearPoint,node.kdPoint.point); + if(node.right == null && node.left == null) { + if(bestNodes.size() < maxNodes || ownDistance < bestNodes.peek().item1) saveNode(node,ownDistance); + return; + } + if(node.right == null) bestChild = node.left; else if(node.left == null) bestChild = node.right; else if(point[dimension] < node.kdPoint.point[dimension]) bestChild = node.left; else bestChild = node.right; + nearestSearch1(bestChild); + if(bestNodes.size() < maxNodes || ownDistance < bestNodes.peek().item1) saveNode(node,ownDistance); + if(bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek().item1) { + if(bestChild == node.left) otherChild = node.right; else otherChild = node.left; + if(otherChild != null) nearestSearch1(otherChild); + } + }; + nearestSearch = nearestSearch1; + var _g4 = 0; + while(_g4 < maxNodes) { + var i3 = _g4++; + bestNodes.push(new verb_core_Pair(null,maxDistance)); + } + nearestSearch(this.root); + var result = []; + var _g5 = 0; + while(_g5 < maxNodes) { + var i4 = _g5++; + if(bestNodes.content[i4].item0 != null) result.push(new verb_core_Pair(bestNodes.content[i4].item0.kdPoint,bestNodes.content[i4].item1)); + } + return result; + } + ,__class__: verb_core_KdTree +}; +var verb_core_BinaryHeap = function(scoreFunction) { + this.content = []; + this.scoreFunction = scoreFunction; +}; +$hxClasses["verb.core.BinaryHeap"] = verb_core_BinaryHeap; +verb_core_BinaryHeap.__name__ = ["verb","core","BinaryHeap"]; +verb_core_BinaryHeap.prototype = { + push: function(element) { + this.content.push(element); + this.bubbleUp(this.content.length - 1); + } + ,pop: function() { + var result = this.content[0]; + var end = this.content.pop(); + if(this.content.length > 0) { + this.content[0] = end; + this.sinkDown(0); + } + return result; + } + ,peek: function() { + return this.content[0]; + } + ,remove: function(node) { + var len = this.content.length; + var _g = 0; + while(_g < len) { + var i = _g++; + if(this.content[i] == node) { + var end = this.content.pop(); + if(i != len - 1) { + this.content[i] = end; + if(this.scoreFunction(end) < this.scoreFunction(node)) this.bubbleUp(i); else this.sinkDown(i); + } + return; + } + } + throw new js__$Boot_HaxeError("Node not found."); + } + ,size: function() { + return this.content.length; + } + ,bubbleUp: function(n) { + var element = this.content[n]; + while(n > 0) { + var parentN = Math.floor((n + 1.0) / 2) - 1; + var parent = this.content[parentN]; + if(this.scoreFunction(element) < this.scoreFunction(parent)) { + this.content[parentN] = element; + this.content[n] = parent; + n = parentN; + } else break; + } + } + ,sinkDown: function(n) { + var length = this.content.length; + var element = this.content[n]; + var elemScore = this.scoreFunction(element); + while(true) { + var child2N = (n + 1) * 2; + var child1N = child2N - 1; + var swap = -1; + var child1Score = 0.0; + if(child1N < length) { + var child1 = this.content[child1N]; + child1Score = this.scoreFunction(child1); + if(child1Score < elemScore) swap = child1N; + } + if(child2N < length) { + var child2 = this.content[child2N]; + var child2Score = this.scoreFunction(child2); + if(child2Score < (swap == -1?elemScore:child1Score)) swap = child2N; + } + if(swap != -1) { + this.content[n] = this.content[swap]; + this.content[swap] = element; + n = swap; + } else break; + } + } + ,__class__: verb_core_BinaryHeap +}; +var verb_core_KdPoint = $hx_exports.core.KdPoint = function(point,obj) { + this.point = point; + this.obj = obj; +}; +$hxClasses["verb.core.KdPoint"] = verb_core_KdPoint; +verb_core_KdPoint.__name__ = ["verb","core","KdPoint"]; +verb_core_KdPoint.prototype = { + __class__: verb_core_KdPoint +}; +var verb_core_KdNode = $hx_exports.core.KdNode = function(kdPoint,dimension,parent) { + this.kdPoint = kdPoint; + this.left = null; + this.right = null; + this.parent = parent; + this.dimension = dimension; +}; +$hxClasses["verb.core.KdNode"] = verb_core_KdNode; +verb_core_KdNode.__name__ = ["verb","core","KdNode"]; +verb_core_KdNode.prototype = { + __class__: verb_core_KdNode +}; +var verb_eval_IBoundingBoxTree = function() { }; +$hxClasses["verb.eval.IBoundingBoxTree"] = verb_eval_IBoundingBoxTree; +verb_eval_IBoundingBoxTree.__name__ = ["verb","eval","IBoundingBoxTree"]; +verb_eval_IBoundingBoxTree.prototype = { + __class__: verb_eval_IBoundingBoxTree +}; +var verb_core_LazyCurveBoundingBoxTree = function(curve,knotTol) { + this._boundingBox = null; + this._curve = curve; + if(knotTol == null) knotTol = verb_core_Vec.domain(this._curve.knots) / 64; + this._knotTol = knotTol; +}; +$hxClasses["verb.core.LazyCurveBoundingBoxTree"] = verb_core_LazyCurveBoundingBoxTree; +verb_core_LazyCurveBoundingBoxTree.__name__ = ["verb","core","LazyCurveBoundingBoxTree"]; +verb_core_LazyCurveBoundingBoxTree.__interfaces__ = [verb_eval_IBoundingBoxTree]; +verb_core_LazyCurveBoundingBoxTree.prototype = { + split: function() { + var min = verb_core_ArrayExtensions.first(this._curve.knots); + var max = verb_core_ArrayExtensions.last(this._curve.knots); + var dom = max - min; + var crvs = verb_eval_Divide.curveSplit(this._curve,(max + min) / 2.0 + dom * 0.1 * Math.random()); + return new verb_core_Pair(new verb_core_LazyCurveBoundingBoxTree(crvs[0],this._knotTol),new verb_core_LazyCurveBoundingBoxTree(crvs[1],this._knotTol)); + } + ,boundingBox: function() { + if(this._boundingBox == null) this._boundingBox = new verb_core_BoundingBox(verb_eval_Eval.dehomogenize1d(this._curve.controlPoints)); + return this._boundingBox; + } + ,'yield': function() { + return this._curve; + } + ,indivisible: function(tolerance) { + return verb_core_Vec.domain(this._curve.knots) < this._knotTol; + } + ,empty: function() { + return false; + } + ,__class__: verb_core_LazyCurveBoundingBoxTree +}; +var verb_core_LazyMeshBoundingBoxTree = function(mesh,faceIndices) { + this._boundingBox = null; + this._mesh = mesh; + if(faceIndices == null) { + var _g = []; + var _g2 = 0; + var _g1 = mesh.faces.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(i); + } + faceIndices = _g; + } + this._faceIndices = faceIndices; +}; +$hxClasses["verb.core.LazyMeshBoundingBoxTree"] = verb_core_LazyMeshBoundingBoxTree; +verb_core_LazyMeshBoundingBoxTree.__name__ = ["verb","core","LazyMeshBoundingBoxTree"]; +verb_core_LazyMeshBoundingBoxTree.__interfaces__ = [verb_eval_IBoundingBoxTree]; +verb_core_LazyMeshBoundingBoxTree.prototype = { + split: function() { + var $as = verb_core_Mesh.sortTrianglesOnLongestAxis(this.boundingBox(),this._mesh,this._faceIndices); + var l = verb_core_ArrayExtensions.left($as); + var r = verb_core_ArrayExtensions.right($as); + return new verb_core_Pair(new verb_core_LazyMeshBoundingBoxTree(this._mesh,l),new verb_core_LazyMeshBoundingBoxTree(this._mesh,r)); + } + ,boundingBox: function() { + if(this._boundingBox == null) this._boundingBox = verb_core_Mesh.makeMeshAabb(this._mesh,this._faceIndices); + return this._boundingBox; + } + ,'yield': function() { + return this._faceIndices[0]; + } + ,indivisible: function(tolerance) { + return this._faceIndices.length == 1; + } + ,empty: function() { + return this._faceIndices.length == 0; + } + ,__class__: verb_core_LazyMeshBoundingBoxTree +}; +var verb_core_LazyPolylineBoundingBoxTree = function(polyline,interval) { + this._boundingBox = null; + this._polyline = polyline; + if(interval == null) interval = new verb_core_Interval(0,polyline.points.length != 0?polyline.points.length - 1:0); + this._interval = interval; +}; +$hxClasses["verb.core.LazyPolylineBoundingBoxTree"] = verb_core_LazyPolylineBoundingBoxTree; +verb_core_LazyPolylineBoundingBoxTree.__name__ = ["verb","core","LazyPolylineBoundingBoxTree"]; +verb_core_LazyPolylineBoundingBoxTree.__interfaces__ = [verb_eval_IBoundingBoxTree]; +verb_core_LazyPolylineBoundingBoxTree.prototype = { + split: function() { + var min = this._interval.min; + var max = this._interval.max; + var pivot = min + Math.ceil((max - min) / 2); + var l = new verb_core_Interval(min,pivot); + var r = new verb_core_Interval(pivot,max); + return new verb_core_Pair(new verb_core_LazyPolylineBoundingBoxTree(this._polyline,l),new verb_core_LazyPolylineBoundingBoxTree(this._polyline,r)); + } + ,boundingBox: function() { + if(this._boundingBox == null) this._boundingBox = new verb_core_BoundingBox(this._polyline.points); + return this._boundingBox; + } + ,'yield': function() { + return this._interval.min; + } + ,indivisible: function(tolerance) { + return this._interval.max - this._interval.min == 1; + } + ,empty: function() { + return this._interval.max - this._interval.min == 0; + } + ,__class__: verb_core_LazyPolylineBoundingBoxTree +}; +var verb_core_LazySurfaceBoundingBoxTree = function(surface,splitV,knotTolU,knotTolV) { + if(splitV == null) splitV = false; + this._boundingBox = null; + this._surface = surface; + this._splitV = splitV; + if(knotTolU == null) knotTolU = verb_core_Vec.domain(surface.knotsU) / 16; + if(knotTolV == null) knotTolV = verb_core_Vec.domain(surface.knotsV) / 16; + this._knotTolU = knotTolU; + this._knotTolV = knotTolV; +}; +$hxClasses["verb.core.LazySurfaceBoundingBoxTree"] = verb_core_LazySurfaceBoundingBoxTree; +verb_core_LazySurfaceBoundingBoxTree.__name__ = ["verb","core","LazySurfaceBoundingBoxTree"]; +verb_core_LazySurfaceBoundingBoxTree.__interfaces__ = [verb_eval_IBoundingBoxTree]; +verb_core_LazySurfaceBoundingBoxTree.prototype = { + split: function() { + var min; + var max; + if(this._splitV) { + min = verb_core_ArrayExtensions.first(this._surface.knotsV); + max = verb_core_ArrayExtensions.last(this._surface.knotsV); + } else { + min = verb_core_ArrayExtensions.first(this._surface.knotsU); + max = verb_core_ArrayExtensions.last(this._surface.knotsU); + } + var dom = max - min; + var pivot = (min + max) / 2.0; + var srfs = verb_eval_Divide.surfaceSplit(this._surface,pivot,this._splitV); + return new verb_core_Pair(new verb_core_LazySurfaceBoundingBoxTree(srfs[0],!this._splitV,this._knotTolU,this._knotTolV),new verb_core_LazySurfaceBoundingBoxTree(srfs[1],!this._splitV,this._knotTolU,this._knotTolV)); + } + ,boundingBox: function() { + if(this._boundingBox == null) { + this._boundingBox = new verb_core_BoundingBox(); + var _g = 0; + var _g1 = this._surface.controlPoints; + while(_g < _g1.length) { + var row = _g1[_g]; + ++_g; + this._boundingBox.addRange(verb_eval_Eval.dehomogenize1d(row)); + } + } + return this._boundingBox; + } + ,'yield': function() { + return this._surface; + } + ,indivisible: function(tolerance) { + return verb_core_Vec.domain(this._surface.knotsV) < this._knotTolV && verb_core_Vec.domain(this._surface.knotsU) < this._knotTolU; + } + ,empty: function() { + return false; + } + ,__class__: verb_core_LazySurfaceBoundingBoxTree +}; +var verb_core_Mat = $hx_exports.core.Mat = function() { }; +$hxClasses["verb.core.Mat"] = verb_core_Mat; +verb_core_Mat.__name__ = ["verb","core","Mat"]; +verb_core_Mat.mul = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = b.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(verb_core_Vec.mul(a,b[i])); + } + return _g; +}; +verb_core_Mat.mult = function(x,y) { + var p; + var q; + var r; + var ret; + var foo; + var bar; + var woo; + var i0; + var k0; + var p0; + var r0; + p = x.length; + q = y.length; + r = y[0].length; + ret = []; + var i = p - 1; + var j = 0; + var k = 0; + while(i >= 0) { + foo = []; + bar = x[i]; + k = r - 1; + while(k >= 0) { + woo = bar[q - 1] * y[q - 1][k]; + j = q - 2; + while(j >= 1) { + i0 = j - 1; + woo += bar[j] * y[j][k] + bar[i0] * y[i0][k]; + j -= 2; + } + if(j == 0) woo += bar[0] * y[0][k]; + foo[k] = woo; + k--; + } + ret[i] = foo; + i--; + } + return ret; +}; +verb_core_Mat.add = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(verb_core_Vec.add(a[i],b[i])); + } + return _g; +}; +verb_core_Mat.div = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(verb_core_Vec.div(a[i],b)); + } + return _g; +}; +verb_core_Mat.sub = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(verb_core_Vec.sub(a[i],b[i])); + } + return _g; +}; +verb_core_Mat.dot = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(verb_core_Vec.dot(a[i],b)); + } + return _g; +}; +verb_core_Mat.identity = function(n) { + var zeros = verb_core_Vec.zeros2d(n,n); + var _g = 0; + while(_g < n) { + var i = _g++; + zeros[i][i] = 1.0; + } + return zeros; +}; +verb_core_Mat.transpose = function(a) { + if(a.length == 0) return []; + var _g = []; + var _g2 = 0; + var _g1 = a[0].length; + while(_g2 < _g1) { + var i = _g2++; + _g.push((function($this) { + var $r; + var _g3 = []; + { + var _g5 = 0; + var _g4 = a.length; + while(_g5 < _g4) { + var j = _g5++; + _g3.push(a[j][i]); + } + } + $r = _g3; + return $r; + }(this))); + } + return _g; +}; +verb_core_Mat.solve = function(A,b) { + return verb_core_Mat.LUsolve(verb_core_Mat.LU(A),b); +}; +verb_core_Mat.LUsolve = function(LUP,b) { + var i; + var j; + var LU = LUP.LU; + var n = LU.length; + var x = b.slice(); + var P = LUP.P; + var Pi; + var LUi; + var LUii; + var tmp; + i = n - 1; + while(i != -1) { + x[i] = b[i]; + --i; + } + i = 0; + while(i < n) { + Pi = P[i]; + if(P[i] != i) { + tmp = x[i]; + x[i] = x[Pi]; + x[Pi] = tmp; + } + LUi = LU[i]; + j = 0; + while(j < i) { + x[i] -= x[j] * LUi[j]; + ++j; + } + ++i; + } + i = n - 1; + while(i >= 0) { + LUi = LU[i]; + j = i + 1; + while(j < n) { + x[i] -= x[j] * LUi[j]; + ++j; + } + x[i] /= LUi[i]; + --i; + } + return x; +}; +verb_core_Mat.LU = function(A) { + var abs = Math.abs; + var i; + var j; + var k; + var absAjk; + var Akk; + var Ak; + var Pk; + var Ai; + var max; + var _g = []; + var _g2 = 0; + var _g1 = A.length; + while(_g2 < _g1) { + var i1 = _g2++; + _g.push(A[i1].slice()); + } + A = _g; + var n = A.length; + var n1 = n - 1; + var P = []; + k = 0; + while(k < n) { + Pk = k; + Ak = A[k]; + max = Math.abs(Ak[k]); + j = k + 1; + while(j < n) { + absAjk = Math.abs(A[j][k]); + if(max < absAjk) { + max = absAjk; + Pk = j; + } + ++j; + } + P[k] = Pk; + if(Pk != k) { + A[k] = A[Pk]; + A[Pk] = Ak; + Ak = A[k]; + } + Akk = Ak[k]; + i = k + 1; + while(i < n) { + A[i][k] /= Akk; + ++i; + } + i = k + 1; + while(i < n) { + Ai = A[i]; + j = k + 1; + while(j < n1) { + Ai[j] -= Ai[k] * Ak[j]; + ++j; + Ai[j] -= Ai[k] * Ak[j]; + ++j; + } + if(j == n1) Ai[j] -= Ai[k] * Ak[j]; + ++i; + } + ++k; + } + return new verb_core__$Mat_LUDecomp(A,P); +}; +var verb_core__$Mat_LUDecomp = function(lu,p) { + this.LU = lu; + this.P = p; +}; +$hxClasses["verb.core._Mat.LUDecomp"] = verb_core__$Mat_LUDecomp; +verb_core__$Mat_LUDecomp.__name__ = ["verb","core","_Mat","LUDecomp"]; +verb_core__$Mat_LUDecomp.prototype = { + __class__: verb_core__$Mat_LUDecomp +}; +var verb_core_Mesh = $hx_exports.core.Mesh = function() { }; +$hxClasses["verb.core.Mesh"] = verb_core_Mesh; +verb_core_Mesh.__name__ = ["verb","core","Mesh"]; +verb_core_Mesh.getTriangleNorm = function(points,tri) { + var v0 = points[tri[0]]; + var v1 = points[tri[1]]; + var v2 = points[tri[2]]; + var u = verb_core_Vec.sub(v1,v0); + var v = verb_core_Vec.sub(v2,v0); + var n = verb_core_Vec.cross(u,v); + return verb_core_Vec.mul(1 / verb_core_Vec.norm(n),n); +}; +verb_core_Mesh.makeMeshAabb = function(mesh,faceIndices) { + var bb = new verb_core_BoundingBox(); + var _g = 0; + while(_g < faceIndices.length) { + var x = faceIndices[_g]; + ++_g; + bb.add(mesh.points[mesh.faces[x][0]]); + bb.add(mesh.points[mesh.faces[x][1]]); + bb.add(mesh.points[mesh.faces[x][2]]); + } + return bb; +}; +verb_core_Mesh.sortTrianglesOnLongestAxis = function(bb,mesh,faceIndices) { + var longAxis = bb.getLongestAxis(); + var minCoordFaceMap = []; + var _g = 0; + while(_g < faceIndices.length) { + var faceIndex = faceIndices[_g]; + ++_g; + var tri_min = verb_core_Mesh.getMinCoordOnAxis(mesh.points,mesh.faces[faceIndex],longAxis); + minCoordFaceMap.push(new verb_core_Pair(tri_min,faceIndex)); + } + minCoordFaceMap.sort(function(a,b) { + var a0 = a.item0; + var b0 = b.item0; + if(a0 == b0) return 0; else if(a0 > b0) return 1; else return -1; + }); + var sortedFaceIndices = []; + var _g1 = 0; + var _g2 = minCoordFaceMap.length; + while(_g1 < _g2) { + var i = _g1++; + sortedFaceIndices.push(minCoordFaceMap[i].item1); + } + return sortedFaceIndices; +}; +verb_core_Mesh.getMinCoordOnAxis = function(points,tri,axis) { + var min = Infinity; + var _g = 0; + while(_g < 3) { + var i = _g++; + var coord = points[tri[i]][axis]; + if(coord < min) min = coord; + } + return min; +}; +verb_core_Mesh.getTriangleCentroid = function(points,tri) { + var centroid = [0.0,0.0,0.0]; + var _g = 0; + while(_g < 3) { + var i = _g++; + var _g1 = 0; + while(_g1 < 3) { + var j = _g1++; + centroid[j] += points[tri[i]][j]; + } + } + var _g2 = 0; + while(_g2 < 3) { + var i1 = _g2++; + centroid[i1] /= 3; + } + return centroid; +}; +verb_core_Mesh.triangleUVFromPoint = function(mesh,faceIndex,f) { + var tri = mesh.faces[faceIndex]; + var p1 = mesh.points[tri[0]]; + var p2 = mesh.points[tri[1]]; + var p3 = mesh.points[tri[2]]; + var uv1 = mesh.uvs[tri[0]]; + var uv2 = mesh.uvs[tri[1]]; + var uv3 = mesh.uvs[tri[2]]; + var f1 = verb_core_Vec.sub(p1,f); + var f2 = verb_core_Vec.sub(p2,f); + var f3 = verb_core_Vec.sub(p3,f); + var a = verb_core_Vec.norm(verb_core_Vec.cross(verb_core_Vec.sub(p1,p2),verb_core_Vec.sub(p1,p3))); + var a1 = verb_core_Vec.norm(verb_core_Vec.cross(f2,f3)) / a; + var a2 = verb_core_Vec.norm(verb_core_Vec.cross(f3,f1)) / a; + var a3 = verb_core_Vec.norm(verb_core_Vec.cross(f1,f2)) / a; + return verb_core_Vec.add(verb_core_Vec.mul(a1,uv1),verb_core_Vec.add(verb_core_Vec.mul(a2,uv2),verb_core_Vec.mul(a3,uv3))); +}; +var verb_core_MeshBoundingBoxTree = function(mesh,faceIndices) { + this._empty = false; + this._face = -1; + if(faceIndices == null) { + var _g = []; + var _g2 = 0; + var _g1 = mesh.faces.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(i); + } + faceIndices = _g; + } + this._boundingBox = verb_core_Mesh.makeMeshAabb(mesh,faceIndices); + if(faceIndices.length < 1) { + this._empty = true; + return; + } else if(faceIndices.length < 2) { + this._face = faceIndices[0]; + return; + } + var $as = verb_core_Mesh.sortTrianglesOnLongestAxis(this._boundingBox,mesh,faceIndices); + var l = verb_core_ArrayExtensions.left($as); + var r = verb_core_ArrayExtensions.right($as); + this._children = new verb_core_Pair(new verb_core_MeshBoundingBoxTree(mesh,l),new verb_core_MeshBoundingBoxTree(mesh,r)); +}; +$hxClasses["verb.core.MeshBoundingBoxTree"] = verb_core_MeshBoundingBoxTree; +verb_core_MeshBoundingBoxTree.__name__ = ["verb","core","MeshBoundingBoxTree"]; +verb_core_MeshBoundingBoxTree.__interfaces__ = [verb_eval_IBoundingBoxTree]; +verb_core_MeshBoundingBoxTree.prototype = { + split: function() { + return this._children; + } + ,boundingBox: function() { + return this._boundingBox; + } + ,'yield': function() { + return this._face; + } + ,indivisible: function(tolerance) { + return this._children == null; + } + ,empty: function() { + return this._empty; + } + ,__class__: verb_core_MeshBoundingBoxTree +}; +var verb_core_Minimizer = $hx_exports.core.Minimizer = function() { }; +$hxClasses["verb.core.Minimizer"] = verb_core_Minimizer; +verb_core_Minimizer.__name__ = ["verb","core","Minimizer"]; +verb_core_Minimizer.uncmin = function(f,x0,tol,gradient,maxit) { + if(tol == null) tol = 1e-8; + if(gradient == null) gradient = function(x) { + return verb_core_Minimizer.numericalGradient(f,x); + }; + if(maxit == null) maxit = 1000; + x0 = x0.slice(0); + var n = x0.length; + var f0 = f(x0); + var f1 = f0; + var df0; + if(isNaN(f0)) throw new js__$Boot_HaxeError("uncmin: f(x0) is a NaN!"); + tol = Math.max(tol,verb_core_Constants.EPSILON); + var step; + var g0; + var g1; + var H1 = verb_core_Mat.identity(n); + var it = 0; + var i; + var s = []; + var x1; + var y; + var Hy; + var Hs; + var ys; + var i0; + var t; + var nstep; + var t1; + var t2; + var msg = ""; + g0 = gradient(x0); + while(it < maxit) { + if(!verb_core_Vec.all(verb_core_Vec.finite(g0))) { + msg = "Gradient has Infinity or NaN"; + break; + } + step = verb_core_Vec.neg(verb_core_Mat.dot(H1,g0)); + if(!verb_core_Vec.all(verb_core_Vec.finite(step))) { + msg = "Search direction has Infinity or NaN"; + break; + } + nstep = verb_core_Vec.norm(step); + if(nstep < tol) { + msg = "Newton step smaller than tol"; + break; + } + t = 1.0; + df0 = verb_core_Vec.dot(g0,step); + x1 = x0; + while(it < maxit) { + if(t * nstep < tol) break; + s = verb_core_Vec.mul(t,step); + x1 = verb_core_Vec.add(x0,s); + f1 = f(x1); + if(f1 - f0 >= 0.1 * t * df0 || isNaN(f1)) { + t *= 0.5; + ++it; + continue; + } + break; + } + if(t * nstep < tol) { + msg = "Line search step size smaller than tol"; + break; + } + if(it == maxit) { + msg = "maxit reached during line search"; + break; + } + g1 = gradient(x1); + y = verb_core_Vec.sub(g1,g0); + ys = verb_core_Vec.dot(y,s); + Hy = verb_core_Mat.dot(H1,y); + H1 = verb_core_Mat.sub(verb_core_Mat.add(H1,verb_core_Mat.mul((ys + verb_core_Vec.dot(y,Hy)) / (ys * ys),verb_core_Minimizer.tensor(s,s))),verb_core_Mat.div(verb_core_Mat.add(verb_core_Minimizer.tensor(Hy,s),verb_core_Minimizer.tensor(s,Hy)),ys)); + x0 = x1; + f0 = f1; + g0 = g1; + ++it; + } + return new verb_core_MinimizationResult(x0,f0,g0,H1,it,msg); +}; +verb_core_Minimizer.numericalGradient = function(f,x) { + var n = x.length; + var f0 = f(x); + if(f0 == NaN) throw new js__$Boot_HaxeError("gradient: f(x) is a NaN!"); + var i; + var x0 = x.slice(0); + var f1; + var f2; + var J = []; + var errest; + var roundoff; + var eps = 1e-3; + var t0; + var t1; + var t2; + var it = 0; + var d1; + var d2; + var N; + var _g = 0; + while(_g < n) { + var i1 = _g++; + var h = Math.max(1e-6 * f0,1e-8); + while(true) { + ++it; + if(it > 20) throw new js__$Boot_HaxeError("Numerical gradient fails"); + x0[i1] = x[i1] + h; + f1 = f(x0); + x0[i1] = x[i1] - h; + f2 = f(x0); + x0[i1] = x[i1]; + if(isNaN(f1) || isNaN(f2)) { + h /= 16; + continue; + } + J[i1] = (f1 - f2) / (2 * h); + t0 = x[i1] - h; + t1 = x[i1]; + t2 = x[i1] + h; + d1 = (f1 - f0) / h; + d2 = (f0 - f2) / h; + N = verb_core_Vec.max([Math.abs(J[i1]),Math.abs(f0),Math.abs(f1),Math.abs(f2),Math.abs(t0),Math.abs(t1),Math.abs(t2),1e-8]); + errest = Math.min(verb_core_Vec.max([Math.abs(d1 - J[i1]),Math.abs(d2 - J[i1]),Math.abs(d1 - d2)]) / N,h / N); + if(errest > eps) h /= 16; else break; + } + } + return J; +}; +verb_core_Minimizer.tensor = function(x,y) { + var m = x.length; + var n = y.length; + var A = []; + var Ai; + var xi; + var i = m - 1; + while(i >= 0) { + Ai = []; + xi = x[i]; + var j = n - 1; + while(j >= 3) { + Ai[j] = xi * y[j]; + --j; + Ai[j] = xi * y[j]; + --j; + Ai[j] = xi * y[j]; + --j; + Ai[j] = xi * y[j]; + --j; + } + while(j >= 0) { + Ai[j] = xi * y[j]; + --j; + } + A[i] = Ai; + i--; + } + return A; +}; +var verb_core_MinimizationResult = function(solution,value,gradient,invHessian,iterations,message) { + this.solution = solution; + this.value = value; + this.gradient = gradient; + this.invHessian = invHessian; + this.iterations = iterations; + this.message = message; +}; +$hxClasses["verb.core.MinimizationResult"] = verb_core_MinimizationResult; +verb_core_MinimizationResult.__name__ = ["verb","core","MinimizationResult"]; +verb_core_MinimizationResult.prototype = { + __class__: verb_core_MinimizationResult +}; +var verb_core_ISerializable = function() { }; +$hxClasses["verb.core.ISerializable"] = verb_core_ISerializable; +verb_core_ISerializable.__name__ = ["verb","core","ISerializable"]; +verb_core_ISerializable.prototype = { + __class__: verb_core_ISerializable +}; +var verb_core_Deserializer = $hx_exports.core.Deserializer = function() { }; +$hxClasses["verb.core.Deserializer"] = verb_core_Deserializer; +verb_core_Deserializer.__name__ = ["verb","core","Deserializer"]; +verb_core_Deserializer.deserialize = function(s) { + var unserializer = new haxe_Unserializer(s); + var r = unserializer.unserialize(); + return r; +}; +var verb_core_Trig = $hx_exports.core.Trig = function() { }; +$hxClasses["verb.core.Trig"] = verb_core_Trig; +verb_core_Trig.__name__ = ["verb","core","Trig"]; +verb_core_Trig.isPointInPlane = function(pt,p,tol) { + return Math.abs(verb_core_Vec.dot(verb_core_Vec.sub(pt,p.origin),p.normal)) < tol; +}; +verb_core_Trig.distToSegment = function(a,b,c) { + var res = verb_core_Trig.segmentClosestPoint(b,a,c,0.0,1.0); + return verb_core_Vec.dist(b,res.pt); +}; +verb_core_Trig.rayClosestPoint = function(pt,o,r) { + var o2pt = verb_core_Vec.sub(pt,o); + var do2ptr = verb_core_Vec.dot(o2pt,r); + var proj = verb_core_Vec.add(o,verb_core_Vec.mul(do2ptr,r)); + return proj; +}; +verb_core_Trig.distToRay = function(pt,o,r) { + var d = verb_core_Trig.rayClosestPoint(pt,o,r); + var dif = verb_core_Vec.sub(d,pt); + return verb_core_Vec.norm(dif); +}; +verb_core_Trig.threePointsAreFlat = function(p1,p2,p3,tol) { + var p2mp1 = verb_core_Vec.sub(p2,p1); + var p3mp1 = verb_core_Vec.sub(p3,p1); + var norm = verb_core_Vec.cross(p2mp1,p3mp1); + var area = verb_core_Vec.dot(norm,norm); + return area < tol; +}; +verb_core_Trig.segmentClosestPoint = function(pt,segpt0,segpt1,u0,u1) { + var dif = verb_core_Vec.sub(segpt1,segpt0); + var l = verb_core_Vec.norm(dif); + if(l < verb_core_Constants.EPSILON) return { u : u0, pt : segpt0}; + var o = segpt0; + var r = verb_core_Vec.mul(1 / l,dif); + var o2pt = verb_core_Vec.sub(pt,o); + var do2ptr = verb_core_Vec.dot(o2pt,r); + if(do2ptr < 0) return { u : u0, pt : segpt0}; else if(do2ptr > l) return { u : u1, pt : segpt1}; + return { u : u0 + (u1 - u0) * do2ptr / l, pt : verb_core_Vec.add(o,verb_core_Vec.mul(do2ptr,r))}; +}; +var verb_core_Vec = $hx_exports.core.Vec = function() { }; +$hxClasses["verb.core.Vec"] = verb_core_Vec; +verb_core_Vec.__name__ = ["verb","core","Vec"]; +verb_core_Vec.angleBetween = function(a,b) { + return Math.acos(verb_core_Vec.dot(a,b) / (verb_core_Vec.norm(a) * verb_core_Vec.norm(b))); +}; +verb_core_Vec.positiveAngleBetween = function(a,b,n) { + var nab = verb_core_Vec.cross(a,b); + var al = verb_core_Vec.norm(a); + var bl = verb_core_Vec.norm(b); + var abl = al * bl; + var adb = verb_core_Vec.dot(a,b); + var sina = verb_core_Vec.norm(nab) / abl; + var cosa = adb / abl; + var w = Math.atan2(sina,cosa); + var s = verb_core_Vec.dot(n,nab); + if(Math.abs(s) < verb_core_Constants.EPSILON) return w; + if(s > 0) return w; else return -w; +}; +verb_core_Vec.signedAngleBetween = function(a,b,n) { + var nab = verb_core_Vec.cross(a,b); + var al = verb_core_Vec.norm(a); + var bl = verb_core_Vec.norm(b); + var abl = al * bl; + var adb = verb_core_Vec.dot(a,b); + var sina = verb_core_Vec.norm(nab) / abl; + var cosa = adb / abl; + var w = Math.atan2(sina,cosa); + var s = verb_core_Vec.dot(n,nab); + if(s > 0.0) return w; else return 2 * Math.PI - w; +}; +verb_core_Vec.angleBetweenNormalized2d = function(a,b) { + var perpDot = a[0] * b[1] - a[1] * b[0]; + return Math.atan2(perpDot,verb_core_Vec.dot(a,b)); +}; +verb_core_Vec.domain = function(a) { + return verb_core_ArrayExtensions.last(a) - verb_core_ArrayExtensions.first(a); +}; +verb_core_Vec.range = function(max) { + var l = []; + var f = 0.0; + var _g = 0; + while(_g < max) { + var i = _g++; + l.push(f); + f += 1.0; + } + return l; +}; +verb_core_Vec.span = function(min,max,step) { + if(step == null) return []; + if(step < verb_core_Constants.EPSILON) return []; + if(min > max && step > 0.0) return []; + if(max > min && step < 0.0) return []; + var l = []; + var cur = min; + while(cur <= max) { + l.push(cur); + cur += step; + } + return l; +}; +verb_core_Vec.neg = function(arr) { + return arr.map(function(x) { + return -x; + }); +}; +verb_core_Vec.min = function(arr) { + return Lambda.fold(arr,function(x,a) { + return Math.min(x,a); + },Infinity); +}; +verb_core_Vec.max = function(arr) { + return Lambda.fold(arr,function(x,a) { + return Math.max(x,a); + },-Infinity); +}; +verb_core_Vec.all = function(arr) { + return Lambda.fold(arr,function(x,a) { + return a && x; + },true); +}; +verb_core_Vec.finite = function(arr) { + return arr.map(function(x) { + return isFinite(x); + }); +}; +verb_core_Vec.onRay = function(origin,dir,u) { + return verb_core_Vec.add(origin,verb_core_Vec.mul(u,dir)); +}; +verb_core_Vec.lerp = function(i,u,v) { + return verb_core_Vec.add(verb_core_Vec.mul(i,u),verb_core_Vec.mul(1.0 - i,v)); +}; +verb_core_Vec.normalized = function(arr) { + return verb_core_Vec.div(arr,verb_core_Vec.norm(arr)); +}; +verb_core_Vec.cross = function(u,v) { + return [u[1] * v[2] - u[2] * v[1],u[2] * v[0] - u[0] * v[2],u[0] * v[1] - u[1] * v[0]]; +}; +verb_core_Vec.dist = function(a,b) { + return verb_core_Vec.norm(verb_core_Vec.sub(a,b)); +}; +verb_core_Vec.distSquared = function(a,b) { + return verb_core_Vec.normSquared(verb_core_Vec.sub(a,b)); +}; +verb_core_Vec.sum = function(a) { + return Lambda.fold(a,function(x,a1) { + return a1 + x; + },0); +}; +verb_core_Vec.addAll = function(a) { + var i = $iterator(a)(); + if(!i.hasNext()) return null; + var f = i.next().length; + return Lambda.fold(a,function(x,a1) { + return verb_core_Vec.add(a1,x); + },verb_core_Vec.rep(f,0.0)); +}; +verb_core_Vec.addAllMutate = function(a) { + var f = a[0]; + var _g1 = 1; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + verb_core_Vec.addMutate(f,a[i]); + } +}; +verb_core_Vec.addMulMutate = function(a,s,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] + s * b[i]; + } +}; +verb_core_Vec.subMulMutate = function(a,s,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] - s * b[i]; + } +}; +verb_core_Vec.addMutate = function(a,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] + b[i]; + } +}; +verb_core_Vec.subMutate = function(a,b) { + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = a[i] - b[i]; + } +}; +verb_core_Vec.mulMutate = function(a,b) { + var _g1 = 0; + var _g = b.length; + while(_g1 < _g) { + var i = _g1++; + b[i] = b[i] * a; + } +}; +verb_core_Vec.norm = function(a) { + var norm2 = verb_core_Vec.normSquared(a); + if(norm2 != 0.0) return Math.sqrt(norm2); else return norm2; +}; +verb_core_Vec.normSquared = function(a) { + return Lambda.fold(a,function(x,a1) { + return a1 + x * x; + },0); +}; +verb_core_Vec.rep = function(num,ele) { + var _g = []; + var _g1 = 0; + while(_g1 < num) { + var i = _g1++; + _g.push(ele); + } + return _g; +}; +verb_core_Vec.zeros1d = function(rows) { + var _g = []; + var _g1 = 0; + while(_g1 < rows) { + var i = _g1++; + _g.push(0.0); + } + return _g; +}; +verb_core_Vec.zeros2d = function(rows,cols) { + var _g = []; + var _g1 = 0; + while(_g1 < rows) { + var i = _g1++; + _g.push(verb_core_Vec.zeros1d(cols)); + } + return _g; +}; +verb_core_Vec.zeros3d = function(rows,cols,depth) { + var _g = []; + var _g1 = 0; + while(_g1 < rows) { + var i = _g1++; + _g.push(verb_core_Vec.zeros2d(cols,depth)); + } + return _g; +}; +verb_core_Vec.dot = function(a,b) { + var sum = 0; + var _g1 = 0; + var _g = a.length; + while(_g1 < _g) { + var i = _g1++; + sum += a[i] * b[i]; + } + return sum; +}; +verb_core_Vec.add = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(a[i] + b[i]); + } + return _g; +}; +verb_core_Vec.mul = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = b.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(a * b[i]); + } + return _g; +}; +verb_core_Vec.div = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(a[i] / b); + } + return _g; +}; +verb_core_Vec.sub = function(a,b) { + var _g = []; + var _g2 = 0; + var _g1 = a.length; + while(_g2 < _g1) { + var i = _g2++; + _g.push(a[i] - b[i]); + } + return _g; +}; +verb_core_Vec.isZero = function(vec) { + var _g1 = 0; + var _g = vec.length; + while(_g1 < _g) { + var i = _g1++; + if(Math.abs(vec[i]) > verb_core_Constants.TOLERANCE) return false; + } + return true; +}; +verb_core_Vec.sortedSetUnion = function(a,b) { + var merged = []; + var ai = 0; + var bi = 0; + while(ai < a.length || bi < b.length) { + if(ai >= a.length) { + merged.push(b[bi]); + bi++; + continue; + } else if(bi >= b.length) { + merged.push(a[ai]); + ai++; + continue; + } + var diff = a[ai] - b[bi]; + if(Math.abs(diff) < verb_core_Constants.EPSILON) { + merged.push(a[ai]); + ai++; + bi++; + continue; + } + if(diff > 0.0) { + merged.push(b[bi]); + bi++; + continue; + } + merged.push(a[ai]); + ai++; + } + return merged; +}; +verb_core_Vec.sortedSetSub = function(a,b) { + var result = []; + var ai = 0; + var bi = 0; + while(ai < a.length) { + if(bi >= b.length) { + result.push(a[ai]); + ai++; + continue; + } + if(Math.abs(a[ai] - b[bi]) < verb_core_Constants.EPSILON) { + ai++; + bi++; + continue; + } + result.push(a[ai]); + ai++; + } + return result; +}; +var verb_eval_Analyze = $hx_exports.eval.Analyze = function() { }; +$hxClasses["verb.eval.Analyze"] = verb_eval_Analyze; +verb_eval_Analyze.__name__ = ["verb","eval","Analyze"]; +verb_eval_Analyze.knotMultiplicities = function(knots) { + var mults = [new verb_eval_KnotMultiplicity(knots[0],0)]; + var curr = mults[0]; + var _g = 0; + while(_g < knots.length) { + var knot = knots[_g]; + ++_g; + if(Math.abs(knot - curr.knot) > verb_core_Constants.EPSILON) { + curr = new verb_eval_KnotMultiplicity(knot,0); + mults.push(curr); + } + curr.inc(); + } + return mults; +}; +verb_eval_Analyze.isRationalSurfaceClosed = function(surface,uDir) { + if(uDir == null) uDir = true; + var cpts; + if(uDir) cpts = surface.controlPoints; else cpts = verb_core_Mat.transpose(surface.controlPoints); + var _g1 = 0; + var _g = cpts[0].length; + while(_g1 < _g) { + var i = _g1++; + var test = verb_core_Vec.dist(verb_core_ArrayExtensions.first(cpts)[i],verb_core_ArrayExtensions.last(cpts)[i]) < verb_core_Constants.EPSILON; + if(!test) return false; + } + return true; +}; +verb_eval_Analyze.rationalSurfaceClosestPoint = function(surface,p) { + var uv = verb_eval_Analyze.rationalSurfaceClosestParam(surface,p); + return verb_eval_Eval.rationalSurfacePoint(surface,uv[0],uv[1]); +}; +verb_eval_Analyze.rationalSurfaceClosestParam = function(surface,p) { + var maxits = 5; + var i = 0; + var e; + var eps1 = 0.0001; + var eps2 = 0.0005; + var dif; + var minu = surface.knotsU[0]; + var maxu = verb_core_ArrayExtensions.last(surface.knotsU); + var minv = surface.knotsV[0]; + var maxv = verb_core_ArrayExtensions.last(surface.knotsV); + var closedu = verb_eval_Analyze.isRationalSurfaceClosed(surface); + var closedv = verb_eval_Analyze.isRationalSurfaceClosed(surface,false); + var cuv; + var tess = verb_eval_Tess.rationalSurfaceAdaptive(surface,new verb_eval_AdaptiveRefinementOptions()); + var dmin = Infinity; + var _g1 = 0; + var _g = tess.points.length; + while(_g1 < _g) { + var i1 = _g1++; + var x = tess.points[i1]; + var d1 = verb_core_Vec.normSquared(verb_core_Vec.sub(p,x)); + if(d1 < dmin) { + dmin = d1; + cuv = tess.uvs[i1]; + } + } + var f = function(uv) { + return verb_eval_Eval.rationalSurfaceDerivatives(surface,uv[0],uv[1],2); + }; + var n = function(uv1,e1,r) { + var Su = e1[1][0]; + var Sv = e1[0][1]; + var Suu = e1[2][0]; + var Svv = e1[0][2]; + var Suv = e1[1][1]; + var Svu = e1[1][1]; + var f1 = verb_core_Vec.dot(Su,r); + var g = verb_core_Vec.dot(Sv,r); + var k = [-f1,-g]; + var J00 = verb_core_Vec.dot(Su,Su) + verb_core_Vec.dot(Suu,r); + var J01 = verb_core_Vec.dot(Su,Sv) + verb_core_Vec.dot(Suv,r); + var J10 = verb_core_Vec.dot(Su,Sv) + verb_core_Vec.dot(Svu,r); + var J11 = verb_core_Vec.dot(Sv,Sv) + verb_core_Vec.dot(Svv,r); + var J = [[J00,J01],[J10,J11]]; + var d = verb_core_Mat.solve(J,k); + return verb_core_Vec.add(d,uv1); + }; + while(i < maxits) { + e = f(cuv); + dif = verb_core_Vec.sub(e[0][0],p); + var c1v = verb_core_Vec.norm(dif); + var c2an = verb_core_Vec.dot(e[1][0],dif); + var c2ad = verb_core_Vec.norm(e[1][0]) * c1v; + var c2bn = verb_core_Vec.dot(e[0][1],dif); + var c2bd = verb_core_Vec.norm(e[0][1]) * c1v; + var c2av = c2an / c2ad; + var c2bv = c2bn / c2bd; + var c1 = c1v < eps1; + var c2a = c2av < eps2; + var c2b = c2bv < eps2; + if(c1 && c2a && c2b) return cuv; + var ct = n(cuv,e,dif); + if(ct[0] < minu) if(closedu) ct = [maxu - (ct[0] - minu),ct[1]]; else ct = [minu + verb_core_Constants.EPSILON,ct[1]]; else if(ct[0] > maxu) if(closedu) ct = [minu + (ct[0] - maxu),ct[1]]; else ct = [maxu - verb_core_Constants.EPSILON,ct[1]]; + if(ct[1] < minv) if(closedv) ct = [ct[0],maxv - (ct[1] - minv)]; else ct = [ct[0],minv + verb_core_Constants.EPSILON]; else if(ct[1] > maxv) if(closedv) ct = [ct[0],minv + (ct[0] - maxv)]; else ct = [ct[0],maxv - verb_core_Constants.EPSILON]; + var c3v0 = verb_core_Vec.norm(verb_core_Vec.mul(ct[0] - cuv[0],e[1][0])); + var c3v1 = verb_core_Vec.norm(verb_core_Vec.mul(ct[1] - cuv[1],e[0][1])); + if(c3v0 + c3v1 < eps1) return cuv; + cuv = ct; + i++; + } + return cuv; +}; +verb_eval_Analyze.rationalCurveClosestPoint = function(curve,p) { + return verb_eval_Eval.rationalCurvePoint(curve,verb_eval_Analyze.rationalCurveClosestParam(curve,p)); +}; +verb_eval_Analyze.rationalCurveClosestParam = function(curve,p) { + var min = Infinity; + var u = 0.0; + var pts = verb_eval_Tess.rationalCurveRegularSample(curve,curve.controlPoints.length * curve.degree,true); + var _g1 = 0; + var _g = pts.length - 1; + while(_g1 < _g) { + var i1 = _g1++; + var u0 = pts[i1].pop(); + var u11 = pts[i1 + 1].pop(); + var p0 = pts[i1]; + var p01 = pts[i1]; + var p1 = pts[i1 + 1]; + var proj = verb_core_Trig.segmentClosestPoint(p,p01,p1,u0,u11); + var d1 = verb_core_Vec.norm(verb_core_Vec.sub(p,proj.pt)); + if(d1 < min) { + min = d1; + u = proj.u; + } + } + var maxits = 5; + var i = 0; + var e; + var eps1 = 0.0001; + var eps2 = 0.0005; + var dif; + var minu = curve.knots[0]; + var maxu = verb_core_ArrayExtensions.last(curve.knots); + var closed = verb_core_Vec.normSquared(verb_core_Vec.sub(curve.controlPoints[0],verb_core_ArrayExtensions.last(curve.controlPoints))) < verb_core_Constants.EPSILON; + var cu = u; + var f = function(u1) { + return verb_eval_Eval.rationalCurveDerivatives(curve,u1,2); + }; + var n = function(u2,e1,d) { + var f1 = verb_core_Vec.dot(e1[1],d); + var s0 = verb_core_Vec.dot(e1[2],d); + var s1 = verb_core_Vec.dot(e1[1],e1[1]); + var df = s0 + s1; + return u2 - f1 / df; + }; + while(i < maxits) { + e = f(cu); + dif = verb_core_Vec.sub(e[0],p); + var c1v = verb_core_Vec.norm(dif); + var c2n = verb_core_Vec.dot(e[1],dif); + var c2d = verb_core_Vec.norm(e[1]) * c1v; + var c2v = c2n / c2d; + var c1 = c1v < eps1; + var c2 = Math.abs(c2v) < eps2; + if(c1 && c2) return cu; + var ct = n(cu,e,dif); + if(ct < minu) if(closed) ct = maxu - (ct - minu); else ct = minu; else if(ct > maxu) if(closed) ct = minu + (ct - maxu); else ct = maxu; + var c3v = verb_core_Vec.norm(verb_core_Vec.mul(ct - cu,e[1])); + if(c3v < eps1) return cu; + cu = ct; + i++; + } + return cu; +}; +verb_eval_Analyze.rationalCurveParamAtArcLength = function(curve,len,tol,beziers,bezierLengths) { + if(tol == null) tol = 1e-3; + if(len < verb_core_Constants.EPSILON) return curve.knots[0]; + var crvs; + if(beziers != null) crvs = beziers; else crvs = verb_eval_Modify.decomposeCurveIntoBeziers(curve); + var i = 0; + var cc = crvs[i]; + var cl = -verb_core_Constants.EPSILON; + var bezier_lengths; + if(bezierLengths != null) bezier_lengths = bezierLengths; else bezier_lengths = []; + while(cl < len && i < crvs.length) { + if(i < bezier_lengths.length) bezier_lengths[i] = bezier_lengths[i]; else bezier_lengths[i] = verb_eval_Analyze.rationalBezierCurveArcLength(curve); + cl += bezier_lengths[i]; + if(len < cl + verb_core_Constants.EPSILON) return verb_eval_Analyze.rationalBezierCurveParamAtArcLength(curve,len,tol,bezier_lengths[i]); + i++; + } + return -1; +}; +verb_eval_Analyze.rationalBezierCurveParamAtArcLength = function(curve,len,tol,totalLength) { + if(len < 0) return curve.knots[0]; + var totalLen; + if(totalLength != null) totalLen = totalLength; else totalLen = verb_eval_Analyze.rationalBezierCurveArcLength(curve); + if(len > totalLen) return verb_core_ArrayExtensions.last(curve.knots); + var start_p = curve.knots[0]; + var start_l = 0.0; + var end_p = verb_core_ArrayExtensions.last(curve.knots); + var end_l = totalLen; + var mid_p = 0.0; + var mid_l = 0.0; + var tol1; + if(tol != null) tol1 = tol; else tol1 = verb_core_Constants.TOLERANCE * 2; + while(end_l - start_l > tol1) { + mid_p = (start_p + end_p) / 2; + mid_l = verb_eval_Analyze.rationalBezierCurveArcLength(curve,mid_p); + if(mid_l > len) { + end_p = mid_p; + end_l = mid_l; + } else { + start_p = mid_p; + start_l = mid_l; + } + } + return (start_p + end_p) / 2; +}; +verb_eval_Analyze.rationalCurveArcLength = function(curve,u,gaussDegIncrease) { + if(gaussDegIncrease == null) gaussDegIncrease = 16; + if(u == null) u = verb_core_ArrayExtensions.last(curve.knots); else u = u; + var crvs = verb_eval_Modify.decomposeCurveIntoBeziers(curve); + var i = 0; + var cc = crvs[0]; + var sum = 0.0; + while(i < crvs.length && cc.knots[0] + verb_core_Constants.EPSILON < u) { + var param = Math.min(verb_core_ArrayExtensions.last(cc.knots),u); + sum += verb_eval_Analyze.rationalBezierCurveArcLength(cc,param,gaussDegIncrease); + cc = crvs[++i]; + } + return sum; +}; +verb_eval_Analyze.rationalBezierCurveArcLength = function(curve,u,gaussDegIncrease) { + if(gaussDegIncrease == null) gaussDegIncrease = 16; + var u1; + if(u == null) u1 = verb_core_ArrayExtensions.last(curve.knots); else u1 = u; + var z = (u1 - curve.knots[0]) / 2; + var sum = 0.0; + var gaussDeg = curve.degree + gaussDegIncrease; + var cu; + var tan; + var _g = 0; + while(_g < gaussDeg) { + var i = _g++; + cu = z * verb_eval_Analyze.Tvalues[gaussDeg][i] + z + curve.knots[0]; + tan = verb_eval_Eval.rationalCurveDerivatives(curve,cu,1); + sum += verb_eval_Analyze.Cvalues[gaussDeg][i] * verb_core_Vec.norm(tan[1]); + } + return z * sum; +}; +var verb_eval_KnotMultiplicity = $hx_exports.eval.KnotMultiplicity = function(knot,mult) { + this.knot = knot; + this.mult = mult; +}; +$hxClasses["verb.eval.KnotMultiplicity"] = verb_eval_KnotMultiplicity; +verb_eval_KnotMultiplicity.__name__ = ["verb","eval","KnotMultiplicity"]; +verb_eval_KnotMultiplicity.prototype = { + inc: function() { + this.mult++; + } + ,__class__: verb_eval_KnotMultiplicity +}; +var verb_eval_Check = $hx_exports.eval.Check = function() { }; +$hxClasses["verb.eval.Check"] = verb_eval_Check; +verb_eval_Check.__name__ = ["verb","eval","Check"]; +verb_eval_Check.isValidKnotVector = function(vec,degree) { + if(vec.length == 0) return false; + if(vec.length < (degree + 1) * 2) return false; + var rep = verb_core_ArrayExtensions.first(vec); + var _g1 = 0; + var _g = degree + 1; + while(_g1 < _g) { + var i = _g1++; + if(Math.abs(vec[i] - rep) > verb_core_Constants.EPSILON) return false; + } + rep = verb_core_ArrayExtensions.last(vec); + var _g11 = vec.length - degree - 1; + var _g2 = vec.length; + while(_g11 < _g2) { + var i1 = _g11++; + if(Math.abs(vec[i1] - rep) > verb_core_Constants.EPSILON) return false; + } + return verb_eval_Check.isNonDecreasing(vec); +}; +verb_eval_Check.isNonDecreasing = function(vec) { + var rep = verb_core_ArrayExtensions.first(vec); + var _g1 = 0; + var _g = vec.length; + while(_g1 < _g) { + var i = _g1++; + if(vec[i] < rep - verb_core_Constants.EPSILON) return false; + rep = vec[i]; + } + return true; +}; +verb_eval_Check.isValidNurbsCurveData = function(data) { + if(data.controlPoints == null) throw new js__$Boot_HaxeError("Control points array cannot be null!"); + if(data.degree == null) throw new js__$Boot_HaxeError("Degree cannot be null!"); + if(data.degree < 1) throw new js__$Boot_HaxeError("Degree must be greater than 1!"); + if(data.knots == null) throw new js__$Boot_HaxeError("Knots cannot be null!"); + if(data.knots.length != data.controlPoints.length + data.degree + 1) throw new js__$Boot_HaxeError("controlPoints.length + degree + 1 must equal knots.length!"); + if(!verb_eval_Check.isValidKnotVector(data.knots,data.degree)) throw new js__$Boot_HaxeError("Invalid knot vector format! Should begin with degree + 1 repeats and end with degree + 1 repeats!"); + return data; +}; +verb_eval_Check.isValidNurbsSurfaceData = function(data) { + if(data.controlPoints == null) throw new js__$Boot_HaxeError("Control points array cannot be null!"); + if(data.degreeU == null) throw new js__$Boot_HaxeError("DegreeU cannot be null!"); + if(data.degreeV == null) throw new js__$Boot_HaxeError("DegreeV cannot be null!"); + if(data.degreeU < 1) throw new js__$Boot_HaxeError("DegreeU must be greater than 1!"); + if(data.degreeV < 1) throw new js__$Boot_HaxeError("DegreeV must be greater than 1!"); + if(data.knotsU == null) throw new js__$Boot_HaxeError("KnotsU cannot be null!"); + if(data.knotsV == null) throw new js__$Boot_HaxeError("KnotsV cannot be null!"); + if(data.knotsU.length != data.controlPoints.length + data.degreeU + 1) throw new js__$Boot_HaxeError("controlPointsU.length + degreeU + 1 must equal knotsU.length!"); + if(data.knotsV.length != data.controlPoints[0].length + data.degreeV + 1) throw new js__$Boot_HaxeError("controlPointsV.length + degreeV + 1 must equal knotsV.length!"); + if(!verb_eval_Check.isValidKnotVector(data.knotsU,data.degreeU) || !verb_eval_Check.isValidKnotVector(data.knotsV,data.degreeV)) throw new js__$Boot_HaxeError("Invalid knot vector format! Should begin with degree + 1 repeats and end with degree + 1 repeats!"); + return data; +}; +var verb_eval_Divide = $hx_exports.eval.Divide = function() { }; +$hxClasses["verb.eval.Divide"] = verb_eval_Divide; +verb_eval_Divide.__name__ = ["verb","eval","Divide"]; +verb_eval_Divide.surfaceSplit = function(surface,u,useV) { + if(useV == null) useV = false; + var knots; + var degree; + var controlPoints; + if(!useV) { + controlPoints = verb_core_Mat.transpose(surface.controlPoints); + knots = surface.knotsU; + degree = surface.degreeU; + } else { + controlPoints = surface.controlPoints; + knots = surface.knotsV; + degree = surface.degreeV; + } + var knots_to_insert; + var _g = []; + var _g2 = 0; + var _g1 = degree + 1; + while(_g2 < _g1) { + var i = _g2++; + _g.push(u); + } + knots_to_insert = _g; + var newpts0 = []; + var newpts1 = []; + var s = verb_eval_Eval.knotSpan(degree,u,knots); + var res = null; + var _g11 = 0; + while(_g11 < controlPoints.length) { + var cps = controlPoints[_g11]; + ++_g11; + res = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,cps),knots_to_insert); + newpts0.push(res.controlPoints.slice(0,s + 1)); + newpts1.push(res.controlPoints.slice(s + 1)); + } + var knots0 = res.knots.slice(0,s + degree + 2); + var knots1 = res.knots.slice(s + 1); + if(!useV) { + newpts0 = verb_core_Mat.transpose(newpts0); + newpts1 = verb_core_Mat.transpose(newpts1); + return [new verb_core_NurbsSurfaceData(degree,surface.degreeV,knots0,surface.knotsV.slice(),newpts0),new verb_core_NurbsSurfaceData(degree,surface.degreeV,knots1,surface.knotsV.slice(),newpts1)]; + } + return [new verb_core_NurbsSurfaceData(surface.degreeU,degree,surface.knotsU.slice(),knots0,newpts0),new verb_core_NurbsSurfaceData(surface.degreeU,degree,surface.knotsU.slice(),knots1,newpts1)]; +}; +verb_eval_Divide.curveSplit = function(curve,u) { + var degree = curve.degree; + var controlPoints = curve.controlPoints; + var knots = curve.knots; + var knots_to_insert; + var _g = []; + var _g2 = 0; + var _g1 = degree + 1; + while(_g2 < _g1) { + var i = _g2++; + _g.push(u); + } + knots_to_insert = _g; + var res = verb_eval_Modify.curveKnotRefine(curve,knots_to_insert); + var s = verb_eval_Eval.knotSpan(degree,u,knots); + var knots0 = res.knots.slice(0,s + degree + 2); + var knots1 = res.knots.slice(s + 1); + var cpts0 = res.controlPoints.slice(0,s + 1); + var cpts1 = res.controlPoints.slice(s + 1); + return [new verb_core_NurbsCurveData(degree,knots0,cpts0),new verb_core_NurbsCurveData(degree,knots1,cpts1)]; +}; +verb_eval_Divide.rationalCurveByEqualArcLength = function(curve,num) { + var tlen = verb_eval_Analyze.rationalCurveArcLength(curve); + var inc = tlen / num; + return verb_eval_Divide.rationalCurveByArcLength(curve,inc); +}; +verb_eval_Divide.rationalCurveByArcLength = function(curve,l) { + var crvs = verb_eval_Modify.decomposeCurveIntoBeziers(curve); + var crvlens = crvs.map(function(x) { + return verb_eval_Analyze.rationalBezierCurveArcLength(x); + }); + var totlen = verb_core_Vec.sum(crvlens); + var pts = [new verb_eval_CurveLengthSample(curve.knots[0],0.0)]; + if(l > totlen) return pts; + var inc = l; + var i = 0; + var lc = inc; + var runsum = 0.0; + var runsum1 = 0.0; + var u; + while(i < crvs.length) { + runsum += crvlens[i]; + while(lc < runsum + verb_core_Constants.EPSILON) { + u = verb_eval_Analyze.rationalBezierCurveParamAtArcLength(crvs[i],lc - runsum1,verb_core_Constants.TOLERANCE,crvlens[i]); + pts.push(new verb_eval_CurveLengthSample(u,lc)); + lc += inc; + } + runsum1 += crvlens[i]; + i++; + } + return pts; +}; +var verb_eval_CurveLengthSample = $hx_exports.eval.CurveLengthSample = function(u,len) { + this.u = u; + this.len = len; +}; +$hxClasses["verb.eval.CurveLengthSample"] = verb_eval_CurveLengthSample; +verb_eval_CurveLengthSample.__name__ = ["verb","eval","CurveLengthSample"]; +verb_eval_CurveLengthSample.prototype = { + __class__: verb_eval_CurveLengthSample +}; +var verb_eval_Eval = $hx_exports.eval.Eval = function() { }; +$hxClasses["verb.eval.Eval"] = verb_eval_Eval; +verb_eval_Eval.__name__ = ["verb","eval","Eval"]; +verb_eval_Eval.rationalCurveTangent = function(curve,u) { + var derivs = verb_eval_Eval.rationalCurveDerivatives(curve,u,1); + return derivs[1]; +}; +verb_eval_Eval.rationalSurfaceNormal = function(surface,u,v) { + var derivs = verb_eval_Eval.rationalSurfaceDerivatives(surface,u,v,1); + return verb_core_Vec.cross(derivs[1][0],derivs[0][1]); +}; +verb_eval_Eval.rationalSurfaceDerivatives = function(surface,u,v,numDerivs) { + if(numDerivs == null) numDerivs = 1; + var ders = verb_eval_Eval.surfaceDerivatives(surface,u,v,numDerivs); + var Aders = verb_eval_Eval.rational2d(ders); + var wders = verb_eval_Eval.weight2d(ders); + var SKL = []; + var dim = Aders[0][0].length; + var _g1 = 0; + var _g = numDerivs + 1; + while(_g1 < _g) { + var k = _g1++; + SKL.push([]); + var _g3 = 0; + var _g2 = numDerivs - k + 1; + while(_g3 < _g2) { + var l = _g3++; + var v1 = Aders[k][l]; + var _g5 = 1; + var _g4 = l + 1; + while(_g5 < _g4) { + var j = _g5++; + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(l,j) * wders[0][j],SKL[k][l - j]); + } + var _g51 = 1; + var _g41 = k + 1; + while(_g51 < _g41) { + var i = _g51++; + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(k,i) * wders[i][0],SKL[k - i][l]); + var v2 = verb_core_Vec.zeros1d(dim); + var _g7 = 1; + var _g6 = l + 1; + while(_g7 < _g6) { + var j1 = _g7++; + verb_core_Vec.addMulMutate(v2,verb_core_Binomial.get(l,j1) * wders[i][j1],SKL[k - i][l - j1]); + } + verb_core_Vec.subMulMutate(v1,verb_core_Binomial.get(k,i),v2); + } + verb_core_Vec.mulMutate(1 / wders[0][0],v1); + SKL[k].push(v1); + } + } + return SKL; +}; +verb_eval_Eval.rationalSurfacePoint = function(surface,u,v) { + return verb_eval_Eval.dehomogenize(verb_eval_Eval.surfacePoint(surface,u,v)); +}; +verb_eval_Eval.rationalCurveDerivatives = function(curve,u,numDerivs) { + if(numDerivs == null) numDerivs = 1; + var ders = verb_eval_Eval.curveDerivatives(curve,u,numDerivs); + var Aders = verb_eval_Eval.rational1d(ders); + var wders = verb_eval_Eval.weight1d(ders); + var k = 0; + var i = 0; + var CK = []; + var _g1 = 0; + var _g = numDerivs + 1; + while(_g1 < _g) { + var k1 = _g1++; + var v = Aders[k1]; + var _g3 = 1; + var _g2 = k1 + 1; + while(_g3 < _g2) { + var i1 = _g3++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k1,i1) * wders[i1],CK[k1 - i1]); + } + verb_core_Vec.mulMutate(1 / wders[0],v); + CK.push(v); + } + return CK; +}; +verb_eval_Eval.rationalCurvePoint = function(curve,u) { + return verb_eval_Eval.dehomogenize(verb_eval_Eval.curvePoint(curve,u)); +}; +verb_eval_Eval.surfaceDerivatives = function(surface,u,v,numDerivs) { + var n = surface.knotsU.length - surface.degreeU - 2; + var m = surface.knotsV.length - surface.degreeV - 2; + return verb_eval_Eval.surfaceDerivativesGivenNM(n,m,surface,u,v,numDerivs); +}; +verb_eval_Eval.surfaceDerivativesGivenNM = function(n,m,surface,u,v,numDerivs) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + if(!verb_eval_Eval.areValidRelations(degreeU,controlPoints.length,knotsU.length) || !verb_eval_Eval.areValidRelations(degreeV,controlPoints[0].length,knotsV.length)) throw new js__$Boot_HaxeError("Invalid relations between control points, knot vector, and n"); + var dim = controlPoints[0][0].length; + var du; + if(numDerivs < degreeU) du = numDerivs; else du = degreeU; + var dv; + if(numDerivs < degreeV) dv = numDerivs; else dv = degreeV; + var SKL = verb_core_Vec.zeros3d(du + 1,dv + 1,dim); + var knotSpan_index_u = verb_eval_Eval.knotSpanGivenN(n,degreeU,u,knotsU); + var knotSpan_index_v = verb_eval_Eval.knotSpanGivenN(m,degreeV,v,knotsV); + var uders = verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index_u,u,degreeU,n,knotsU); + var vders = verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index_v,v,degreeV,m,knotsV); + var temp = verb_core_Vec.zeros2d(degreeV + 1,dim); + var dd = 0; + var _g1 = 0; + var _g = du + 1; + while(_g1 < _g) { + var k = _g1++; + var _g3 = 0; + var _g2 = degreeV + 1; + while(_g3 < _g2) { + var s = _g3++; + temp[s] = verb_core_Vec.zeros1d(dim); + var _g5 = 0; + var _g4 = degreeU + 1; + while(_g5 < _g4) { + var r = _g5++; + verb_core_Vec.addMulMutate(temp[s],uders[k][r],controlPoints[knotSpan_index_u - degreeU + r][knotSpan_index_v - degreeV + s]); + } + } + var nk = numDerivs - k; + if(nk < dv) dd = nk; else dd = dv; + var _g31 = 0; + var _g21 = dd + 1; + while(_g31 < _g21) { + var l = _g31++; + SKL[k][l] = verb_core_Vec.zeros1d(dim); + var _g51 = 0; + var _g41 = degreeV + 1; + while(_g51 < _g41) { + var s1 = _g51++; + verb_core_Vec.addMulMutate(SKL[k][l],vders[l][s1],temp[s1]); + } + } + } + return SKL; +}; +verb_eval_Eval.surfacePoint = function(surface,u,v) { + var n = surface.knotsU.length - surface.degreeU - 2; + var m = surface.knotsV.length - surface.degreeV - 2; + return verb_eval_Eval.surfacePointGivenNM(n,m,surface,u,v); +}; +verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + if(!verb_eval_Eval.areValidRelations(degreeU,controlPoints.length,knotsU.length) || !verb_eval_Eval.areValidRelations(degreeV,controlPoints[0].length,knotsV.length)) throw new js__$Boot_HaxeError("Invalid relations between control points, knot vector, and n"); + var dim = controlPoints[0][0].length; + var knotSpan_index_u = verb_eval_Eval.knotSpanGivenN(n,degreeU,u,knotsU); + var knotSpan_index_v = verb_eval_Eval.knotSpanGivenN(m,degreeV,v,knotsV); + var u_basis_vals = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index_u,u,degreeU,knotsU); + var v_basis_vals = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index_v,v,degreeV,knotsV); + var uind = knotSpan_index_u - degreeU; + var vind = knotSpan_index_v; + var position = verb_core_Vec.zeros1d(dim); + var temp = verb_core_Vec.zeros1d(dim); + var _g1 = 0; + var _g = degreeV + 1; + while(_g1 < _g) { + var l = _g1++; + temp = verb_core_Vec.zeros1d(dim); + vind = knotSpan_index_v - degreeV + l; + var _g3 = 0; + var _g2 = degreeU + 1; + while(_g3 < _g2) { + var k = _g3++; + verb_core_Vec.addMulMutate(temp,u_basis_vals[k],controlPoints[uind + k][vind]); + } + verb_core_Vec.addMulMutate(position,v_basis_vals[l],temp); + } + return position; +}; +verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { + var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); + var allratders = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var numDerivs1 = numDerivs + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var rowders = []; + allratders.push(rowders); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + var ders = allders[i][j]; + var Aders = verb_eval_Eval.rational2d(ders); + var wders = verb_eval_Eval.weight2d(ders); + var SKL = []; + var dim = Aders[0][0].length; + var _g2 = 0; + while(_g2 < numDerivs1) { + var k = _g2++; + SKL.push([]); + var _g4 = 0; + var _g3 = numDerivs1 - k; + while(_g4 < _g3) { + var l = _g4++; + var v = Aders[k][l]; + var _g6 = 1; + var _g5 = l + 1; + while(_g6 < _g5) { + var j1 = _g6++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(l,j1) * wders[0][j1],SKL[k][l - j1]); + } + var _g61 = 1; + var _g51 = k + 1; + while(_g61 < _g51) { + var i1 = _g61++; + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1) * wders[i1][0],SKL[k - i1][l]); + var v2 = verb_core_Vec.zeros1d(dim); + var _g8 = 1; + var _g7 = l + 1; + while(_g8 < _g7) { + var j2 = _g8++; + verb_core_Vec.addMulMutate(v2,verb_core_Binomial.get(l,j2) * wders[i1][j2],SKL[k - i1][l - j2]); + } + verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1),v2); + } + verb_core_Vec.mulMutate(1 / wders[0][0],v); + SKL[k].push(v); + } + } + rowders.push(SKL); + } + } + return allratders; +}; +verb_eval_Eval.surfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var dim = controlPoints[0][0].length; + var spanU = (verb_core_ArrayExtensions.last(knotsU) - knotsU[0]) / divsU; + var spanV = (verb_core_ArrayExtensions.last(knotsV) - knotsV[0]) / divsV; + var knotSpansBasesU = verb_eval_Eval.regularlySpacedDerivativeBasisFunctions(degreeU,knotsU,divsU); + var knotSpansU = knotSpansBasesU.item0; + var basesU = knotSpansBasesU.item1; + var knotSpansBasesV = verb_eval_Eval.regularlySpacedDerivativeBasisFunctions(degreeV,knotsV,divsV); + var knotSpansV = knotSpansBasesV.item0; + var basesV = knotSpansBasesV.item1; + var pts = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var ptsi = []; + pts.push(ptsi); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + ptsi.push(verb_eval_Eval.surfaceDerivativesGivenBasesKnotSpans(degreeU,degreeV,controlPoints,knotSpansU[i],knotSpansV[j],basesU[i],basesV[j],dim,numDerivs)); + } + } + return pts; +}; +verb_eval_Eval.regularlySpacedBasisFunctions = function(degree,knots,divs) { + var n = knots.length - degree - 2; + var span = (verb_core_ArrayExtensions.last(knots) - knots[0]) / divs; + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var div1 = divs + 1; + var _g = 0; + while(_g < div1) { + var i = _g++; + while(u >= knots[knotIndex + 1]) knotIndex++; + knotspans.push(knotIndex); + bases.push(verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotIndex,u,degree,knots)); + u += span; + } + return new verb_core_Pair(knotspans,bases); +}; +verb_eval_Eval.regularlySpacedDerivativeBasisFunctions = function(degree,knots,divs) { + var n = knots.length - degree - 2; + var span = (verb_core_ArrayExtensions.last(knots) - knots[0]) / divs; + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var div1 = divs + 1; + var _g = 0; + while(_g < div1) { + var i = _g++; + while(u >= knots[knotIndex + 1]) knotIndex++; + knotspans.push(knotIndex); + bases.push(verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotIndex,u,degree,n,knots)); + u += span; + } + return new verb_core_Pair(knotspans,bases); +}; +verb_eval_Eval.surfacePointGivenBasesKnotSpans = function(degreeU,degreeV,controlPoints,knotSpanU,knotSpanV,basesU,basesV,dim) { + var position = verb_core_Vec.zeros1d(dim); + var temp; + var uind = knotSpanU - degreeU; + var vind = knotSpanV - degreeV; + var _g1 = 0; + var _g = degreeV + 1; + while(_g1 < _g) { + var l = _g1++; + temp = verb_core_Vec.zeros1d(dim); + var _g3 = 0; + var _g2 = degreeU + 1; + while(_g3 < _g2) { + var k = _g3++; + verb_core_Vec.addMulMutate(temp,basesU[k],controlPoints[uind + k][vind]); + } + vind++; + verb_core_Vec.addMulMutate(position,basesV[l],temp); + } + return position; +}; +verb_eval_Eval.surfaceDerivativesGivenBasesKnotSpans = function(degreeU,degreeV,controlPoints,knotSpanU,knotSpanV,basesU,basesV,dim,numDerivs) { + var dim1 = controlPoints[0][0].length; + var du; + if(numDerivs < degreeU) du = numDerivs; else du = degreeU; + var dv; + if(numDerivs < degreeV) dv = numDerivs; else dv = degreeV; + var SKL = verb_core_Vec.zeros3d(du + 1,dv + 1,dim1); + var temp = verb_core_Vec.zeros2d(degreeV + 1,dim1); + var dd = 0; + var _g1 = 0; + var _g = du + 1; + while(_g1 < _g) { + var k = _g1++; + var _g3 = 0; + var _g2 = degreeV + 1; + while(_g3 < _g2) { + var s = _g3++; + temp[s] = verb_core_Vec.zeros1d(dim1); + var _g5 = 0; + var _g4 = degreeU + 1; + while(_g5 < _g4) { + var r = _g5++; + verb_core_Vec.addMulMutate(temp[s],basesU[k][r],controlPoints[knotSpanU - degreeU + r][knotSpanV - degreeV + s]); + } + } + var nk = numDerivs - k; + if(nk < dv) dd = nk; else dd = dv; + var _g31 = 0; + var _g21 = dd + 1; + while(_g31 < _g21) { + var l = _g31++; + SKL[k][l] = verb_core_Vec.zeros1d(dim1); + var _g51 = 0; + var _g41 = degreeV + 1; + while(_g51 < _g41) { + var s1 = _g51++; + verb_core_Vec.addMulMutate(SKL[k][l],basesV[l][s1],temp[s1]); + } + } + } + return SKL; +}; +verb_eval_Eval.curveDerivatives = function(crv,u,numDerivs) { + var n = crv.knots.length - crv.degree - 2; + return verb_eval_Eval.curveDerivativesGivenN(n,crv,u,numDerivs); +}; +verb_eval_Eval.curveDerivativesGivenN = function(n,curve,u,numDerivs) { + var degree = curve.degree; + var controlPoints = curve.controlPoints; + var knots = curve.knots; + if(!verb_eval_Eval.areValidRelations(degree,controlPoints.length,knots.length)) throw new js__$Boot_HaxeError("Invalid relations between control points, knot vector, and n"); + var dim = controlPoints[0].length; + var du; + if(numDerivs < degree) du = numDerivs; else du = degree; + var CK = verb_core_Vec.zeros2d(du + 1,dim); + var knotSpan_index = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var nders = verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index,u,degree,du,knots); + var k = 0; + var j = 0; + var _g1 = 0; + var _g = du + 1; + while(_g1 < _g) { + var k1 = _g1++; + var _g3 = 0; + var _g2 = degree + 1; + while(_g3 < _g2) { + var j1 = _g3++; + verb_core_Vec.addMulMutate(CK[k1],nders[k1][j1],controlPoints[knotSpan_index - degree + j1]); + } + } + return CK; +}; +verb_eval_Eval.curvePoint = function(curve,u) { + var n = curve.knots.length - curve.degree - 2; + return verb_eval_Eval.curvePointGivenN(n,curve,u); +}; +verb_eval_Eval.areValidRelations = function(degree,num_controlPoints,knots_length) { + return num_controlPoints + degree + 1 - knots_length == 0; +}; +verb_eval_Eval.curvePointGivenN = function(n,curve,u) { + var degree = curve.degree; + var controlPoints = curve.controlPoints; + var knots = curve.knots; + if(!verb_eval_Eval.areValidRelations(degree,controlPoints.length,knots.length)) { + throw new js__$Boot_HaxeError("Invalid relations between control points, knot Array, and n"); + return null; + } + var knotSpan_index = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var basis_values = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index,u,degree,knots); + var position = verb_core_Vec.zeros1d(controlPoints[0].length); + var _g1 = 0; + var _g = degree + 1; + while(_g1 < _g) { + var j = _g1++; + verb_core_Vec.addMulMutate(position,basis_values[j],controlPoints[knotSpan_index - degree + j]); + } + return position; +}; +verb_eval_Eval.volumePoint = function(volume,u,v,w) { + var n = volume.knotsU.length - volume.degreeU - 2; + var m = volume.knotsV.length - volume.degreeV - 2; + var l = volume.knotsW.length - volume.degreeW - 2; + return verb_eval_Eval.volumePointGivenNML(volume,n,m,l,u,v,w); +}; +verb_eval_Eval.volumePointGivenNML = function(volume,n,m,l,u,v,w) { + if(!verb_eval_Eval.areValidRelations(volume.degreeU,volume.controlPoints.length,volume.knotsU.length) || !verb_eval_Eval.areValidRelations(volume.degreeV,volume.controlPoints[0].length,volume.knotsV.length) || !verb_eval_Eval.areValidRelations(volume.degreeW,volume.controlPoints[0][0].length,volume.knotsW.length)) throw new js__$Boot_HaxeError("Invalid relations between control points and knot vector"); + var controlPoints = volume.controlPoints; + var degreeU = volume.degreeU; + var degreeV = volume.degreeV; + var degreeW = volume.degreeW; + var knotsU = volume.knotsU; + var knotsV = volume.knotsV; + var knotsW = volume.knotsW; + var dim = controlPoints[0][0][0].length; + var knotSpan_index_u = verb_eval_Eval.knotSpanGivenN(n,degreeU,u,knotsU); + var knotSpan_index_v = verb_eval_Eval.knotSpanGivenN(m,degreeV,v,knotsV); + var knotSpan_index_w = verb_eval_Eval.knotSpanGivenN(l,degreeW,w,knotsW); + var u_basis_vals = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index_u,u,degreeU,knotsU); + var v_basis_vals = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index_v,v,degreeV,knotsV); + var w_basis_vals = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index_w,w,degreeW,knotsW); + var uind = knotSpan_index_u - degreeU; + var position = verb_core_Vec.zeros1d(dim); + var temp = verb_core_Vec.zeros1d(dim); + var temp2 = verb_core_Vec.zeros1d(dim); + var _g1 = 0; + var _g = degreeW + 1; + while(_g1 < _g) { + var i = _g1++; + temp2 = verb_core_Vec.zeros1d(dim); + var wind = knotSpan_index_w - degreeW + i; + var _g3 = 0; + var _g2 = degreeV + 1; + while(_g3 < _g2) { + var j = _g3++; + temp = verb_core_Vec.zeros1d(dim); + var vind = knotSpan_index_v - degreeV + j; + var _g5 = 0; + var _g4 = degreeU + 1; + while(_g5 < _g4) { + var k = _g5++; + verb_core_Vec.addMulMutate(temp,u_basis_vals[k],controlPoints[uind + k][vind][wind]); + } + verb_core_Vec.addMulMutate(temp2,v_basis_vals[j],temp); + } + verb_core_Vec.addMulMutate(position,w_basis_vals[i],temp2); + } + return position; +}; +verb_eval_Eval.derivativeBasisFunctions = function(u,degree,knots) { + var knotSpan_index = verb_eval_Eval.knotSpan(degree,u,knots); + var m = knots.length - 1; + var n = m - degree - 1; + return verb_eval_Eval.derivativeBasisFunctionsGivenNI(knotSpan_index,u,degree,n,knots); +}; +verb_eval_Eval.derivativeBasisFunctionsGivenNI = function(knotIndex,u,p,n,knots) { + var ndu = verb_core_Vec.zeros2d(p + 1,p + 1); + var left = verb_core_Vec.zeros1d(p + 1); + var right = verb_core_Vec.zeros1d(p + 1); + var saved = 0.0; + var temp = 0.0; + ndu[0][0] = 1.0; + var _g1 = 1; + var _g = p + 1; + while(_g1 < _g) { + var j = _g1++; + left[j] = u - knots[knotIndex + 1 - j]; + right[j] = knots[knotIndex + j] - u; + saved = 0.0; + var _g2 = 0; + while(_g2 < j) { + var r = _g2++; + ndu[j][r] = right[r + 1] + left[j - r]; + temp = ndu[r][j - 1] / ndu[j][r]; + ndu[r][j] = saved + right[r + 1] * temp; + saved = left[j - r] * temp; + } + ndu[j][j] = saved; + } + var ders = verb_core_Vec.zeros2d(n + 1,p + 1); + var a = verb_core_Vec.zeros2d(2,p + 1); + var s1 = 0; + var s2 = 1; + var d = 0.0; + var rk = 0; + var pk = 0; + var j1 = 0; + var j2 = 0; + var _g11 = 0; + var _g3 = p + 1; + while(_g11 < _g3) { + var j3 = _g11++; + ders[0][j3] = ndu[j3][p]; + } + var _g12 = 0; + var _g4 = p + 1; + while(_g12 < _g4) { + var r1 = _g12++; + s1 = 0; + s2 = 1; + a[0][0] = 1.0; + var _g31 = 1; + var _g21 = n + 1; + while(_g31 < _g21) { + var k = _g31++; + d = 0.0; + rk = r1 - k; + pk = p - k; + if(r1 >= k) { + a[s2][0] = a[s1][0] / ndu[pk + 1][rk]; + d = a[s2][0] * ndu[rk][pk]; + } + if(rk >= -1) j1 = 1; else j1 = -rk; + if(r1 - 1 <= pk) j2 = k - 1; else j2 = p - r1; + var _g5 = j1; + var _g41 = j2 + 1; + while(_g5 < _g41) { + var j4 = _g5++; + a[s2][j4] = (a[s1][j4] - a[s1][j4 - 1]) / ndu[pk + 1][rk + j4]; + d += a[s2][j4] * ndu[rk + j4][pk]; + } + if(r1 <= pk) { + a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r1]; + d += a[s2][k] * ndu[r1][pk]; + } + ders[k][r1] = d; + var temp1 = s1; + s1 = s2; + s2 = temp1; + } + } + var acc = p; + var _g13 = 1; + var _g6 = n + 1; + while(_g13 < _g6) { + var k1 = _g13++; + var _g32 = 0; + var _g22 = p + 1; + while(_g32 < _g22) { + var j5 = _g32++; + ders[k1][j5] *= acc; + } + acc *= p - k1; + } + return ders; +}; +verb_eval_Eval.basisFunctions = function(u,degree,knots) { + var knotSpan_index = verb_eval_Eval.knotSpan(degree,u,knots); + return verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(knotSpan_index,u,degree,knots); +}; +verb_eval_Eval.basisFunctionsGivenKnotSpanIndex = function(knotSpan_index,u,degree,knots) { + var basisFunctions = verb_core_Vec.zeros1d(degree + 1); + var left = verb_core_Vec.zeros1d(degree + 1); + var right = verb_core_Vec.zeros1d(degree + 1); + var saved = 0; + var temp = 0; + basisFunctions[0] = 1.0; + var _g1 = 1; + var _g = degree + 1; + while(_g1 < _g) { + var j = _g1++; + left[j] = u - knots[knotSpan_index + 1 - j]; + right[j] = knots[knotSpan_index + j] - u; + saved = 0.0; + var _g2 = 0; + while(_g2 < j) { + var r = _g2++; + temp = basisFunctions[r] / (right[r + 1] + left[j - r]); + basisFunctions[r] = saved + right[r + 1] * temp; + saved = left[j - r] * temp; + } + basisFunctions[j] = saved; + } + return basisFunctions; +}; +verb_eval_Eval.knotSpan = function(degree,u,knots) { + return verb_eval_Eval.knotSpanGivenN(knots.length - degree - 2,degree,u,knots); +}; +verb_eval_Eval.knotSpanGivenN = function(n,degree,u,knots) { + if(u > knots[n + 1] - verb_core_Constants.EPSILON) return n; + if(u < knots[degree] + verb_core_Constants.EPSILON) return degree; + var low = degree; + var high = n + 1; + var mid = Math.floor((low + high) / 2); + while(u < knots[mid] || u >= knots[mid + 1]) { + if(u < knots[mid]) high = mid; else low = mid; + mid = Math.floor((low + high) / 2); + } + return mid; +}; +verb_eval_Eval.dehomogenize = function(homoPoint) { + var dim = homoPoint.length; + var point = []; + var wt = homoPoint[dim - 1]; + var l = homoPoint.length - 1; + var _g = 0; + while(_g < l) { + var i = _g++; + point.push(homoPoint[i] / wt); + } + return point; +}; +verb_eval_Eval.rational1d = function(homoPoints) { + var dim = homoPoints[0].length - 1; + return homoPoints.map(function(x) { + return x.slice(0,dim); + }); +}; +verb_eval_Eval.rational2d = function(homoPoints) { + return homoPoints.map(verb_eval_Eval.rational1d); +}; +verb_eval_Eval.weight1d = function(homoPoints) { + var dim = homoPoints[0].length - 1; + return homoPoints.map(function(x) { + return x[dim]; + }); +}; +verb_eval_Eval.weight2d = function(homoPoints) { + return homoPoints.map(verb_eval_Eval.weight1d); +}; +verb_eval_Eval.dehomogenize1d = function(homoPoints) { + return homoPoints.map(verb_eval_Eval.dehomogenize); +}; +verb_eval_Eval.dehomogenize2d = function(homoPoints) { + return homoPoints.map(verb_eval_Eval.dehomogenize1d); +}; +verb_eval_Eval.homogenize1d = function(controlPoints,weights) { + var rows = controlPoints.length; + var dim = controlPoints[0].length; + var homo_controlPoints = []; + var wt = 0.0; + var ref_pt = []; + var weights1; + if(weights != null) weights1 = weights; else weights1 = verb_core_Vec.rep(controlPoints.length,1.0); + var _g = 0; + while(_g < rows) { + var i = _g++; + var pt = []; + ref_pt = controlPoints[i]; + wt = weights1[i]; + var _g1 = 0; + while(_g1 < dim) { + var k = _g1++; + pt.push(ref_pt[k] * wt); + } + pt.push(wt); + homo_controlPoints.push(pt); + } + return homo_controlPoints; +}; +verb_eval_Eval.homogenize2d = function(controlPoints,weights) { + var rows = controlPoints.length; + var homo_controlPoints = []; + var weights1; + if(weights != null) weights1 = weights; else { + var _g = []; + var _g1 = 0; + while(_g1 < rows) { + var i = _g1++; + _g.push(verb_core_Vec.rep(controlPoints[0].length,1.0)); + } + weights1 = _g; + } + var _g11 = 0; + while(_g11 < rows) { + var i1 = _g11++; + homo_controlPoints.push(verb_eval_Eval.homogenize1d(controlPoints[i1],weights1[i1])); + } + return homo_controlPoints; +}; +var verb_eval_Intersect = $hx_exports.eval.Intersect = function() { }; +$hxClasses["verb.eval.Intersect"] = verb_eval_Intersect; +verb_eval_Intersect.__name__ = ["verb","eval","Intersect"]; +verb_eval_Intersect.surfaces = function(surface0,surface1,tol) { + var tess1 = verb_eval_Tess.rationalSurfaceAdaptive(surface0); + var tess2 = verb_eval_Tess.rationalSurfaceAdaptive(surface1); + var resApprox = verb_eval_Intersect.meshes(tess1,tess2); + var exactPls = resApprox.map(function(pl) { + return pl.map(function(inter) { + return verb_eval_Intersect.surfacesAtPointWithEstimate(surface0,surface1,inter.uv0,inter.uv1,tol); + }); + }); + return exactPls.map(function(x) { + return verb_eval_Make.rationalInterpCurve(x.map(function(y) { + return y.point; + }),3); + }); +}; +verb_eval_Intersect.surfacesAtPointWithEstimate = function(surface0,surface1,uv1,uv2,tol) { + var pds; + var p; + var pn; + var pu; + var pv; + var pd; + var qds; + var q; + var qn; + var qu; + var qv; + var qd; + var dist; + var maxits = 5; + var its = 0; + do { + pds = verb_eval_Eval.rationalSurfaceDerivatives(surface0,uv1[0],uv1[1],1); + p = pds[0][0]; + pu = pds[1][0]; + pv = pds[0][1]; + pn = verb_core_Vec.normalized(verb_core_Vec.cross(pu,pv)); + pd = verb_core_Vec.dot(pn,p); + qds = verb_eval_Eval.rationalSurfaceDerivatives(surface1,uv2[0],uv2[1],1); + q = qds[0][0]; + qu = qds[1][0]; + qv = qds[0][1]; + qn = verb_core_Vec.normalized(verb_core_Vec.cross(qu,qv)); + qd = verb_core_Vec.dot(qn,q); + dist = verb_core_Vec.distSquared(p,q); + if(dist < tol * tol) break; + var fn = verb_core_Vec.normalized(verb_core_Vec.cross(pn,qn)); + var fd = verb_core_Vec.dot(fn,p); + var x = verb_eval_Intersect.threePlanes(pn,pd,qn,qd,fn,fd); + if(x == null) throw new js__$Boot_HaxeError("panic!"); + var pdif = verb_core_Vec.sub(x,p); + var qdif = verb_core_Vec.sub(x,q); + var rw = verb_core_Vec.cross(pu,pn); + var rt = verb_core_Vec.cross(pv,pn); + var su = verb_core_Vec.cross(qu,qn); + var sv = verb_core_Vec.cross(qv,qn); + var dw = verb_core_Vec.dot(rt,pdif) / verb_core_Vec.dot(rt,pu); + var dt = verb_core_Vec.dot(rw,pdif) / verb_core_Vec.dot(rw,pv); + var du = verb_core_Vec.dot(sv,qdif) / verb_core_Vec.dot(sv,qu); + var dv = verb_core_Vec.dot(su,qdif) / verb_core_Vec.dot(su,qv); + uv1 = verb_core_Vec.add([dw,dt],uv1); + uv2 = verb_core_Vec.add([du,dv],uv2); + its++; + } while(its < maxits); + return new verb_core_SurfaceSurfaceIntersectionPoint(uv1,uv2,p,dist); +}; +verb_eval_Intersect.meshes = function(mesh0,mesh1,bbtree0,bbtree1) { + if(bbtree0 == null) bbtree0 = new verb_core_LazyMeshBoundingBoxTree(mesh0); + if(bbtree1 == null) bbtree1 = new verb_core_LazyMeshBoundingBoxTree(mesh1); + var bbints = verb_eval_Intersect.boundingBoxTrees(bbtree0,bbtree1,0); + var segments = verb_core_ArrayExtensions.unique(bbints.map(function(ids) { + return verb_eval_Intersect.triangles(mesh0,ids.item0,mesh1,ids.item1); + }).filter(function(x) { + return x != null; + }).filter(function(x1) { + return verb_core_Vec.distSquared(x1.min.point,x1.max.point) > verb_core_Constants.EPSILON; + }),function(a,b) { + var s1 = verb_core_Vec.sub(a.min.uv0,b.min.uv0); + var d1 = verb_core_Vec.dot(s1,s1); + var s2 = verb_core_Vec.sub(a.max.uv0,b.max.uv0); + var d2 = verb_core_Vec.dot(s2,s2); + var s3 = verb_core_Vec.sub(a.min.uv0,b.max.uv0); + var d3 = verb_core_Vec.dot(s3,s3); + var s4 = verb_core_Vec.sub(a.max.uv0,b.min.uv0); + var d4 = verb_core_Vec.dot(s4,s4); + return d1 < verb_core_Constants.EPSILON && d2 < verb_core_Constants.EPSILON || d3 < verb_core_Constants.EPSILON && d4 < verb_core_Constants.EPSILON; + }); + return verb_eval_Intersect.makeMeshIntersectionPolylines(segments); +}; +verb_eval_Intersect.meshSlices = function(mesh,min,max,step) { + var bbtree = new verb_core_MeshBoundingBoxTree(mesh); + var bb = bbtree.boundingBox(); + var x0 = bb.min[0]; + var y0 = bb.min[1]; + var x1 = bb.max[0]; + var y1 = bb.max[1]; + var span = verb_core_Vec.span(min,max,step); + var slices = []; + var _g = 0; + while(_g < span.length) { + var z = span[_g]; + ++_g; + var pts = [[x0,y0,z],[x1,y0,z],[x1,y1,z],[x0,y1,z]]; + var uvs = [[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]]; + var faces = [[0,1,2],[0,2,3]]; + var plane = new verb_core_MeshData(faces,pts,null,uvs); + slices.push(verb_eval_Intersect.meshes(mesh,plane,bbtree)); + } + return slices; +}; +verb_eval_Intersect.makeMeshIntersectionPolylines = function(segments) { + if(segments.length == 0) return []; + var _g = 0; + while(_g < segments.length) { + var s = segments[_g]; + ++_g; + s.max.opp = s.min; + s.min.opp = s.max; + } + var tree = verb_eval_Intersect.kdTreeFromSegments(segments); + var ends = []; + var _g1 = 0; + while(_g1 < segments.length) { + var seg = segments[_g1]; + ++_g1; + ends.push(seg.min); + ends.push(seg.max); + } + var _g2 = 0; + while(_g2 < ends.length) { + var segEnd = ends[_g2]; + ++_g2; + if(segEnd.adj != null) continue; + var adjEnd = verb_eval_Intersect.lookupAdjacentSegment(segEnd,tree,segments.length); + if(adjEnd != null && adjEnd.adj == null) { + segEnd.adj = adjEnd; + adjEnd.adj = segEnd; + } + } + var freeEnds = ends.filter(function(x) { + return x.adj == null; + }); + if(freeEnds.length == 0) freeEnds = ends; + var pls = []; + var numVisitedEnds = 0; + var loopDetected = false; + while(freeEnds.length != 0) { + var end = freeEnds.pop(); + if(!end.visited) { + var pl = []; + var curEnd = end; + while(curEnd != null) { + if(curEnd.visited) break; + curEnd.visited = true; + curEnd.opp.visited = true; + pl.push(curEnd); + numVisitedEnds += 2; + curEnd = curEnd.opp.adj; + if(curEnd == end) break; + } + if(pl.length > 0) { + pl.push(pl[pl.length - 1].opp); + pls.push(pl); + } + } + if(freeEnds.length == 0 && ends.length > 0 && (loopDetected || numVisitedEnds < ends.length)) { + loopDetected = true; + var e = ends.pop(); + freeEnds.push(e); + } + } + return pls; +}; +verb_eval_Intersect.kdTreeFromSegments = function(segments) { + var treePoints = []; + var _g = 0; + while(_g < segments.length) { + var seg = segments[_g]; + ++_g; + treePoints.push(new verb_core_KdPoint(seg.min.point,seg.min)); + treePoints.push(new verb_core_KdPoint(seg.max.point,seg.max)); + } + return new verb_core_KdTree(treePoints,verb_core_Vec.distSquared); +}; +verb_eval_Intersect.lookupAdjacentSegment = function(segEnd,tree,numResults) { + var adj = tree.nearest(segEnd.point,numResults,verb_core_Constants.EPSILON).filter(function(r) { + return segEnd != r.item0.obj; + }).map(function(r1) { + return r1.item0.obj; + }); + if(adj.length == 1) return adj[0]; else return null; +}; +verb_eval_Intersect.curveAndSurface = function(curve,surface,tol,crvBbTree,srfBbTree) { + if(tol == null) tol = 1e-3; + if(crvBbTree != null) crvBbTree = crvBbTree; else crvBbTree = new verb_core_LazyCurveBoundingBoxTree(curve); + if(srfBbTree != null) srfBbTree = srfBbTree; else srfBbTree = new verb_core_LazySurfaceBoundingBoxTree(surface); + var ints = verb_eval_Intersect.boundingBoxTrees(crvBbTree,srfBbTree,tol); + return verb_core_ArrayExtensions.unique(ints.map(function(inter) { + var crvSeg = inter.item0; + var srfPart = inter.item1; + var min = verb_core_ArrayExtensions.first(crvSeg.knots); + var max = verb_core_ArrayExtensions.last(crvSeg.knots); + var u = (min + max) / 2.0; + var minu = verb_core_ArrayExtensions.first(srfPart.knotsU); + var maxu = verb_core_ArrayExtensions.last(srfPart.knotsU); + var minv = verb_core_ArrayExtensions.first(srfPart.knotsV); + var maxv = verb_core_ArrayExtensions.last(srfPart.knotsV); + var uv = [(minu + maxu) / 2.0,(minv + maxv) / 2.0]; + return verb_eval_Intersect.curveAndSurfaceWithEstimate(crvSeg,srfPart,[u].concat(uv),tol); + }).filter(function(x) { + return verb_core_Vec.distSquared(x.curvePoint,x.surfacePoint) < tol * tol; + }),function(a,b) { + return Math.abs(a.u - b.u) < 0.5 * tol; + }); +}; +verb_eval_Intersect.curveAndSurfaceWithEstimate = function(curve,surface,start_params,tol) { + if(tol == null) tol = 1e-3; + var objective = function(x) { + var p1 = verb_eval_Eval.rationalCurvePoint(curve,x[0]); + var p2 = verb_eval_Eval.rationalSurfacePoint(surface,x[1],x[2]); + var p1_p2 = verb_core_Vec.sub(p1,p2); + return verb_core_Vec.dot(p1_p2,p1_p2); + }; + var grad = function(x1) { + var dc = verb_eval_Eval.rationalCurveDerivatives(curve,x1[0],1); + var ds = verb_eval_Eval.rationalSurfaceDerivatives(surface,x1[1],x1[2],1); + var r = verb_core_Vec.sub(ds[0][0],dc[0]); + var drdt = verb_core_Vec.mul(-1.0,dc[1]); + var drdu = ds[1][0]; + var drdv = ds[0][1]; + return [2.0 * verb_core_Vec.dot(drdt,r),2.0 * verb_core_Vec.dot(drdu,r),2.0 * verb_core_Vec.dot(drdv,r)]; + }; + var sol_obj = verb_core_Minimizer.uncmin(objective,start_params,tol * tol,grad); + var $final = sol_obj.solution; + return new verb_core_CurveSurfaceIntersection($final[0],[$final[1],$final[2]],verb_eval_Eval.rationalCurvePoint(curve,$final[0]),verb_eval_Eval.rationalSurfacePoint(surface,$final[1],$final[2])); +}; +verb_eval_Intersect.polylineAndMesh = function(polyline,mesh,tol) { + var res = verb_eval_Intersect.boundingBoxTrees(new verb_core_LazyPolylineBoundingBoxTree(polyline),new verb_core_LazyMeshBoundingBoxTree(mesh),tol); + var finalResults = []; + var _g = 0; + while(_g < res.length) { + var event = res[_g]; + ++_g; + var polid = event.item0; + var faceid = event.item1; + var inter = verb_eval_Intersect.segmentWithTriangle(polyline.points[polid],polyline.points[polid + 1],mesh.points,mesh.faces[faceid]); + if(inter == null) continue; + var pt = inter.point; + var u = verb_core_Vec.lerp(inter.p,[polyline.params[polid]],[polyline.params[polid + 1]])[0]; + var uv = verb_core_Mesh.triangleUVFromPoint(mesh,faceid,pt); + finalResults.push(new verb_core_PolylineMeshIntersection(pt,u,uv,polid,faceid)); + } + return finalResults; +}; +verb_eval_Intersect.boundingBoxTrees = function(ai,bi,tol) { + if(tol == null) tol = 1e-9; + var atrees = []; + var btrees = []; + atrees.push(ai); + btrees.push(bi); + var results = []; + while(atrees.length > 0) { + var a = atrees.pop(); + var b = btrees.pop(); + if(a.empty() || b.empty()) continue; + if(!a.boundingBox().intersects(b.boundingBox(),tol)) continue; + var ai1 = a.indivisible(tol); + var bi1 = b.indivisible(tol); + if(ai1 && bi1) { + results.push(new verb_core_Pair(a["yield"](),b["yield"]())); + continue; + } else if(ai1 && !bi1) { + var bs1 = b.split(); + atrees.push(a); + btrees.push(bs1.item1); + atrees.push(a); + btrees.push(bs1.item0); + continue; + } else if(!ai1 && bi1) { + var as1 = a.split(); + atrees.push(as1.item1); + btrees.push(b); + atrees.push(as1.item0); + btrees.push(b); + continue; + } + var $as = a.split(); + var bs = b.split(); + atrees.push($as.item1); + btrees.push(bs.item1); + atrees.push($as.item1); + btrees.push(bs.item0); + atrees.push($as.item0); + btrees.push(bs.item1); + atrees.push($as.item0); + btrees.push(bs.item0); + } + return results; +}; +verb_eval_Intersect.curves = function(curve1,curve2,tolerance) { + var ints = verb_eval_Intersect.boundingBoxTrees(new verb_core_LazyCurveBoundingBoxTree(curve1),new verb_core_LazyCurveBoundingBoxTree(curve2),0); + return verb_core_ArrayExtensions.unique(ints.map(function(x) { + return verb_eval_Intersect.curvesWithEstimate(curve1,curve2,verb_core_ArrayExtensions.first(x.item0.knots),verb_core_ArrayExtensions.first(x.item1.knots),tolerance); + }).filter(function(x1) { + return verb_core_Vec.distSquared(x1.point0,x1.point1) < tolerance; + }),function(a,b) { + return Math.abs(a.u0 - b.u0) < tolerance * 5; + }); +}; +verb_eval_Intersect.curvesWithEstimate = function(curve0,curve1,u0,u1,tolerance) { + var objective = function(x) { + var p1 = verb_eval_Eval.rationalCurvePoint(curve0,x[0]); + var p2 = verb_eval_Eval.rationalCurvePoint(curve1,x[1]); + var p1_p2 = verb_core_Vec.sub(p1,p2); + return verb_core_Vec.dot(p1_p2,p1_p2); + }; + var grad = function(x1) { + var dc0 = verb_eval_Eval.rationalCurveDerivatives(curve0,x1[0],1); + var dc1 = verb_eval_Eval.rationalCurveDerivatives(curve1,x1[1],1); + var r = verb_core_Vec.sub(dc0[0],dc1[0]); + var drdu = dc0[1]; + var drdt = verb_core_Vec.mul(-1.0,dc1[1]); + return [2.0 * verb_core_Vec.dot(drdu,r),2.0 * verb_core_Vec.dot(drdt,r)]; + }; + var sol_obj = verb_core_Minimizer.uncmin(objective,[u0,u1],tolerance * tolerance,grad); + var u11 = sol_obj.solution[0]; + var u2 = sol_obj.solution[1]; + var p11 = verb_eval_Eval.rationalCurvePoint(curve0,u11); + var p21 = verb_eval_Eval.rationalCurvePoint(curve1,u2); + return new verb_core_CurveCurveIntersection(p11,p21,u11,u2); +}; +verb_eval_Intersect.triangles = function(mesh0,faceIndex0,mesh1,faceIndex1) { + var tri0 = mesh0.faces[faceIndex0]; + var tri1 = mesh1.faces[faceIndex1]; + var n0 = verb_core_Mesh.getTriangleNorm(mesh0.points,tri0); + var n1 = verb_core_Mesh.getTriangleNorm(mesh1.points,tri1); + var o0 = mesh0.points[tri0[0]]; + var o1 = mesh1.points[tri1[0]]; + var ray = verb_eval_Intersect.planes(o0,n0,o1,n1); + if(ray == null) return null; + var clip1 = verb_eval_Intersect.clipRayInCoplanarTriangle(ray,mesh0,faceIndex0); + if(clip1 == null) return null; + var clip2 = verb_eval_Intersect.clipRayInCoplanarTriangle(ray,mesh1,faceIndex1); + if(clip2 == null) return null; + var merged = verb_eval_Intersect.mergeTriangleClipIntervals(clip1,clip2,mesh0,faceIndex0,mesh1,faceIndex1); + if(merged == null) return null; + return new verb_core_Interval(new verb_core_MeshIntersectionPoint(merged.min.uv0,merged.min.uv1,merged.min.point,faceIndex0,faceIndex1),new verb_core_MeshIntersectionPoint(merged.max.uv0,merged.max.uv1,merged.max.point,faceIndex0,faceIndex1)); +}; +verb_eval_Intersect.clipRayInCoplanarTriangle = function(ray,mesh,faceIndex) { + var tri = mesh.faces[faceIndex]; + var o = [mesh.points[tri[0]],mesh.points[tri[1]],mesh.points[tri[2]]]; + var uvs = [mesh.uvs[tri[0]],mesh.uvs[tri[1]],mesh.uvs[tri[2]]]; + var uvd = [verb_core_Vec.sub(uvs[1],uvs[0]),verb_core_Vec.sub(uvs[2],uvs[1]),verb_core_Vec.sub(uvs[0],uvs[2])]; + var s = [verb_core_Vec.sub(o[1],o[0]),verb_core_Vec.sub(o[2],o[1]),verb_core_Vec.sub(o[0],o[2])]; + var d = s.map(verb_core_Vec.normalized); + var l = s.map(verb_core_Vec.norm); + var minU = null; + var maxU = null; + var _g = 0; + while(_g < 3) { + var i = _g++; + var o0 = o[i]; + var d0 = d[i]; + var res = verb_eval_Intersect.rays(o0,d0,ray.origin,ray.dir); + if(res == null) continue; + var useg = res.u0; + var uray = res.u1; + if(useg < -verb_core_Constants.EPSILON || useg > l[i] + verb_core_Constants.EPSILON) continue; + if(minU == null || uray < minU.u) minU = new verb_core_CurveTriPoint(uray,verb_core_Vec.onRay(ray.origin,ray.dir,uray),verb_core_Vec.onRay(uvs[i],uvd[i],useg / l[i])); + if(maxU == null || uray > maxU.u) maxU = new verb_core_CurveTriPoint(uray,verb_core_Vec.onRay(ray.origin,ray.dir,uray),verb_core_Vec.onRay(uvs[i],uvd[i],useg / l[i])); + } + if(maxU == null || minU == null) return null; + return new verb_core_Interval(minU,maxU); +}; +verb_eval_Intersect.mergeTriangleClipIntervals = function(clip1,clip2,mesh1,faceIndex1,mesh2,faceIndex2) { + if(clip2.min.u > clip1.max.u + verb_core_Constants.EPSILON || clip1.min.u > clip2.max.u + verb_core_Constants.EPSILON) return null; + var min; + if(clip1.min.u > clip2.min.u) min = new verb_core_Pair(clip1.min,0); else min = new verb_core_Pair(clip2.min,1); + var max; + if(clip1.max.u < clip2.max.u) max = new verb_core_Pair(clip1.max,0); else max = new verb_core_Pair(clip2.max,1); + var res = new verb_core_Interval(new verb_core_MeshIntersectionPoint(null,null,min.item0.point,faceIndex1,faceIndex2),new verb_core_MeshIntersectionPoint(null,null,max.item0.point,faceIndex1,faceIndex2)); + if(min.item1 == 0) { + res.min.uv0 = min.item0.uv; + res.min.uv1 = verb_core_Mesh.triangleUVFromPoint(mesh2,faceIndex2,min.item0.point); + } else { + res.min.uv0 = verb_core_Mesh.triangleUVFromPoint(mesh1,faceIndex1,min.item0.point); + res.min.uv1 = min.item0.uv; + } + if(max.item1 == 0) { + res.max.uv0 = max.item0.uv; + res.max.uv1 = verb_core_Mesh.triangleUVFromPoint(mesh2,faceIndex2,max.item0.point); + } else { + res.max.uv0 = verb_core_Mesh.triangleUVFromPoint(mesh1,faceIndex1,max.item0.point); + res.max.uv1 = max.item0.uv; + } + return res; +}; +verb_eval_Intersect.planes = function(origin0,normal0,origin1,normal1) { + var d = verb_core_Vec.cross(normal0,normal1); + if(verb_core_Vec.dot(d,d) < verb_core_Constants.EPSILON) return null; + var li = 0; + var mi = Math.abs(d[0]); + var m1 = Math.abs(d[1]); + var m2 = Math.abs(d[2]); + if(m1 > mi) { + li = 1; + mi = m1; + } + if(m2 > mi) { + li = 2; + mi = m2; + } + var a1; + var b1; + var a2; + var b2; + if(li == 0) { + a1 = normal0[1]; + b1 = normal0[2]; + a2 = normal1[1]; + b2 = normal1[2]; + } else if(li == 1) { + a1 = normal0[0]; + b1 = normal0[2]; + a2 = normal1[0]; + b2 = normal1[2]; + } else { + a1 = normal0[0]; + b1 = normal0[1]; + a2 = normal1[0]; + b2 = normal1[1]; + } + var d1 = -verb_core_Vec.dot(origin0,normal0); + var d2 = -verb_core_Vec.dot(origin1,normal1); + var den = a1 * b2 - b1 * a2; + var x = (b1 * d2 - d1 * b2) / den; + var y = (d1 * a2 - a1 * d2) / den; + var p; + if(li == 0) p = [0,x,y]; else if(li == 1) p = [x,0,y]; else p = [x,y,0]; + return new verb_core_Ray(p,verb_core_Vec.normalized(d)); +}; +verb_eval_Intersect.threePlanes = function(n0,d0,n1,d1,n2,d2) { + var u = verb_core_Vec.cross(n1,n2); + var den = verb_core_Vec.dot(n0,u); + if(Math.abs(den) < verb_core_Constants.EPSILON) return null; + var diff = verb_core_Vec.sub(verb_core_Vec.mul(d2,n1),verb_core_Vec.mul(d1,n2)); + var num = verb_core_Vec.add(verb_core_Vec.mul(d0,u),verb_core_Vec.cross(n0,diff)); + return verb_core_Vec.mul(1 / den,num); +}; +verb_eval_Intersect.polylines = function(polyline0,polyline1,tol) { + var res = verb_eval_Intersect.boundingBoxTrees(new verb_core_LazyPolylineBoundingBoxTree(polyline0),new verb_core_LazyPolylineBoundingBoxTree(polyline1),tol); + var finalResults = []; + var _g = 0; + while(_g < res.length) { + var event = res[_g]; + ++_g; + var polid0 = event.item0; + var polid1 = event.item1; + var inter = verb_eval_Intersect.segments(polyline0.points[polid0],polyline0.points[polid0 + 1],polyline1.points[polid1],polyline1.points[polid1 + 1],tol); + if(inter == null) continue; + inter.u0 = verb_core_Vec.lerp(inter.u0,[polyline0.params[polid0]],[polyline0.params[polid0 + 1]])[0]; + inter.u1 = verb_core_Vec.lerp(inter.u1,[polyline1.params[polid1]],[polyline1.params[polid1 + 1]])[0]; + finalResults.push(inter); + } + return finalResults; +}; +verb_eval_Intersect.segments = function(a0,a1,b0,b1,tol) { + var a1ma0 = verb_core_Vec.sub(a1,a0); + var aN = Math.sqrt(verb_core_Vec.dot(a1ma0,a1ma0)); + var a = verb_core_Vec.mul(1 / aN,a1ma0); + var b1mb0 = verb_core_Vec.sub(b1,b0); + var bN = Math.sqrt(verb_core_Vec.dot(b1mb0,b1mb0)); + var b = verb_core_Vec.mul(1 / bN,b1mb0); + var int_params = verb_eval_Intersect.rays(a0,a,b0,b); + if(int_params != null) { + var u0 = Math.min(Math.max(0,int_params.u0 / aN),1.0); + var u1 = Math.min(Math.max(0,int_params.u1 / bN),1.0); + var point0 = verb_core_Vec.onRay(a0,a1ma0,u0); + var point1 = verb_core_Vec.onRay(b0,b1mb0,u1); + var dist = verb_core_Vec.distSquared(point0,point1); + if(dist < tol * tol) return new verb_core_CurveCurveIntersection(point0,point1,u0,u1); + } + return null; +}; +verb_eval_Intersect.rays = function(a0,a,b0,b) { + var dab = verb_core_Vec.dot(a,b); + var dab0 = verb_core_Vec.dot(a,b0); + var daa0 = verb_core_Vec.dot(a,a0); + var dbb0 = verb_core_Vec.dot(b,b0); + var dba0 = verb_core_Vec.dot(b,a0); + var daa = verb_core_Vec.dot(a,a); + var dbb = verb_core_Vec.dot(b,b); + var div = daa * dbb - dab * dab; + if(Math.abs(div) < verb_core_Constants.EPSILON) return null; + var num = dab * (dab0 - daa0) - daa * (dbb0 - dba0); + var w = num / div; + var t = (dab0 - daa0 + w * dab) / daa; + var p0 = verb_core_Vec.onRay(a0,a,t); + var p1 = verb_core_Vec.onRay(b0,b,w); + return new verb_core_CurveCurveIntersection(p0,p1,t,w); +}; +verb_eval_Intersect.segmentWithTriangle = function(p0,p1,points,tri) { + var v0 = points[tri[0]]; + var v1 = points[tri[1]]; + var v2 = points[tri[2]]; + var u = verb_core_Vec.sub(v1,v0); + var v = verb_core_Vec.sub(v2,v0); + var n = verb_core_Vec.cross(u,v); + var dir = verb_core_Vec.sub(p1,p0); + var w0 = verb_core_Vec.sub(p0,v0); + var a = -verb_core_Vec.dot(n,w0); + var b = verb_core_Vec.dot(n,dir); + if(Math.abs(b) < verb_core_Constants.EPSILON) return null; + var r = a / b; + if(r < 0 || r > 1) return null; + var pt = verb_core_Vec.add(p0,verb_core_Vec.mul(r,dir)); + var uv = verb_core_Vec.dot(u,v); + var uu = verb_core_Vec.dot(u,u); + var vv = verb_core_Vec.dot(v,v); + var w = verb_core_Vec.sub(pt,v0); + var wu = verb_core_Vec.dot(w,u); + var wv = verb_core_Vec.dot(w,v); + var denom = uv * uv - uu * vv; + if(Math.abs(denom) < verb_core_Constants.EPSILON) return null; + var s = (uv * wv - vv * wu) / denom; + var t = (uv * wu - uu * wv) / denom; + if(s > 1.0 + verb_core_Constants.EPSILON || t > 1.0 + verb_core_Constants.EPSILON || t < -verb_core_Constants.EPSILON || s < -verb_core_Constants.EPSILON || s + t > 1.0 + verb_core_Constants.EPSILON) return null; + return new verb_core_TriSegmentIntersection(pt,s,t,r); +}; +verb_eval_Intersect.segmentAndPlane = function(p0,p1,v0,n) { + var denom = verb_core_Vec.dot(n,verb_core_Vec.sub(p1,p0)); + if(Math.abs(denom) < verb_core_Constants.EPSILON) return null; + var numer = verb_core_Vec.dot(n,verb_core_Vec.sub(v0,p0)); + var p = numer / denom; + if(p > 1.0 + verb_core_Constants.EPSILON || p < -verb_core_Constants.EPSILON) return null; + return { p : p}; +}; +var verb_eval_Make = $hx_exports.eval.Make = function() { }; +$hxClasses["verb.eval.Make"] = verb_eval_Make; +verb_eval_Make.__name__ = ["verb","eval","Make"]; +verb_eval_Make.rationalTranslationalSurface = function(profile,rail) { + var pt0 = verb_eval_Eval.rationalCurvePoint(rail,verb_core_ArrayExtensions.first(rail.knots)); + var startu = verb_core_ArrayExtensions.first(rail.knots); + var endu = verb_core_ArrayExtensions.last(rail.knots); + var numSamples = 2 * rail.controlPoints.length; + var span = (endu - startu) / (numSamples - 1); + var crvs = []; + var _g = 0; + while(_g < numSamples) { + var i = _g++; + var pt = verb_core_Vec.sub(verb_eval_Eval.rationalCurvePoint(rail,startu + i * span),pt0); + var crv = verb_eval_Modify.rationalCurveTransform(profile,[[1,0,0,pt[0]],[0,1,0,pt[1]],[0,0,1,pt[2]],[0,0,0,1]]); + crvs.push(crv); + } + return verb_eval_Make.loftedSurface(crvs); +}; +verb_eval_Make.surfaceBoundaryCurves = function(surface) { + var crvs = []; + var c0 = verb_eval_Make.surfaceIsocurve(surface,verb_core_ArrayExtensions.first(surface.knotsU),false); + var c1 = verb_eval_Make.surfaceIsocurve(surface,verb_core_ArrayExtensions.last(surface.knotsU),false); + var c2 = verb_eval_Make.surfaceIsocurve(surface,verb_core_ArrayExtensions.first(surface.knotsV),true); + var c3 = verb_eval_Make.surfaceIsocurve(surface,verb_core_ArrayExtensions.last(surface.knotsV),true); + return [c0,c1,c2,c3]; +}; +verb_eval_Make.surfaceIsocurve = function(surface,u,useV) { + if(useV == null) useV = false; + var knots; + if(useV) knots = surface.knotsV; else knots = surface.knotsU; + var degree; + if(useV) degree = surface.degreeV; else degree = surface.degreeU; + var knotMults = verb_eval_Analyze.knotMultiplicities(knots); + var reqKnotIndex = -1; + var _g1 = 0; + var _g = knotMults.length; + while(_g1 < _g) { + var i = _g1++; + if(Math.abs(u - knotMults[i].knot) < verb_core_Constants.EPSILON) { + reqKnotIndex = i; + break; + } + } + var numKnotsToInsert = degree + 1; + if(reqKnotIndex >= 0) numKnotsToInsert = numKnotsToInsert - knotMults[reqKnotIndex].mult; + var newSrf; + if(numKnotsToInsert > 0) newSrf = verb_eval_Modify.surfaceKnotRefine(surface,verb_core_Vec.rep(numKnotsToInsert,u),useV); else newSrf = surface; + var span = verb_eval_Eval.knotSpan(degree,u,knots); + if(Math.abs(u - verb_core_ArrayExtensions.first(knots)) < verb_core_Constants.EPSILON) span = 0; else if(Math.abs(u - verb_core_ArrayExtensions.last(knots)) < verb_core_Constants.EPSILON) span = (useV?newSrf.controlPoints[0].length:newSrf.controlPoints.length) - 1; + if(useV) return new verb_core_NurbsCurveData(newSrf.degreeU,newSrf.knotsU,(function($this) { + var $r; + var _g2 = []; + { + var _g11 = 0; + var _g21 = newSrf.controlPoints; + while(_g11 < _g21.length) { + var row = _g21[_g11]; + ++_g11; + _g2.push(row[span]); + } + } + $r = _g2; + return $r; + }(this))); + return new verb_core_NurbsCurveData(newSrf.degreeV,newSrf.knotsV,newSrf.controlPoints[span]); +}; +verb_eval_Make.loftedSurface = function(curves,degreeV) { + curves = verb_eval_Modify.unifyCurveKnotVectors(curves); + var degreeU = curves[0].degree; + if(degreeV == null) degreeV = 3; + if(degreeV > curves.length - 1) degreeV = curves.length - 1; + var knotsU = curves[0].knots; + var knotsV = []; + var controlPoints = []; + var _g1 = 0; + var _g = curves[0].controlPoints.length; + while(_g1 < _g) { + var i = [_g1++]; + var points = curves.map((function(i) { + return function(x) { + return x.controlPoints[i[0]]; + }; + })(i)); + var c = verb_eval_Make.rationalInterpCurve(points,degreeV,true); + controlPoints.push(c.controlPoints); + knotsV = c.knots; + } + return new verb_core_NurbsSurfaceData(degreeU,degreeV,knotsU,knotsV,controlPoints); +}; +verb_eval_Make.clonedCurve = function(curve) { + return new verb_core_NurbsCurveData(curve.degree,curve.knots.slice(),curve.controlPoints.map(function(x) { + return x.slice(); + })); +}; +verb_eval_Make.clonedSurface = function(surface) { + var newpts = []; + var newrow; + var _g = 0; + var _g1 = surface.controlPoints; + while(_g < _g1.length) { + var row = _g1[_g]; + ++_g; + newrow = []; + newpts.push(newrow); + var _g2 = 0; + while(_g2 < row.length) { + var pt = row[_g2]; + ++_g2; + newrow.push(pt.slice()); + } + } + return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),surface.knotsV.slice(),newpts); +}; +verb_eval_Make.rationalBezierCurve = function(controlPoints,weights) { + var degree = controlPoints.length - 1; + var knots = []; + var _g1 = 0; + var _g = degree + 1; + while(_g1 < _g) { + var i = _g1++; + knots.push(0.0); + } + var _g11 = 0; + var _g2 = degree + 1; + while(_g11 < _g2) { + var i1 = _g11++; + knots.push(1.0); + } + if(weights == null) weights = verb_core_Vec.rep(controlPoints.length,1.0); + return new verb_core_NurbsCurveData(degree,knots,verb_eval_Eval.homogenize1d(controlPoints,weights)); +}; +verb_eval_Make.fourPointSurface = function(p1,p2,p3,p4,degree) { + if(degree == null) degree = 3; + var degreeFloat = degree; + var pts = []; + var _g1 = 0; + var _g = degree + 1; + while(_g1 < _g) { + var i = _g1++; + var row = []; + var _g3 = 0; + var _g2 = degree + 1; + while(_g3 < _g2) { + var j = _g3++; + var l = 1.0 - i / degreeFloat; + var p1p2 = verb_core_Vec.lerp(l,p1,p2); + var p4p3 = verb_core_Vec.lerp(l,p4,p3); + var res = verb_core_Vec.lerp(1.0 - j / degreeFloat,p1p2,p4p3); + res.push(1.0); + row.push(res); + } + pts.push(row); + } + var zeros = verb_core_Vec.rep(degree + 1,0.0); + var ones = verb_core_Vec.rep(degree + 1,1.0); + return new verb_core_NurbsSurfaceData(degree,degree,zeros.concat(ones),zeros.concat(ones),pts); +}; +verb_eval_Make.ellipseArc = function(center,xaxis,yaxis,startAngle,endAngle) { + var xradius = verb_core_Vec.norm(xaxis); + var yradius = verb_core_Vec.norm(yaxis); + xaxis = verb_core_Vec.normalized(xaxis); + yaxis = verb_core_Vec.normalized(yaxis); + if(endAngle < startAngle) endAngle = 2.0 * Math.PI + startAngle; + var theta = endAngle - startAngle; + var numArcs = 0; + if(theta <= Math.PI / 2) numArcs = 1; else if(theta <= Math.PI) numArcs = 2; else if(theta <= 3 * Math.PI / 2) numArcs = 3; else numArcs = 4; + var dtheta = theta / numArcs; + var n = 2 * numArcs; + var w1 = Math.cos(dtheta / 2); + var P0 = verb_core_Vec.add(center,verb_core_Vec.add(verb_core_Vec.mul(xradius * Math.cos(startAngle),xaxis),verb_core_Vec.mul(yradius * Math.sin(startAngle),yaxis))); + var T0 = verb_core_Vec.sub(verb_core_Vec.mul(Math.cos(startAngle),yaxis),verb_core_Vec.mul(Math.sin(startAngle),xaxis)); + var controlPoints = []; + var knots = verb_core_Vec.zeros1d(2 * numArcs + 3); + var index = 0; + var angle = startAngle; + var weights = verb_core_Vec.zeros1d(numArcs * 2); + controlPoints[0] = P0; + weights[0] = 1.0; + var _g1 = 1; + var _g = numArcs + 1; + while(_g1 < _g) { + var i = _g1++; + angle += dtheta; + var P2 = verb_core_Vec.add(center,verb_core_Vec.add(verb_core_Vec.mul(xradius * Math.cos(angle),xaxis),verb_core_Vec.mul(yradius * Math.sin(angle),yaxis))); + weights[index + 2] = 1; + controlPoints[index + 2] = P2; + var T2 = verb_core_Vec.sub(verb_core_Vec.mul(Math.cos(angle),yaxis),verb_core_Vec.mul(Math.sin(angle),xaxis)); + var inters = verb_eval_Intersect.rays(P0,verb_core_Vec.mul(1 / verb_core_Vec.norm(T0),T0),P2,verb_core_Vec.mul(1 / verb_core_Vec.norm(T2),T2)); + var P1 = verb_core_Vec.add(P0,verb_core_Vec.mul(inters.u0,T0)); + weights[index + 1] = w1; + controlPoints[index + 1] = P1; + index += 2; + if(i < numArcs) { + P0 = P2; + T0 = T2; + } + } + var j = 2 * numArcs + 1; + var _g2 = 0; + while(_g2 < 3) { + var i1 = _g2++; + knots[i1] = 0.0; + knots[i1 + j] = 1.0; + } + switch(numArcs) { + case 2: + knots[3] = knots[4] = 0.5; + break; + case 3: + knots[3] = knots[4] = 0.333333333333333315; + knots[5] = knots[6] = 0.66666666666666663; + break; + case 4: + knots[3] = knots[4] = 0.25; + knots[5] = knots[6] = 0.5; + knots[7] = knots[8] = 0.75; + break; + } + return new verb_core_NurbsCurveData(2,knots,verb_eval_Eval.homogenize1d(controlPoints,weights)); +}; +verb_eval_Make.arc = function(center,xaxis,yaxis,radius,startAngle,endAngle) { + return verb_eval_Make.ellipseArc(center,verb_core_Vec.mul(radius,verb_core_Vec.normalized(xaxis)),verb_core_Vec.mul(radius,verb_core_Vec.normalized(yaxis)),startAngle,endAngle); +}; +verb_eval_Make.polyline = function(pts) { + var knots = [0.0,0.0]; + var lsum = 0.0; + var _g1 = 0; + var _g = pts.length - 1; + while(_g1 < _g) { + var i = _g1++; + lsum += verb_core_Vec.dist(pts[i],pts[i + 1]); + knots.push(lsum); + } + knots.push(lsum); + knots = verb_core_Vec.mul(1 / lsum,knots); + var weights; + var _g2 = []; + var _g21 = 0; + var _g11 = pts.length; + while(_g21 < _g11) { + var i1 = _g21++; + _g2.push(1.0); + } + weights = _g2; + return new verb_core_NurbsCurveData(1,knots,verb_eval_Eval.homogenize1d(pts.slice(0),weights)); +}; +verb_eval_Make.extrudedSurface = function(axis,length,profile) { + var controlPoints = [[],[],[]]; + var weights = [[],[],[]]; + var prof_controlPoints = verb_eval_Eval.dehomogenize1d(profile.controlPoints); + var prof_weights = verb_eval_Eval.weight1d(profile.controlPoints); + var translation = verb_core_Vec.mul(length,axis); + var halfTranslation = verb_core_Vec.mul(0.5 * length,axis); + var _g1 = 0; + var _g = prof_controlPoints.length; + while(_g1 < _g) { + var j = _g1++; + controlPoints[2][j] = prof_controlPoints[j]; + controlPoints[1][j] = verb_core_Vec.add(halfTranslation,prof_controlPoints[j]); + controlPoints[0][j] = verb_core_Vec.add(translation,prof_controlPoints[j]); + weights[0][j] = prof_weights[j]; + weights[1][j] = prof_weights[j]; + weights[2][j] = prof_weights[j]; + } + return new verb_core_NurbsSurfaceData(2,profile.degree,[0,0,0,1,1,1],profile.knots,verb_eval_Eval.homogenize2d(controlPoints,weights)); +}; +verb_eval_Make.cylindricalSurface = function(axis,xaxis,base,height,radius) { + var yaxis = verb_core_Vec.cross(axis,xaxis); + var angle = 2.0 * Math.PI; + var circ = verb_eval_Make.arc(base,xaxis,yaxis,radius,0.0,2 * Math.PI); + return verb_eval_Make.extrudedSurface(axis,height,circ); +}; +verb_eval_Make.revolvedSurface = function(profile,center,axis,theta) { + var prof_controlPoints = verb_eval_Eval.dehomogenize1d(profile.controlPoints); + var prof_weights = verb_eval_Eval.weight1d(profile.controlPoints); + var narcs; + var knotsU; + var controlPoints; + var weights; + if(theta <= Math.PI / 2) { + narcs = 1; + knotsU = verb_core_Vec.zeros1d(6 + 2 * (narcs - 1)); + } else if(theta <= Math.PI) { + narcs = 2; + knotsU = verb_core_Vec.zeros1d(6 + 2 * (narcs - 1)); + knotsU[3] = knotsU[4] = 0.5; + } else if(theta <= 3 * Math.PI / 2) { + narcs = 3; + knotsU = verb_core_Vec.zeros1d(6 + 2 * (narcs - 1)); + knotsU[3] = knotsU[4] = 0.333333333333333315; + knotsU[5] = knotsU[6] = 0.66666666666666663; + } else { + narcs = 4; + knotsU = verb_core_Vec.zeros1d(6 + 2 * (narcs - 1)); + knotsU[3] = knotsU[4] = 0.25; + knotsU[5] = knotsU[6] = 0.5; + knotsU[7] = knotsU[8] = 0.75; + } + var dtheta = theta / narcs; + var j = 3 + 2 * (narcs - 1); + var _g = 0; + while(_g < 3) { + var i = _g++; + knotsU[i] = 0.0; + knotsU[j + i] = 1.0; + } + var n = 2 * narcs; + var wm = Math.cos(dtheta / 2.0); + var angle = 0.0; + var sines = verb_core_Vec.zeros1d(narcs + 1); + var cosines = verb_core_Vec.zeros1d(narcs + 1); + var controlPoints1 = verb_core_Vec.zeros3d(2 * narcs + 1,prof_controlPoints.length,3); + var weights1 = verb_core_Vec.zeros2d(2 * narcs + 1,prof_controlPoints.length); + var _g1 = 1; + var _g2 = narcs + 1; + while(_g1 < _g2) { + var i1 = _g1++; + angle += dtheta; + cosines[i1] = Math.cos(angle); + sines[i1] = Math.sin(angle); + } + var _g11 = 0; + var _g3 = prof_controlPoints.length; + while(_g11 < _g3) { + var j1 = _g11++; + var O = verb_core_Trig.rayClosestPoint(prof_controlPoints[j1],center,axis); + var X = verb_core_Vec.sub(prof_controlPoints[j1],O); + var r = verb_core_Vec.norm(X); + var Y = verb_core_Vec.cross(axis,X); + if(r > verb_core_Constants.EPSILON) { + X = verb_core_Vec.mul(1 / r,X); + Y = verb_core_Vec.mul(1 / r,Y); + } + controlPoints1[0][j1] = prof_controlPoints[j1]; + var P0 = prof_controlPoints[j1]; + weights1[0][j1] = prof_weights[j1]; + var T0 = Y; + var index = 0; + var angle1 = 0.0; + var _g31 = 1; + var _g21 = narcs + 1; + while(_g31 < _g21) { + var i2 = _g31++; + var P2; + if(r == 0) P2 = O; else P2 = verb_core_Vec.add(O,verb_core_Vec.add(verb_core_Vec.mul(r * cosines[i2],X),verb_core_Vec.mul(r * sines[i2],Y))); + controlPoints1[index + 2][j1] = P2; + weights1[index + 2][j1] = prof_weights[j1]; + var T2 = verb_core_Vec.sub(verb_core_Vec.mul(cosines[i2],Y),verb_core_Vec.mul(sines[i2],X)); + if(r == 0) controlPoints1[index + 1][j1] = O; else { + var inters = verb_eval_Intersect.rays(P0,verb_core_Vec.mul(1 / verb_core_Vec.norm(T0),T0),P2,verb_core_Vec.mul(1 / verb_core_Vec.norm(T2),T2)); + var P1 = verb_core_Vec.add(P0,verb_core_Vec.mul(inters.u0,T0)); + controlPoints1[index + 1][j1] = P1; + } + weights1[index + 1][j1] = wm * prof_weights[j1]; + index += 2; + if(i2 < narcs) { + P0 = P2; + T0 = T2; + } + } + } + return new verb_core_NurbsSurfaceData(2,profile.degree,knotsU,profile.knots,verb_eval_Eval.homogenize2d(controlPoints1,weights1)); +}; +verb_eval_Make.sphericalSurface = function(center,axis,xaxis,radius) { + var arc = verb_eval_Make.arc(center,verb_core_Vec.mul(-1.0,axis),xaxis,radius,0.0,Math.PI); + return verb_eval_Make.revolvedSurface(arc,center,axis,2 * Math.PI); +}; +verb_eval_Make.conicalSurface = function(axis,xaxis,base,height,radius) { + var angle = 2 * Math.PI; + var prof_degree = 1; + var prof_ctrl_pts = [verb_core_Vec.add(base,verb_core_Vec.mul(height,axis)),verb_core_Vec.add(base,verb_core_Vec.mul(radius,xaxis))]; + var prof_knots = [0.0,0.0,1.0,1.0]; + var prof_weights = [1.0,1.0]; + var prof = new verb_core_NurbsCurveData(prof_degree,prof_knots,verb_eval_Eval.homogenize1d(prof_ctrl_pts,prof_weights)); + return verb_eval_Make.revolvedSurface(prof,base,axis,angle); +}; +verb_eval_Make.rationalInterpCurve = function(points,degree,homogeneousPoints,start_tangent,end_tangent) { + if(homogeneousPoints == null) homogeneousPoints = false; + if(degree == null) degree = 3; + if(points.length < degree + 1) throw new js__$Boot_HaxeError("You need to supply at least degree + 1 points! You only supplied " + points.length + " points."); + var us = [0.0]; + var _g1 = 1; + var _g = points.length; + while(_g1 < _g) { + var i = _g1++; + var chord = verb_core_Vec.norm(verb_core_Vec.sub(points[i],points[i - 1])); + var last = us[us.length - 1]; + us.push(last + chord); + } + var max = us[us.length - 1]; + var _g11 = 0; + var _g2 = us.length; + while(_g11 < _g2) { + var i1 = _g11++; + us[i1] = us[i1] / max; + } + var knotsStart = verb_core_Vec.rep(degree + 1,0.0); + var hasTangents = start_tangent != null && end_tangent != null; + var start; + if(hasTangents) start = 0; else start = 1; + var end; + if(hasTangents) end = us.length - degree + 1; else end = us.length - degree; + var _g3 = start; + while(_g3 < end) { + var i2 = _g3++; + var weightSums = 0.0; + var _g12 = 0; + while(_g12 < degree) { + var j = _g12++; + weightSums += us[i2 + j]; + } + knotsStart.push(1 / degree * weightSums); + } + var knots = knotsStart.concat(verb_core_Vec.rep(degree + 1,1.0)); + var A = []; + var n; + if(hasTangents) n = points.length + 1; else n = points.length - 1; + var lst; + if(hasTangents) lst = 1; else lst = 0; + var ld; + if(hasTangents) ld = points.length - (degree - 1); else ld = points.length - (degree + 1); + var _g4 = 0; + while(_g4 < us.length) { + var u = us[_g4]; + ++_g4; + var span = verb_eval_Eval.knotSpanGivenN(n,degree,u,knots); + var basisFuncs = verb_eval_Eval.basisFunctionsGivenKnotSpanIndex(span,u,degree,knots); + var ls = span - degree; + var rowstart = verb_core_Vec.zeros1d(ls); + var rowend = verb_core_Vec.zeros1d(ld - ls); + A.push(rowstart.concat(basisFuncs).concat(rowend)); + } + if(hasTangents) { + var ln = A[0].length - 2; + var tanRow0 = [-1.0,1.0].concat(verb_core_Vec.zeros1d(ln)); + var tanRow1 = verb_core_Vec.zeros1d(ln).concat([-1.0,1.0]); + verb_core_ArrayExtensions.spliceAndInsert(A,1,0,tanRow0); + verb_core_ArrayExtensions.spliceAndInsert(A,A.length - 1,0,tanRow1); + } + var dim = points[0].length; + var xs = []; + var mult1 = (1 - knots[knots.length - degree - 2]) / degree; + var mult0 = knots[degree + 1] / degree; + var _g5 = 0; + while(_g5 < dim) { + var i3 = [_g5++]; + var b; + if(!hasTangents) b = points.map((function(i3) { + return function(x1) { + return x1[i3[0]]; + }; + })(i3)); else { + b = [points[0][i3[0]]]; + b.push(mult0 * start_tangent[i3[0]]); + var _g21 = 1; + var _g13 = points.length - 1; + while(_g21 < _g13) { + var j1 = _g21++; + b.push(points[j1][i3[0]]); + } + b.push(mult1 * end_tangent[i3[0]]); + b.push(verb_core_ArrayExtensions.last(points)[i3[0]]); + } + var x = verb_core_Mat.solve(A,b); + xs.push(x); + } + var controlPts = verb_core_Mat.transpose(xs); + if(!homogeneousPoints) { + var weights = verb_core_Vec.rep(controlPts.length,1.0); + controlPts = verb_eval_Eval.homogenize1d(controlPts,weights); + } + return new verb_core_NurbsCurveData(degree,knots,controlPts); +}; +var verb_eval_Modify = $hx_exports.eval.Modify = function() { }; +$hxClasses["verb.eval.Modify"] = verb_eval_Modify; +verb_eval_Modify.__name__ = ["verb","eval","Modify"]; +verb_eval_Modify.curveReverse = function(curve) { + return new verb_core_NurbsCurveData(curve.degree,verb_eval_Modify.knotsReverse(curve.knots),verb_core_ArrayExtensions.reversed(curve.controlPoints)); +}; +verb_eval_Modify.surfaceReverse = function(surface,useV) { + if(useV == null) useV = false; + if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU,verb_eval_Modify.knotsReverse(surface.knotsV),(function($this) { + var $r; + var _g = []; + { + var _g1 = 0; + var _g2 = surface.controlPoints; + while(_g1 < _g2.length) { + var row = _g2[_g1]; + ++_g1; + _g.push(verb_core_ArrayExtensions.reversed(row)); + } + } + $r = _g; + return $r; + }(this))); + return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,verb_eval_Modify.knotsReverse(surface.knotsU),surface.knotsV,verb_core_ArrayExtensions.reversed(surface.controlPoints)); +}; +verb_eval_Modify.knotsReverse = function(knots) { + var min = verb_core_ArrayExtensions.first(knots); + var max = verb_core_ArrayExtensions.last(knots); + var l = [min]; + var len = knots.length; + var _g = 1; + while(_g < len) { + var i = _g++; + l.push(l[i - 1] + (knots[len - i] - knots[len - i - 1])); + } + return l; +}; +verb_eval_Modify.unifyCurveKnotVectors = function(curves) { + curves = curves.map(verb_eval_Make.clonedCurve); + var maxDegree = Lambda.fold(curves,function(x,a) { + return verb_eval_Modify.imax(x.degree,a); + },0); + var _g1 = 0; + var _g = curves.length; + while(_g1 < _g) { + var i = _g1++; + if(curves[i].degree < maxDegree) curves[i] = verb_eval_Modify.curveElevateDegree(curves[i],maxDegree); + } + var knotIntervals; + var _g2 = []; + var _g11 = 0; + while(_g11 < curves.length) { + var c = curves[_g11]; + ++_g11; + _g2.push(new verb_core_Interval(verb_core_ArrayExtensions.first(c.knots),verb_core_ArrayExtensions.last(c.knots))); + } + knotIntervals = _g2; + var _g21 = 0; + var _g12 = curves.length; + while(_g21 < _g12) { + var i1 = _g21++; + var min = [knotIntervals[i1].min]; + curves[i1].knots = curves[i1].knots.map((function(min) { + return function(x4) { + return x4 - min[0]; + }; + })(min)); + } + var knotSpans = knotIntervals.map(function(x1) { + return x1.max - x1.min; + }); + var maxKnotSpan = Lambda.fold(knotSpans,function(x2,a1) { + return Math.max(x2,a1); + },0.0); + var _g22 = 0; + var _g13 = curves.length; + while(_g22 < _g13) { + var i2 = _g22++; + var scale = [maxKnotSpan / knotSpans[i2]]; + curves[i2].knots = curves[i2].knots.map((function(scale) { + return function(x5) { + return x5 * scale[0]; + }; + })(scale)); + } + var mergedKnots = Lambda.fold(curves,function(x3,a2) { + return verb_core_Vec.sortedSetUnion(x3.knots,a2); + },[]); + var _g23 = 0; + var _g14 = curves.length; + while(_g23 < _g14) { + var i3 = _g23++; + var rem = verb_core_Vec.sortedSetSub(mergedKnots,curves[i3].knots); + if(rem.length == 0) curves[i3] = curves[i3]; + curves[i3] = verb_eval_Modify.curveKnotRefine(curves[i3],rem); + } + return curves; +}; +verb_eval_Modify.imin = function(a,b) { + if(a < b) return a; else return b; +}; +verb_eval_Modify.imax = function(a,b) { + if(a > b) return a; else return b; +}; +verb_eval_Modify.curveElevateDegree = function(curve,finalDegree) { + if(finalDegree <= curve.degree) return curve; + var n = curve.knots.length - curve.degree - 2; + var newDegree = curve.degree; + var knots = curve.knots; + var controlPoints = curve.controlPoints; + var degreeInc = finalDegree - curve.degree; + var dim = curve.controlPoints[0].length; + var bezalfs = verb_core_Vec.zeros2d(newDegree + degreeInc + 1,newDegree + 1); + var bpts = []; + var ebpts = []; + var Nextbpts = []; + var alphas = []; + var m = n + newDegree + 1; + var ph = finalDegree; + var ph2 = Math.floor(ph / 2); + var Qw = []; + var Uh = []; + var nh; + bezalfs[0][0] = 1.0; + bezalfs[ph][newDegree] = 1.0; + var _g1 = 1; + var _g = ph2 + 1; + while(_g1 < _g) { + var i = _g1++; + var inv = 1.0 / verb_core_Binomial.get(ph,i); + var mpi = verb_eval_Modify.imin(newDegree,i); + var _g3 = verb_eval_Modify.imax(0,i - degreeInc); + var _g2 = mpi + 1; + while(_g3 < _g2) { + var j = _g3++; + bezalfs[i][j] = inv * verb_core_Binomial.get(newDegree,j) * verb_core_Binomial.get(degreeInc,i - j); + } + } + var _g4 = ph2 + 1; + while(_g4 < ph) { + var i1 = _g4++; + var mpi1 = verb_eval_Modify.imin(newDegree,i1); + var _g21 = verb_eval_Modify.imax(0,i1 - degreeInc); + var _g11 = mpi1 + 1; + while(_g21 < _g11) { + var j1 = _g21++; + bezalfs[i1][j1] = bezalfs[ph - i1][newDegree - j1]; + } + } + var mh = ph; + var kind = ph + 1; + var r = -1; + var a = newDegree; + var b = newDegree + 1; + var cind = 1; + var ua = knots[0]; + Qw[0] = controlPoints[0]; + var _g12 = 0; + var _g5 = ph + 1; + while(_g12 < _g5) { + var i2 = _g12++; + Uh[i2] = ua; + } + var _g13 = 0; + var _g6 = newDegree + 1; + while(_g13 < _g6) { + var i3 = _g13++; + bpts[i3] = controlPoints[i3]; + } + while(b < m) { + var i4 = b; + while(b < m && knots[b] == knots[b + 1]) b = b + 1; + var mul = b - i4 + 1; + var mh1 = mh + mul + degreeInc; + var ub = knots[b]; + var oldr = r; + r = newDegree - mul; + var lbz; + if(oldr > 0) lbz = Math.floor((oldr + 2) / 2); else lbz = 1; + var rbz; + if(r > 0) rbz = Math.floor(ph - (r + 1) / 2); else rbz = ph; + if(r > 0) { + var numer = ub - ua; + var alfs = []; + var k = newDegree; + while(k > mul) { + alfs[k - mul - 1] = numer / (knots[a + k] - ua); + k--; + } + var _g14 = 1; + var _g7 = r + 1; + while(_g14 < _g7) { + var j2 = _g14++; + var save = r - j2; + var s = mul + j2; + var k1 = newDegree; + while(k1 >= s) { + bpts[k1] = verb_core_Vec.add(verb_core_Vec.mul(alfs[k1 - s],bpts[k1]),verb_core_Vec.mul(1.0 - alfs[k1 - s],bpts[k1 - 1])); + k1--; + } + Nextbpts[save] = bpts[newDegree]; + } + } + var _g15 = lbz; + var _g8 = ph + 1; + while(_g15 < _g8) { + var i5 = _g15++; + ebpts[i5] = verb_core_Vec.zeros1d(dim); + var mpi2 = verb_eval_Modify.imin(newDegree,i5); + var _g31 = verb_eval_Modify.imax(0,i5 - degreeInc); + var _g22 = mpi2 + 1; + while(_g31 < _g22) { + var j3 = _g31++; + ebpts[i5] = verb_core_Vec.add(ebpts[i5],verb_core_Vec.mul(bezalfs[i5][j3],bpts[j3])); + } + } + if(oldr > 1) { + var first = kind - 2; + var last = kind; + var den = ub - ua; + var bet = (ub - Uh[kind - 1]) / den; + var _g9 = 1; + while(_g9 < oldr) { + var tr = _g9++; + var i6 = first; + var j4 = last; + var kj = j4 - kind + 1; + while(j4 - i6 > tr) { + if(i6 < cind) { + var alf = (ub - Uh[i6]) / (ua - Uh[i6]); + Qw[i6] = verb_core_Vec.lerp(alf,Qw[i6],Qw[i6 - 1]); + } + if(j4 >= lbz) { + if(j4 - tr <= kind - ph + oldr) { + var gam = (ub - Uh[j4 - tr]) / den; + ebpts[kj] = verb_core_Vec.lerp(gam,ebpts[kj],ebpts[kj + 1]); + } + } else ebpts[kj] = verb_core_Vec.lerp(bet,ebpts[kj],ebpts[kj + 1]); + i6 = i6 + 1; + j4 = j4 - 1; + kj = kj - 1; + } + first = first - 1; + last = last + 1; + } + } + if(a != newDegree) { + var _g16 = 0; + var _g10 = ph - oldr; + while(_g16 < _g10) { + var i7 = _g16++; + Uh[kind] = ua; + kind = kind + 1; + } + } + var _g17 = lbz; + var _g18 = rbz + 1; + while(_g17 < _g18) { + var j5 = _g17++; + Qw[cind] = ebpts[j5]; + cind = cind + 1; + } + if(b < m) { + var _g19 = 0; + while(_g19 < r) { + var j6 = _g19++; + bpts[j6] = Nextbpts[j6]; + } + var _g110 = r; + var _g20 = newDegree + 1; + while(_g110 < _g20) { + var j7 = _g110++; + bpts[j7] = controlPoints[b - newDegree + j7]; + } + a = b; + b = b + 1; + ua = ub; + } else { + var _g111 = 0; + var _g23 = ph + 1; + while(_g111 < _g23) { + var i8 = _g111++; + Uh[kind + i8] = ub; + } + } + } + nh = mh - ph - 1; + return new verb_core_NurbsCurveData(finalDegree,Uh,Qw); +}; +verb_eval_Modify.rationalSurfaceTransform = function(surface,mat) { + var pts = verb_eval_Eval.dehomogenize2d(surface.controlPoints); + var _g1 = 0; + var _g = pts.length; + while(_g1 < _g) { + var i = _g1++; + var _g3 = 0; + var _g2 = pts[i].length; + while(_g3 < _g2) { + var j = _g3++; + var homoPt = pts[i][j]; + homoPt.push(1.0); + pts[i][j] = verb_core_Mat.dot(mat,homoPt).slice(0,homoPt.length - 1); + } + } + return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),surface.knotsV.slice(),verb_eval_Eval.homogenize2d(pts,verb_eval_Eval.weight2d(surface.controlPoints))); +}; +verb_eval_Modify.rationalCurveTransform = function(curve,mat) { + var pts = verb_eval_Eval.dehomogenize1d(curve.controlPoints); + var _g1 = 0; + var _g = pts.length; + while(_g1 < _g) { + var i = _g1++; + var homoPt = pts[i]; + homoPt.push(1.0); + pts[i] = verb_core_Mat.dot(mat,homoPt).slice(0,homoPt.length - 1); + } + return new verb_core_NurbsCurveData(curve.degree,curve.knots.slice(),verb_eval_Eval.homogenize1d(pts,verb_eval_Eval.weight1d(curve.controlPoints))); +}; +verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { + if(knotsToInsert.length == 0) return verb_eval_Make.clonedSurface(surface); + var degree; + var controlPoints = surface.controlPoints; + var knots; + if(useV) { + degree = surface.degreeV; + knots = surface.knotsV; + } else { + degree = surface.degreeU; + knots = surface.knotsU; + } + var n; + if(useV) n = controlPoints[0].length - 1; else n = controlPoints.length - 1; + var m = n + degree + 1; + var r = knotsToInsert.length - 1; + var a = verb_eval_Eval.knotSpan(degree,knotsToInsert[0],knots); + var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); + var controlPoints_post = []; + var knots_post = []; + if(useV) { + var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); + var _g1 = 0; + var _g = controlPoints.length + km.length - 1; + while(_g1 < _g) { + var i1 = _g1++; + controlPoints_post.push([]); + } + var _g11 = 0; + var _g2 = a - degree + 1; + while(_g11 < _g2) { + var i2 = _g11++; + var _g3 = 0; + var _g21 = controlPoints.length; + while(_g3 < _g21) { + var j1 = _g3++; + controlPoints_post[j1][i2] = controlPoints[j1][i2]; + } + } + var _g12 = b - 1; + var _g4 = n + 1; + while(_g12 < _g4) { + var i3 = _g12++; + var l = i3 + r + 1; + var _g31 = 0; + var _g22 = controlPoints.length; + while(_g31 < _g22) { + var j2 = _g31++; + controlPoints_post[j2][l] = controlPoints[j2][i3]; + } + } + } else { + var _g13 = 0; + var _g5 = a - degree + 1; + while(_g13 < _g5) { + var i4 = _g13++; + controlPoints_post[i4] = controlPoints[i4].slice(0); + } + var _g14 = b - 1; + var _g6 = n + 1; + while(_g14 < _g6) { + var i5 = _g14++; + controlPoints_post[i5 + r + 1] = controlPoints[i5].slice(0); + } + } + var _g15 = 0; + var _g7 = a + 1; + while(_g15 < _g7) { + var i6 = _g15++; + knots_post[i6] = knots[i6]; + } + var _g16 = b + degree; + var _g8 = m + 1; + while(_g16 < _g8) { + var i7 = _g16++; + knots_post[i7 + r + 1] = knots[i7]; + } + var i = b + degree - 1; + var k = b + degree + r; + var j = r; + var ci; + while(j >= 0) { + while(knotsToInsert[j] <= knots[i] && i > a) { + var wi = k - degree - 1; + var xi = i - degree - 1; + if(useV) { + var _g17 = 0; + var _g9 = controlPoints_post.length; + while(_g17 < _g9) { + var ci1 = _g17++; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi].slice(0); + } + } else controlPoints_post[wi] = controlPoints[xi].slice(0); + knots_post[k] = knots[i]; + k = k - 1; + i = i - 1; + } + if(useV) { + var _g18 = 0; + var _g10 = controlPoints_post.length; + while(_g18 < _g10) { + var ci2 = _g18++; + controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree].slice(0); + } + } else controlPoints_post[k - degree - 1] = controlPoints_post[k - degree].slice(0); + var _g19 = 1; + var _g20 = degree + 1; + while(_g19 < _g20) { + var l1 = _g19++; + var ind = k - degree + l1; + var alfa = knots_post[k + l1] - knotsToInsert[j]; + if(Math.abs(alfa) < verb_core_Constants.EPSILON) { + if(useV) { + var _g32 = 0; + var _g23 = controlPoints_post.length; + while(_g32 < _g23) { + var ci3 = _g32++; + controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; + } + } else controlPoints_post[ind - 1] = controlPoints_post[ind].slice(0); + } else { + alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); + if(useV) { + var _g33 = 0; + var _g24 = controlPoints_post.length; + while(_g33 < _g24) { + var wi1 = _g33++; + controlPoints_post[wi1][ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[wi1][ind - 1],controlPoints_post[wi1][ind]); + } + } else { + var _g34 = 0; + var _g25 = controlPoints_post[ind].length; + while(_g34 < _g25) { + var wi2 = _g34++; + controlPoints_post[ind - 1][wi2] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1][wi2],controlPoints_post[ind][wi2]); + } + } + } + } + knots_post[k] = knotsToInsert[j]; + k = k - 1; + j--; + } + if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),knots_post,controlPoints_post); else return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,knots_post,surface.knotsV.slice(),controlPoints_post); +}; +verb_eval_Modify.decomposeSurfaceIntoBeziers = function(surface) { + var knotmultsU = verb_eval_Analyze.knotMultiplicities(surface.knotsU); + var reqMultU = surface.degreeU + 1; + var _g = 0; + while(_g < knotmultsU.length) { + var knotmult = knotmultsU[_g]; + ++_g; + if(knotmult.mult < reqMultU) { + var knotsInsert = verb_core_Vec.rep(reqMultU - knotmult.mult,knotmult.knot); + if(knotsInsert.length == 0) continue; + surface = verb_eval_Modify.surfaceKnotRefine(surface,knotsInsert,false); + } + } + var knotmultsV = verb_eval_Analyze.knotMultiplicities(surface.knotsV); + var reqMultV = surface.degreeV + 1; + var _g1 = 0; + while(_g1 < knotmultsV.length) { + var knotmult1 = knotmultsV[_g1]; + ++_g1; + if(knotmult1.mult < reqMultV) { + var knotsInsert1 = verb_core_Vec.rep(reqMultV - knotmult1.mult,knotmult1.knot); + if(knotsInsert1.length == 0) continue; + surface = verb_eval_Modify.surfaceKnotRefine(surface,knotsInsert1,true); + } + } + var numU = surface.knotsU.length / reqMultU - 1; + var numV = surface.knotsV.length / reqMultV - 1; + var knotLengthU = reqMultU * 2; + var knotLengthV = reqMultV * 2; + var subSurfaces = []; + var i = 0; + while(i < surface.controlPoints.length) { + var row = []; + subSurfaces.push(row); + var ktsU = surface.knotsU.slice(i,i + knotLengthU); + var j = 0; + while(j < surface.controlPoints[i].length) { + var ktsV = surface.knotsV.slice(j,j + knotLengthV); + var pts = verb_eval_Modify.submatrix(surface.controlPoints,i,j,reqMultV,reqMultU); + row.push(new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,ktsU,ktsV,pts)); + j += reqMultV; + } + i += reqMultU; + } + return subSurfaces; +}; +verb_eval_Modify.submatrix = function(mat,startRow,startCol,rows,cols) { + var newmat = []; + var _g1 = startRow; + var _g = startRow + rows; + while(_g1 < _g) { + var i = _g1++; + newmat.push(mat[i].slice(startCol,startCol + cols)); + } + return newmat; +}; +verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { + var degree = curve.degree; + var controlPoints = curve.controlPoints; + var knots = curve.knots; + var knotmults = verb_eval_Analyze.knotMultiplicities(knots); + var reqMult = degree + 1; + var _g = 0; + while(_g < knotmults.length) { + var knotmult = knotmults[_g]; + ++_g; + if(knotmult.mult < reqMult) { + var knotsInsert = verb_core_Vec.rep(reqMult - knotmult.mult,knotmult.knot); + if(knotsInsert.length == 0) continue; + var res = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,controlPoints),knotsInsert); + knots = res.knots; + controlPoints = res.controlPoints; + } + } + var numCrvs = knots.length / reqMult - 1; + var crvKnotLength = reqMult * 2; + var crvs = []; + var i = 0; + while(i < controlPoints.length) { + var kts = knots.slice(i,i + crvKnotLength); + var pts = controlPoints.slice(i,i + reqMult); + crvs.push(new verb_core_NurbsCurveData(degree,kts,pts)); + i += reqMult; + } + return crvs; +}; +verb_eval_Modify.curveKnotRefine = function(curve,knotsToInsert) { + if(knotsToInsert.length == 0) return verb_eval_Make.clonedCurve(curve); + var degree = curve.degree; + var controlPoints = curve.controlPoints; + var knots = curve.knots; + var n = controlPoints.length - 1; + var m = n + degree + 1; + var r = knotsToInsert.length - 1; + var a = verb_eval_Eval.knotSpan(degree,knotsToInsert[0],knots); + var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); + var controlPoints_post = []; + var knots_post = []; + var _g1 = 0; + var _g = a - degree + 1; + while(_g1 < _g) { + var i1 = _g1++; + controlPoints_post[i1] = controlPoints[i1]; + } + var _g11 = b - 1; + var _g2 = n + 1; + while(_g11 < _g2) { + var i2 = _g11++; + controlPoints_post[i2 + r + 1] = controlPoints[i2]; + } + var _g12 = 0; + var _g3 = a + 1; + while(_g12 < _g3) { + var i3 = _g12++; + knots_post[i3] = knots[i3]; + } + var _g13 = b + degree; + var _g4 = m + 1; + while(_g13 < _g4) { + var i4 = _g13++; + knots_post[i4 + r + 1] = knots[i4]; + } + var i = b + degree - 1; + var k = b + degree + r; + var j = r; + while(j >= 0) { + while(knotsToInsert[j] <= knots[i] && i > a) { + controlPoints_post[k - degree - 1] = controlPoints[i - degree - 1]; + knots_post[k] = knots[i]; + k = k - 1; + i = i - 1; + } + controlPoints_post[k - degree - 1] = controlPoints_post[k - degree]; + var _g14 = 1; + var _g5 = degree + 1; + while(_g14 < _g5) { + var l = _g14++; + var ind = k - degree + l; + var alfa = knots_post[k + l] - knotsToInsert[j]; + if(Math.abs(alfa) < verb_core_Constants.EPSILON) controlPoints_post[ind - 1] = controlPoints_post[ind]; else { + alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); + controlPoints_post[ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1],controlPoints_post[ind]); + } + } + knots_post[k] = knotsToInsert[j]; + k = k - 1; + j--; + } + return new verb_core_NurbsCurveData(degree,knots_post,controlPoints_post); +}; +verb_eval_Modify.curveKnotInsert = function(curve,u,r) { + var degree = curve.degree; + var controlPoints = curve.controlPoints; + var knots = curve.knots; + var s = 0; + var num_pts = controlPoints.length; + var k = verb_eval_Eval.knotSpan(degree,u,knots); + var num_pts_post = num_pts + r; + var controlPoints_temp = []; + var knots_post = []; + var controlPoints_post = []; + var i = 0; + var _g1 = 1; + var _g = k + 1; + while(_g1 < _g) { + var i1 = _g1++; + knots_post[i1] = knots[i1]; + } + var _g11 = 1; + var _g2 = r + 1; + while(_g11 < _g2) { + var i2 = _g11++; + knots_post[k + i2] = u; + } + var _g12 = k + 1; + var _g3 = knots.length; + while(_g12 < _g3) { + var i3 = _g12++; + knots_post[i3 + r] = knots[i3]; + } + var _g13 = 0; + var _g4 = k - degree + 1; + while(_g13 < _g4) { + var i4 = _g13++; + controlPoints_post[i4] = controlPoints[i4]; + } + var _g5 = k - s; + while(_g5 < num_pts) { + var i5 = _g5++; + controlPoints_post[i5 + r] = controlPoints[i5]; + } + var _g14 = 0; + var _g6 = degree - s + 1; + while(_g14 < _g6) { + var i6 = _g14++; + controlPoints_temp[i6] = controlPoints[k - degree + i6]; + } + var L = 0; + var alpha = 0; + var _g15 = 1; + var _g7 = r + 1; + while(_g15 < _g7) { + var j = _g15++; + L = k - degree + j; + var _g31 = 0; + var _g21 = degree - j - s + 1; + while(_g31 < _g21) { + var i7 = _g31++; + alpha = (u - knots[L + i7]) / (knots[i7 + k + 1] - knots[L + i7]); + controlPoints_temp[i7] = verb_core_Vec.add(verb_core_Vec.mul(1.0 - alpha,controlPoints_temp[i7]),verb_core_Vec.mul(alpha,controlPoints_temp[i7 + 1])); + } + controlPoints_post[L] = controlPoints_temp[0]; + controlPoints_post[k + r - j - s] = controlPoints_temp[degree - j - s]; + } + var _g16 = L + 1; + var _g8 = k - s; + while(_g16 < _g8) { + var i8 = _g16++; + controlPoints_post[i8] = controlPoints_temp[i8 - L]; + } + return new verb_core_NurbsCurveData(degree,knots_post,controlPoints_post); +}; +var verb_eval_NewMeshData = function() { }; +$hxClasses["verb.eval.NewMeshData"] = verb_eval_NewMeshData; +verb_eval_NewMeshData.__name__ = ["verb","eval","NewMeshData"]; +verb_eval_NewMeshData.prototype = { + __class__: verb_eval_NewMeshData +}; +var verb_eval_BezierEdgeIndices = function() { +}; +$hxClasses["verb.eval.BezierEdgeIndices"] = verb_eval_BezierEdgeIndices; +verb_eval_BezierEdgeIndices.__name__ = ["verb","eval","BezierEdgeIndices"]; +verb_eval_BezierEdgeIndices.prototype = { + __class__: verb_eval_BezierEdgeIndices +}; +var verb_eval_EdgeSide = $hxClasses["verb.eval.EdgeSide"] = { __ename__ : ["verb","eval","EdgeSide"], __constructs__ : ["North","South","East","West"] }; +verb_eval_EdgeSide.North = ["North",0]; +verb_eval_EdgeSide.North.toString = $estr; +verb_eval_EdgeSide.North.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.South = ["South",1]; +verb_eval_EdgeSide.South.toString = $estr; +verb_eval_EdgeSide.South.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.East = ["East",2]; +verb_eval_EdgeSide.East.toString = $estr; +verb_eval_EdgeSide.East.__enum__ = verb_eval_EdgeSide; +verb_eval_EdgeSide.West = ["West",3]; +verb_eval_EdgeSide.West.toString = $estr; +verb_eval_EdgeSide.West.__enum__ = verb_eval_EdgeSide; +var verb_eval_Tess = $hx_exports.eval.Tess = function() { }; +$hxClasses["verb.eval.Tess"] = verb_eval_Tess; +verb_eval_Tess.__name__ = ["verb","eval","Tess"]; +verb_eval_Tess.rationalBezierSurfaceRegularSample = function(surface,divsU,divsV) { + var pts = []; + var u = surface.knotsU[0]; + var t = (verb_core_ArrayExtensions.last(surface.knotsU) - surface.knotsU[0]) / divsU; + var _g = 0; + while(_g < divsU) { + var i = _g++; + var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); + var v = (verb_core_ArrayExtensions.last(iso.knots) - iso.knots[0]) / divsV; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(iso,pts,iso.knots[0],t,divsV,false); + u += t; + } + return pts; +}; +verb_eval_Tess.northIndex = function(i,j,divs) { + if(i <= 0) return null; + return divs[i - 1][j]; +}; +verb_eval_Tess.southIndex = function(i,j,divs) { + if(i >= divs.length - 1) return null; + return divs[i + 1][j]; +}; +verb_eval_Tess.eastIndex = function(i,j,divs) { + if(j >= divs[i].length - 1) return null; + return divs[i][j + 1]; +}; +verb_eval_Tess.westIndex = function(i,j,divs) { + if(j <= 0) return null; + return divs[i][j - 1]; +}; +verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { + var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); + var stepLengths = []; + var stepLengthRow; + var _g = 0; + while(_g < beziers.length) { + var bezierrow = beziers[_g]; + ++_g; + stepLengthRow = []; + stepLengths.push(stepLengthRow); + var _g1 = 0; + while(_g1 < bezierrow.length) { + var bezier = bezierrow[_g1]; + ++_g1; + var ls = verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol); + ls.item0 = Math.min(ls.item0,(verb_core_ArrayExtensions.last(bezier.knotsU) - verb_core_ArrayExtensions.first(bezier.knotsU)) / 2); + ls.item1 = Math.min(ls.item1,(verb_core_ArrayExtensions.last(bezier.knotsV) - verb_core_ArrayExtensions.first(bezier.knotsV)) / 2); + stepLengthRow.push(ls); + } + } + var pts = []; + var uvs = []; + var edgeRow; + var n; + var s; + var e; + var w; + var empty = new verb_core_Pair(Infinity,Infinity); + var beis = []; + var beir; + var bei; + var e0; + var e1; + var srf; + var _g11 = 0; + var _g2 = beziers.length; + while(_g11 < _g2) { + var i = _g11++; + beir = []; + beis.push(beir); + var _g3 = 0; + var _g21 = beziers[i].length; + while(_g3 < _g21) { + var j = _g3++; + srf = beziers[i][j]; + bei = new verb_eval_BezierEdgeIndices(); + beir.push(bei); + s = verb_eval_Tess.southIndex(i,j,stepLengths); + if(s == null) s = empty; + e = verb_eval_Tess.eastIndex(i,j,stepLengths); + if(e == null) e = empty; + if(i == 0) { + var ne = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.first(srf.knotsU),false); + e0 = pts.length; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(ne,pts,stepLengths[i][j].item1); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(ne.knots),stepLengths[i][j].item1,uvs,verb_core_ArrayExtensions.first(srf.knotsU),true); + bei.n = new verb_core_Pair(e0,e1); + } else bei.n = beis[i - 1][j].s; + if(j == 0) { + e0 = pts.length; + var we = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.first(srf.knotsV),true); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(we,pts,stepLengths[i][j].item0); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(we.knots),stepLengths[i][j].item0,uvs,verb_core_ArrayExtensions.first(srf.knotsV),false); + bei.w = new verb_core_Pair(e0,e1); + } else bei.w = beis[i][j - 1].e; + e0 = pts.length; + var se = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.last(srf.knotsU),false); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(se,pts,Math.min(s.item1,stepLengths[i][j].item1)); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(se.knots),Math.min(s.item1,stepLengths[i][j].item1),uvs,verb_core_ArrayExtensions.last(srf.knotsU),true); + bei.s = new verb_core_Pair(e0,e1); + e0 = pts.length; + var ee = verb_eval_Make.surfaceIsocurve(srf,verb_core_ArrayExtensions.last(srf.knotsV),true); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2(ee,pts,Math.min(e.item0,stepLengths[i][j].item0)); + e1 = pts.length; + verb_eval_Tess.regularUvsMutate(e1 - e0,verb_core_ArrayExtensions.first(ee.knots),Math.min(e.item0,stepLengths[i][j].item0),uvs,verb_core_ArrayExtensions.last(srf.knotsV),false); + bei.e = new verb_core_Pair(e0,e1); + } + } + var faces = []; + var p0; + var _g12 = 0; + var _g4 = beziers.length; + while(_g12 < _g4) { + var i1 = _g12++; + var _g31 = 0; + var _g22 = beziers[i1].length; + while(_g31 < _g22) { + var j1 = _g31++; + p0 = pts.length; + var bezier1 = beziers[i1][j1]; + var divsU = Math.ceil(1.0 / stepLengths[i1][j1].item0); + var domainV = verb_core_ArrayExtensions.last(bezier1.knotsV) - bezier1.knotsV[0]; + var domainU = verb_core_ArrayExtensions.last(bezier1.knotsU) - bezier1.knotsU[0]; + var divsV = Math.ceil(1.0 / stepLengths[i1][j1].item1); + var tessStepV = domainV / divsV; + var tessStepU = domainU / divsU; + var u = bezier1.knotsU[0] + tessStepU; + var _g5 = 0; + var _g41 = divsU - 1; + while(_g5 < _g41) { + var k = _g5++; + var iso = verb_eval_Make.surfaceIsocurve(bezier1,u,false); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(iso,pts,iso.knots[0] + tessStepV,tessStepV,divsV - 1,false); + verb_eval_Tess.regularUvsMutate(divsV - 1,iso.knots[0] + tessStepV,tessStepV,uvs,u,true); + u += tessStepU; + } + divsU = divsU - 2; + divsV = divsV - 2; + var _g42 = 0; + while(_g42 < divsU) { + var k1 = _g42++; + var _g51 = 0; + while(_g51 < divsV) { + var l = _g51++; + var a_k = p0 + k1 * (divsV + 1) + l; + var b_k = p0 + (k1 + 1) * (divsV + 1) + l; + var c_k = b_k + 1; + var d_k = a_k + 1; + var abc = [a_k,b_k,c_k]; + var acd = [a_k,c_k,d_k]; + faces.push(abc); + faces.push(acd); + } + } + bei = beis[i1][j1]; + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainV,p0,tessStepV,verb_eval_EdgeSide.North); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainV,p0,tessStepV,verb_eval_EdgeSide.South); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.East); + verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.West); + } + } + return new verb_core_MeshData(faces,pts,null,uvs); +}; +verb_eval_Tess.regularUvsMutate = function(count,start,step,uvs,constant,uConstant) { + var i = 0; + var u = start; + if(uConstant) while(i < count) { + uvs.push([constant,u]); + u += step; + i++; + } else while(i < count) { + uvs.push([u,constant]); + u += step; + i++; + } +}; +verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tessStep,edgeSide) { + var edgeIndices; + var knots; + var reverseFace = false; + var tessIStep = 1; + var tessDivCount = 1; + switch(edgeSide[1]) { + case 0: + edgeIndices = bei.n; + knots = bezier.knotsV; + tessDivCount = divsV; + break; + case 1: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV + 1); + reverseFace = true; + tessDivCount = divsV; + break; + case 2: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV + 1; + p0 += divsV; + tessDivCount = divsU; + break; + case 3: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV + 1; + reverseFace = true; + tessDivCount = divsU; + break; + } + var edgeCount = edgeIndices.item1 - edgeIndices.item0 - 1; + var edgeStep = domain / edgeCount; + var edgeU = verb_core_ArrayExtensions.first(knots); + var tessU = verb_core_ArrayExtensions.first(knots) + 1.5 * tessStep; + var edgeI = 0; + var tessI = 0; + var tessDivI = 1; + while(edgeI < edgeCount) { + while(edgeU < tessU && edgeI < edgeCount || edgeI < edgeCount && tessDivI > tessDivCount) { + var ei = edgeIndices.item0 + edgeI; + var ei2 = ei + 1; + if(reverseFace) faces.push([ei,ei2,p0 + tessI]); else faces.push([ei,p0 + tessI,ei2]); + edgeI++; + edgeU += edgeStep; + } + if(edgeI < edgeCount) { + var ei1 = edgeIndices.item0 + edgeI; + if(reverseFace) faces.push([p0 + tessI,ei1,p0 + tessI + tessIStep]); else faces.push([p0 + tessI,p0 + tessI + tessIStep,ei1]); + } + tessDivI++; + tessI += tessIStep; + tessU += tessStep; + } +}; +verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate2 = function(crv,pts,step,includeU) { + if(includeU == null) includeU = false; + var domain = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var steps = Math.ceil(1.0 / step); + var len = domain / steps; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(crv,pts,crv.knots[0],len,steps + 1,false); +}; +verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { + var dehomo = verb_eval_Eval.dehomogenize2d(surface.controlPoints); + var bb = new verb_core_BoundingBox(); + var _g = 0; + while(_g < dehomo.length) { + var row = dehomo[_g]; + ++_g; + bb.addRange(row); + } + var avgPt = verb_core_Vec.mul(0.5,verb_core_Vec.add(bb.min,bb.max)); + var m = verb_core_Mat.identity(4); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + var ts = verb_eval_Modify.rationalSurfaceTransform(surface,m); + dehomo = verb_eval_Eval.dehomogenize2d(ts.controlPoints); + var r = 0.0; + var n; + var _g1 = 0; + var _g2 = dehomo.length; + while(_g1 < _g2) { + var i = _g1++; + var _g3 = 0; + var _g21 = dehomo[i].length; + while(_g3 < _g21) { + var j = _g3++; + n = verb_core_Vec.norm(dehomo[i][j]); + if(n > r) r = n; + } + } + var duu = -Infinity; + var iduu; + var _g11 = 0; + var _g4 = surface.controlPoints.length - 2; + while(_g11 < _g4) { + var i1 = _g11++; + var _g31 = 0; + var _g22 = surface.controlPoints[i1].length; + while(_g31 < _g22) { + var j1 = _g31++; + iduu = verb_core_Vec.norm(verb_core_Vec.add(dehomo[i1 + 2][j1],verb_core_Vec.add(verb_core_Vec.mul(-2.0,dehomo[i1 + 1][j1]),dehomo[i1][j1]))) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i1 + 2][j1]) - 2 * verb_core_ArrayExtensions.last(ts.controlPoints[i1 + 1][j1]) + verb_core_ArrayExtensions.last(ts.controlPoints[i1][j1])); + if(iduu > duu) duu = iduu; + } + } + var dvv = -Infinity; + var idvv; + var _g12 = 0; + var _g5 = surface.controlPoints.length; + while(_g12 < _g5) { + var i2 = _g12++; + var _g32 = 0; + var _g23 = surface.controlPoints[i2].length - 2; + while(_g32 < _g23) { + var j2 = _g32++; + idvv = verb_core_Vec.norm(verb_core_Vec.add(dehomo[i2][j2 + 2],verb_core_Vec.add(verb_core_Vec.mul(-2.0,dehomo[i2][j2 + 1]),dehomo[i2][j2]))) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2 + 2]) - 2 * verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2 + 1]) + verb_core_ArrayExtensions.last(ts.controlPoints[i2][j2])); + if(idvv > dvv) dvv = idvv; + } + } + var duv = -Infinity; + var iduv; + var _g13 = 0; + var _g6 = surface.controlPoints.length - 1; + while(_g13 < _g6) { + var i3 = _g13++; + var _g33 = 0; + var _g24 = surface.controlPoints[i3].length - 1; + while(_g33 < _g24) { + var j3 = _g33++; + iduv = verb_core_Vec.norm(verb_core_Vec.addAll([dehomo[i3 + 1][j3 + 1],verb_core_Vec.mul(-1.0,dehomo[i3][j3 + 1]),verb_core_Vec.mul(-1.0,dehomo[i3 + 1][j3]),dehomo[i3][j3]])) - (r - tol) * (verb_core_ArrayExtensions.last(ts.controlPoints[i3 + 1][j3 + 1]) - verb_core_ArrayExtensions.last(ts.controlPoints[i3][j3 + 1]) - verb_core_ArrayExtensions.last(ts.controlPoints[i3 + 1][j3]) + verb_core_ArrayExtensions.last(ts.controlPoints[i3][j3])); + if(iduv > duv) duv = iduv; + } + } + duu *= surface.degreeU * (surface.degreeU - 1); + dvv *= surface.degreeV * (surface.degreeV - 1); + duv *= surface.degreeU * surface.degreeV; + var minw = Infinity; + var w; + var _g14 = 0; + var _g7 = surface.controlPoints.length; + while(_g14 < _g7) { + var i4 = _g14++; + var _g34 = 0; + var _g25 = surface.controlPoints[i4].length; + while(_g34 < _g25) { + var j4 = _g34++; + w = verb_core_ArrayExtensions.last(surface.controlPoints[i4][j4]); + if(w < minw) minw = w; + } + } + var stepu; + var stepv; + if(Math.abs(duu) < verb_core_Constants.TOLERANCE) { + stepu = 1.0; + if(Math.abs(dvv) < verb_core_Constants.TOLERANCE) { + stepv = 1.0; + return new verb_core_Pair(stepu,stepv); + } + stepv = (Math.sqrt(duv * duv + 8 * dvv * tol * minw) - duv) / dvv; + } + if(Math.abs(dvv) < verb_core_Constants.TOLERANCE) { + stepv = 1.0; + stepu = (Math.sqrt(duv * duv + 8 * duu * tol * minw) - duv) / duu; + return new verb_core_Pair(stepu,stepv); + } + var unum; + var vnum; + var denom; + unum = 4 * dvv * tol * minw; + denom = duu * dvv + duv * Math.sqrt(duu * dvv); + stepu = Math.sqrt(unum / denom); + vnum = 4 * duu * tol * minw; + stepv = Math.sqrt(vnum / denom); + return new verb_core_Pair(stepu,stepv); +}; +verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { + if(includeU == null) includeU = false; + if(crv.degree == 1) { + var pts1 = []; + var _g1 = 0; + var _g = crv.controlPoints.length; + while(_g1 < _g) { + var i = _g1++; + pts1.push(verb_eval_Eval.dehomogenize(crv.controlPoints[i])); + } + if(includeU) { + var _g11 = 0; + var _g2 = crv.controlPoints.length; + while(_g11 < _g2) { + var i1 = _g11++; + pts1[i1].push(crv.knots[i1 + 1]); + } + } + return pts1; + } + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var beziers; + if(crv.knots.length == (crv.degree + 1) * 2) beziers = [crv]; else beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var brange; + var fraction; + var currentU = crv.knots[0]; + var step = range / divs; + var brange1; + var bsteps; + var nextU; + var _g12 = 0; + var _g3 = beziers.length; + while(_g12 < _g3) { + var i2 = _g12++; + brange1 = verb_core_ArrayExtensions.last(beziers[i2].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i2].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,currentU,step,bsteps + 1,includeU); + currentU = nextU + step; + } + return pts; +}; +verb_eval_Tess.rationalCurveAdaptiveSample = function(crv,tol,includeU) { + if(includeU == null) includeU = false; + if(crv.degree == 1) { + var pts1 = []; + var _g1 = 0; + var _g = crv.controlPoints.length; + while(_g1 < _g) { + var i = _g1++; + pts1.push(verb_eval_Eval.dehomogenize(crv.controlPoints[i])); + } + if(includeU) { + var _g11 = 0; + var _g2 = crv.controlPoints.length; + while(_g11 < _g2) { + var i1 = _g11++; + pts1[i1].push(crv.knots[i1 + 1]); + } + } + return pts1; + } + var beziers; + if(crv.knots.length == (crv.degree + 1) * 2) beziers = [crv]; else beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var steps; + var domain; + var len; + var _g12 = 0; + var _g3 = beziers.length; + while(_g12 < _g3) { + var i2 = _g12++; + domain = verb_core_ArrayExtensions.last(beziers[i2].knots) - beziers[i2].knots[0]; + len = verb_eval_Tess.rationalBezierCurveStepLength(beziers[i2],tol); + steps = Math.ceil(domain / len); + len = domain / steps; + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,beziers[i2].knots[0],len,steps + 1,includeU); + if(i2 == beziers.length - 1) break; + pts.pop(); + } + return pts; +}; +verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps,includeU) { + if(includeU == null) includeU = false; + var its = []; + var ts = [its]; + var u = startU; + var degree1 = crv.degree + 1; + if(numSteps <= crv.degree + 1) { + var _g = 0; + while(_g < numSteps) { + var i = _g++; + pts.push(verb_eval_Eval.rationalCurvePoint(crv,u)); + u += step; + } + return; + } + var _g1 = 0; + while(_g1 < degree1) { + var i1 = _g1++; + its.push(verb_eval_Eval.curvePoint(crv,u)); + u += step; + } + var prev; + var _g2 = 1; + while(_g2 < degree1) { + var i2 = _g2++; + its = []; + ts.push(its); + prev = ts[i2 - 1]; + var _g21 = 1; + var _g11 = prev.length; + while(_g21 < _g11) { + var j = _g21++; + its.push(verb_core_Vec.sub(prev[j],prev[j - 1])); + } + } + var _g3 = 0; + var _g12 = ts[0]; + while(_g3 < _g12.length) { + var pt = _g12[_g3]; + ++_g3; + pts.push(verb_eval_Eval.dehomogenize(pt)); + } + var front; + var _g4 = []; + var _g13 = 0; + while(_g13 < ts.length) { + var r = ts[_g13]; + ++_g13; + _g4.push(verb_core_ArrayExtensions.last(r)); + } + front = _g4; + var k; + var frlen2 = front.length - 2; + var _g22 = 0; + var _g14 = numSteps - degree1; + while(_g22 < _g14) { + var i3 = _g22++; + var _g41 = 0; + var _g31 = front.length - 1; + while(_g41 < _g31) { + var j1 = _g41++; + k = frlen2 - j1; + verb_core_Vec.addMutate(front[k],front[k + 1]); + } + pts.push(verb_eval_Eval.dehomogenize(front[0])); + } + u = startU; + if(includeU) { + var _g15 = 0; + while(_g15 < pts.length) { + var pt1 = pts[_g15]; + ++_g15; + pt1.push(u); + u += step; + } + } +}; +verb_eval_Tess.rationalBezierCurveStepLength = function(curve,tol) { + var dehomo = verb_eval_Eval.dehomogenize1d(curve.controlPoints); + var bb = new verb_core_BoundingBox(dehomo); + var avgPt = verb_core_Vec.mul(0.5,verb_core_Vec.add(bb.min,bb.max)); + var m = verb_core_Mat.identity(4); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + var tc = verb_eval_Modify.rationalCurveTransform(curve,m); + dehomo = verb_eval_Eval.dehomogenize1d(tc.controlPoints); + var r = 0.0; + var n; + var _g1 = 0; + var _g = dehomo.length; + while(_g1 < _g) { + var i = _g1++; + n = verb_core_Vec.norm(dehomo[i]); + if(n > r) r = n; + } + var wts = verb_eval_Eval.weight1d(curve.controlPoints); + var w = verb_core_Vec.min(wts); + var domain = verb_core_ArrayExtensions.last(curve.knots) - curve.knots[0]; + if(tol < r) { + var numer = 8 * w * tol; + var ws = verb_eval_Tess.secondForwardDiff(wts); + var pts = verb_eval_Tess.secondForwardDiff2(dehomo); + var fs; + var _g2 = []; + var _g21 = 0; + var _g11 = pts.length; + while(_g21 < _g11) { + var i1 = _g21++; + _g2.push(verb_core_Vec.norm(pts[i1]) + (r - tol) * ws[i1]); + } + fs = _g2; + var f = verb_core_Vec.max(fs); + var denom = curve.degree * (curve.degree - 1.0) * f; + return domain * Math.sqrt(numer / denom); + } else if(r >= tol && tol < 2.0 * r) { + var numer1 = 8 * w * tol; + var pts1 = verb_eval_Tess.secondForwardDiff2(dehomo); + var fs1; + var _g3 = []; + var _g22 = 0; + var _g12 = pts1.length; + while(_g22 < _g12) { + var i2 = _g22++; + _g3.push(verb_core_Vec.norm(pts1[i2])); + } + fs1 = _g3; + var f1 = verb_core_Vec.max(fs1); + var denom1 = curve.degree * (curve.degree - 1.0) * f1; + return domain * Math.sqrt(numer1 / denom1); + } else return domain; +}; +verb_eval_Tess.secondForwardDiff = function(array) { + var i = 0; + var res = []; + while(i < array.length - 2) { + res.push(array[i + 2] - 2.0 * array[i + 1] + array[i]); + i++; + } + return res; +}; +verb_eval_Tess.secondForwardDiff2 = function(array) { + var i = 0; + var res = []; + while(i < array.length - 2) { + res.push(verb_core_Vec.add(array[i + 2],verb_core_Vec.add(verb_core_Vec.mul(-2.0,array[i + 1]),array[i]))); + i++; + } + return res; +}; +verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { + if(divs_u < 1) divs_u = 1; + if(divs_v < 1) divs_v = 1; + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var u_span = verb_core_ArrayExtensions.last(knotsU) - knotsU[0]; + var v_span = verb_core_ArrayExtensions.last(knotsV) - knotsV[0]; + var span_u = u_span / divs_u; + var span_v = v_span / divs_v; + var points = []; + var uvs = []; + var normals = []; + var _g1 = 0; + var _g = divs_u + 1; + while(_g1 < _g) { + var i = _g1++; + var _g3 = 0; + var _g2 = divs_v + 1; + while(_g3 < _g2) { + var j = _g3++; + var pt_u = knotsU[0] + i * span_u; + var pt_v = knotsV[0] + j * span_v; + uvs.push([pt_u,pt_v]); + var derivs = verb_eval_Eval.rationalSurfaceDerivatives(surface,pt_u,pt_v,1); + var pt = derivs[0][0]; + points.push(pt); + var normal = verb_core_Vec.normalized(verb_core_Vec.cross(derivs[1][0],derivs[0][1])); + normals.push(normal); + } + } + var faces = []; + var _g4 = 0; + while(_g4 < divs_u) { + var i1 = _g4++; + var _g11 = 0; + while(_g11 < divs_v) { + var j1 = _g11++; + var a_i = i1 * (divs_v + 1) + j1; + var b_i = (i1 + 1) * (divs_v + 1) + j1; + var c_i = b_i + 1; + var d_i = a_i + 1; + var abc = [a_i,b_i,c_i]; + var acd = [a_i,c_i,d_i]; + faces.push(abc); + faces.push(acd); + } + } + return new verb_core_MeshData(faces,points,normals,uvs); +}; +verb_eval_Tess.divideRationalSurfaceAdaptive = function(surface,options) { + if(options == null) options = new verb_eval_AdaptiveRefinementOptions(); + if(options.minDivsU != null) options.minDivsU = options.minDivsU; else options.minDivsU = 1; + if(options.minDivsV != null) options.minDivsU = options.minDivsV; else options.minDivsU = 1; + if(options.refine != null) options.refine = options.refine; else options.refine = true; + var minU = (surface.controlPoints.length - 1) * 2; + var minV = (surface.controlPoints[0].length - 1) * 2; + var divsU; + if(options.minDivsU > minU) divsU = options.minDivsU = options.minDivsU; else divsU = options.minDivsU = minU; + var divsV; + if(options.minDivsV > minV) divsV = options.minDivsV = options.minDivsV; else divsV = options.minDivsV = minV; + var umax = verb_core_ArrayExtensions.last(surface.knotsU); + var umin = surface.knotsU[0]; + var vmax = verb_core_ArrayExtensions.last(surface.knotsV); + var vmin = surface.knotsV[0]; + var du = (umax - umin) / divsU; + var dv = (vmax - vmin) / divsV; + var divs = []; + var pts = []; + var _g1 = 0; + var _g = divsV + 1; + while(_g1 < _g) { + var i = _g1++; + var ptrow = []; + var _g3 = 0; + var _g2 = divsU + 1; + while(_g3 < _g2) { + var j = _g3++; + var u = umin + du * j; + var v = vmin + dv * i; + var ds = verb_eval_Eval.rationalSurfaceDerivatives(surface,u,v,1); + var norm = verb_core_Vec.normalized(verb_core_Vec.cross(ds[0][1],ds[1][0])); + ptrow.push(new verb_core_SurfacePoint(ds[0][0],norm,[u,v],-1,verb_core_Vec.isZero(norm))); + } + pts.push(ptrow); + } + var _g4 = 0; + while(_g4 < divsV) { + var i1 = _g4++; + var _g11 = 0; + while(_g11 < divsU) { + var j1 = _g11++; + var corners = [pts[divsV - i1 - 1][j1],pts[divsV - i1 - 1][j1 + 1],pts[divsV - i1][j1 + 1],pts[divsV - i1][j1]]; + divs.push(new verb_eval_AdaptiveRefinementNode(surface,corners)); + } + } + if(!options.refine) return divs; + var _g5 = 0; + while(_g5 < divsV) { + var i2 = _g5++; + var _g12 = 0; + while(_g12 < divsU) { + var j2 = _g12++; + var ci = i2 * divsU + j2; + var n = verb_eval_Tess.north(ci,i2,j2,divsU,divsV,divs); + var e = verb_eval_Tess.east(ci,i2,j2,divsU,divsV,divs); + var s = verb_eval_Tess.south(ci,i2,j2,divsU,divsV,divs); + var w = verb_eval_Tess.west(ci,i2,j2,divsU,divsV,divs); + divs[ci].neighbors = [s,e,n,w]; + divs[ci].divide(options); + } + } + return divs; +}; +verb_eval_Tess.north = function(index,i,j,divsU,divsV,divs) { + if(i == 0) return null; + return divs[index - divsU]; +}; +verb_eval_Tess.south = function(index,i,j,divsU,divsV,divs) { + if(i == divsV - 1) return null; + return divs[index + divsU]; +}; +verb_eval_Tess.east = function(index,i,j,divsU,divsV,divs) { + if(j == divsU - 1) return null; + return divs[index + 1]; +}; +verb_eval_Tess.west = function(index,i,j,divsU,divsV,divs) { + if(j == 0) return null; + return divs[index - 1]; +}; +verb_eval_Tess.triangulateAdaptiveRefinementNodeTree = function(arrTree) { + var mesh = verb_core_MeshData.empty(); + var _g = 0; + while(_g < arrTree.length) { + var x = arrTree[_g]; + ++_g; + x.triangulate(mesh); + } + return mesh; +}; +verb_eval_Tess.rationalSurfaceAdaptive = function(surface,options) { + if(options != null) options = options; else options = new verb_eval_AdaptiveRefinementOptions(); + var arrTrees = verb_eval_Tess.divideRationalSurfaceAdaptive(surface,options); + return verb_eval_Tess.triangulateAdaptiveRefinementNodeTree(arrTrees); +}; +verb_eval_Tess.rationalSurfaceRegularSample = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSample(surface,divsU,divsV)); +}; +verb_eval_Tess.surfaceRegularSample = function(surface,divsU,divsV) { + var degreeU = surface.degreeU; + var degreeV = surface.degreeV; + var controlPoints = surface.controlPoints; + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + var dim = controlPoints[0][0].length; + var spanU = (verb_core_ArrayExtensions.last(knotsU) - knotsU[0]) / divsU; + var spanV = (verb_core_ArrayExtensions.last(knotsV) - knotsV[0]) / divsV; + var knotSpansBasesU = verb_eval_Eval.regularlySpacedBasisFunctions(degreeU,knotsU,divsU); + var knotSpansU = knotSpansBasesU.item0; + var basesU = knotSpansBasesU.item1; + var knotSpansBasesV = verb_eval_Eval.regularlySpacedBasisFunctions(degreeV,knotsV,divsV); + var knotSpansV = knotSpansBasesV.item0; + var basesV = knotSpansBasesV.item1; + var pts = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var _g = 0; + while(_g < divsU1) { + var i = _g++; + var ptsi = []; + pts.push(ptsi); + var _g1 = 0; + while(_g1 < divsV1) { + var j = _g1++; + ptsi.push(verb_eval_Eval.surfacePointGivenBasesKnotSpans(degreeU,degreeV,controlPoints,knotSpansU[i],knotSpansV[j],basesU[i],basesV[j],dim)); + } + } + return pts; +}; +verb_eval_Tess.surfaceRegularSample2 = function(surface,divsU,divsV) { + var pts = []; + var u = surface.knotsU[0]; + var t = (verb_core_ArrayExtensions.last(surface.knotsU) - surface.knotsU[0]) / divsU; + var _g = 0; + while(_g < divsU) { + var i = _g++; + var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); + pts.push(verb_eval_Tess.rationalCurveRegularSample(iso,divsV)); + u += t; + } + return pts; +}; +var verb_eval_AdaptiveRefinementOptions = $hx_exports.core.AdaptiveRefinementOptions = function() { + this.minDivsV = 1; + this.minDivsU = 1; + this.refine = true; + this.maxDepth = 10; + this.minDepth = 0; + this.normTol = 2.5e-2; +}; +$hxClasses["verb.eval.AdaptiveRefinementOptions"] = verb_eval_AdaptiveRefinementOptions; +verb_eval_AdaptiveRefinementOptions.__name__ = ["verb","eval","AdaptiveRefinementOptions"]; +verb_eval_AdaptiveRefinementOptions.prototype = { + __class__: verb_eval_AdaptiveRefinementOptions +}; +var verb_eval_AdaptiveRefinementNode = $hx_exports.core.AdaptiveRefinementNode = function(srf,corners,neighbors) { + this.srf = srf; + if(neighbors == null) this.neighbors = [null,null,null,null]; else this.neighbors = neighbors; + this.corners = corners; + if(this.corners == null) { + var u0 = srf.knotsU[0]; + var u1 = verb_core_ArrayExtensions.last(srf.knotsU); + var v0 = srf.knotsV[0]; + var v1 = verb_core_ArrayExtensions.last(srf.knotsV); + this.corners = [verb_core_SurfacePoint.fromUv(u0,v0),verb_core_SurfacePoint.fromUv(u1,v0),verb_core_SurfacePoint.fromUv(u1,v1),verb_core_SurfacePoint.fromUv(u0,v1)]; + } +}; +$hxClasses["verb.eval.AdaptiveRefinementNode"] = verb_eval_AdaptiveRefinementNode; +verb_eval_AdaptiveRefinementNode.__name__ = ["verb","eval","AdaptiveRefinementNode"]; +verb_eval_AdaptiveRefinementNode.prototype = { + isLeaf: function() { + return this.children == null; + } + ,center: function() { + if(this.centerPoint != null) return this.centerPoint; else return this.evalSrf(this.u05,this.v05); + } + ,evalCorners: function() { + this.u05 = (this.corners[0].uv[0] + this.corners[2].uv[0]) / 2; + this.v05 = (this.corners[0].uv[1] + this.corners[2].uv[1]) / 2; + var _g = 0; + while(_g < 4) { + var i = _g++; + if(this.corners[i].point == null) { + var c = this.corners[i]; + this.evalSrf(c.uv[0],c.uv[1],c); + } + } + } + ,evalSrf: function(u,v,srfPt) { + var derivs = verb_eval_Eval.rationalSurfaceDerivatives(this.srf,u,v,1); + var pt = derivs[0][0]; + var norm = verb_core_Vec.cross(derivs[0][1],derivs[1][0]); + var degen = verb_core_Vec.isZero(norm); + if(!degen) norm = verb_core_Vec.normalized(norm); + if(srfPt != null) { + srfPt.degen = degen; + srfPt.point = pt; + srfPt.normal = norm; + return srfPt; + } else return new verb_core_SurfacePoint(pt,norm,[u,v],-1,degen); + } + ,getEdgeCorners: function(edgeIndex) { + if(this.isLeaf()) return [this.corners[edgeIndex]]; + if(this.horizontal) switch(edgeIndex) { + case 0: + return this.children[0].getEdgeCorners(0); + case 1: + return this.children[0].getEdgeCorners(1).concat(this.children[1].getEdgeCorners(1)); + case 2: + return this.children[1].getEdgeCorners(2); + case 3: + return this.children[1].getEdgeCorners(3).concat(this.children[0].getEdgeCorners(3)); + } + switch(edgeIndex) { + case 0: + return this.children[0].getEdgeCorners(0).concat(this.children[1].getEdgeCorners(0)); + case 1: + return this.children[1].getEdgeCorners(1); + case 2: + return this.children[1].getEdgeCorners(2).concat(this.children[0].getEdgeCorners(2)); + case 3: + return this.children[0].getEdgeCorners(3); + } + return null; + } + ,getAllCorners: function(edgeIndex) { + var baseArr = [this.corners[edgeIndex]]; + if(this.neighbors[edgeIndex] == null) return baseArr; + var corners = this.neighbors[edgeIndex].getEdgeCorners((edgeIndex + 2) % 4); + var funcIndex = edgeIndex % 2; + var e = verb_core_Constants.EPSILON; + var that = this; + var rangeFuncMap = [function(c) { + return c.uv[0] > that.corners[0].uv[0] + e && c.uv[0] < that.corners[2].uv[0] - e; + },function(c1) { + return c1.uv[1] > that.corners[0].uv[1] + e && c1.uv[1] < that.corners[2].uv[1] - e; + }]; + var cornercopy = corners.filter(rangeFuncMap[funcIndex]); + cornercopy.reverse(); + return baseArr.concat(cornercopy); + } + ,midpoint: function(index) { + if(this.midPoints == null) this.midPoints = [null,null,null,null]; + if(!(this.midPoints[index] == null)) return this.midPoints[index]; + switch(index) { + case 0: + this.midPoints[0] = this.evalSrf(this.u05,this.corners[0].uv[1]); + break; + case 1: + this.midPoints[1] = this.evalSrf(this.corners[1].uv[0],this.v05); + break; + case 2: + this.midPoints[2] = this.evalSrf(this.u05,this.corners[2].uv[1]); + break; + case 3: + this.midPoints[3] = this.evalSrf(this.corners[0].uv[0],this.v05); + break; + } + return this.midPoints[index]; + } + ,hasBadNormals: function() { + return this.corners[0].degen || this.corners[1].degen || this.corners[2].degen || this.corners[3].degen; + } + ,fixNormals: function() { + var l = this.corners.length; + var _g = 0; + while(_g < l) { + var i = _g++; + var corn = this.corners[i]; + if(this.corners[i].degen) { + var v1 = this.corners[(i + 1) % l]; + var v2 = this.corners[(i + 3) % l]; + if(v1.degen) this.corners[i].normal = v2.normal; else this.corners[i].normal = v1.normal; + } + } + } + ,shouldDivide: function(options,currentDepth) { + if(currentDepth < options.minDepth) return true; + if(currentDepth >= options.maxDepth) return false; + if(this.hasBadNormals()) { + this.fixNormals(); + return false; + } + this.splitVert = verb_core_Vec.normSquared(verb_core_Vec.sub(this.corners[0].normal,this.corners[1].normal)) > options.normTol || verb_core_Vec.normSquared(verb_core_Vec.sub(this.corners[2].normal,this.corners[3].normal)) > options.normTol; + this.splitHoriz = verb_core_Vec.normSquared(verb_core_Vec.sub(this.corners[1].normal,this.corners[2].normal)) > options.normTol || verb_core_Vec.normSquared(verb_core_Vec.sub(this.corners[3].normal,this.corners[0].normal)) > options.normTol; + if(this.splitVert || this.splitHoriz) return true; + var center = this.center(); + return verb_core_Vec.normSquared(verb_core_Vec.sub(center.normal,this.corners[0].normal)) > options.normTol || verb_core_Vec.normSquared(verb_core_Vec.sub(center.normal,this.corners[1].normal)) > options.normTol || verb_core_Vec.normSquared(verb_core_Vec.sub(center.normal,this.corners[2].normal)) > options.normTol || verb_core_Vec.normSquared(verb_core_Vec.sub(center.normal,this.corners[3].normal)) > options.normTol; + } + ,divide: function(options) { + if(options == null) options = new verb_eval_AdaptiveRefinementOptions(); + if(options.normTol == null) options.normTol = 8.5e-2; + if(options.minDepth == null) options.minDepth = 0; + if(options.maxDepth == null) options.maxDepth = 10; + this._divide(options,0,true); + } + ,_divide: function(options,currentDepth,horiz) { + this.evalCorners(); + if(!this.shouldDivide(options,currentDepth)) return; + currentDepth++; + if(this.splitVert && !this.splitHoriz) horiz = false; else if(!this.splitVert && this.splitHoriz) horiz = true; + this.horizontal = horiz; + if(this.horizontal) { + var bott = [this.corners[0],this.corners[1],this.midpoint(1),this.midpoint(3)]; + var top = [this.midpoint(3),this.midpoint(1),this.corners[2],this.corners[3]]; + this.children = [new verb_eval_AdaptiveRefinementNode(this.srf,bott),new verb_eval_AdaptiveRefinementNode(this.srf,top)]; + this.children[0].neighbors = [this.neighbors[0],this.neighbors[1],this.children[1],this.neighbors[3]]; + this.children[1].neighbors = [this.children[0],this.neighbors[1],this.neighbors[2],this.neighbors[3]]; + } else { + var left = [this.corners[0],this.midpoint(0),this.midpoint(2),this.corners[3]]; + var right = [this.midpoint(0),this.corners[1],this.corners[2],this.midpoint(2)]; + this.children = [new verb_eval_AdaptiveRefinementNode(this.srf,left),new verb_eval_AdaptiveRefinementNode(this.srf,right)]; + this.children[0].neighbors = [this.neighbors[0],this.children[1],this.neighbors[2],this.neighbors[3]]; + this.children[1].neighbors = [this.neighbors[0],this.neighbors[1],this.neighbors[2],this.children[0]]; + } + var _g = 0; + var _g1 = this.children; + while(_g < _g1.length) { + var child = _g1[_g]; + ++_g; + child._divide(options,currentDepth,!horiz); + } + } + ,triangulate: function(mesh) { + if(mesh == null) mesh = verb_core_MeshData.empty(); + if(this.isLeaf()) return this.triangulateLeaf(mesh); + var _g = 0; + var _g1 = this.children; + while(_g < _g1.length) { + var x = _g1[_g]; + ++_g; + if(x == null) break; + x.triangulate(mesh); + } + return mesh; + } + ,triangulateLeaf: function(mesh) { + var baseIndex = mesh.points.length; + var uvs = []; + var ids = []; + var splitid = 0; + var _g = 0; + while(_g < 4) { + var i1 = _g++; + var edgeCorners = this.getAllCorners(i1); + if(edgeCorners.length == 2) splitid = i1 + 1; + var _g2 = 0; + var _g1 = edgeCorners.length; + while(_g2 < _g1) { + var j1 = _g2++; + uvs.push(edgeCorners[j1]); + } + } + var _g3 = 0; + while(_g3 < uvs.length) { + var corner = uvs[_g3]; + ++_g3; + if(corner.id != -1) { + ids.push(corner.id); + continue; + } + mesh.uvs.push(corner.uv); + mesh.points.push(corner.point); + mesh.normals.push(corner.normal); + corner.id = baseIndex; + ids.push(baseIndex); + baseIndex++; + } + if(uvs.length == 4) { + mesh.faces.push([ids[0],ids[3],ids[1]]); + mesh.faces.push([ids[3],ids[2],ids[1]]); + return mesh; + } else if(uvs.length == 5) { + var il = ids.length; + mesh.faces.push([ids[splitid],ids[(splitid + 2) % il],ids[(splitid + 1) % il]]); + mesh.faces.push([ids[(splitid + 4) % il],ids[(splitid + 3) % il],ids[splitid]]); + mesh.faces.push([ids[splitid],ids[(splitid + 3) % il],ids[(splitid + 2) % il]]); + return mesh; + } + var center = this.center(); + mesh.uvs.push(center.uv); + mesh.points.push(center.point); + mesh.normals.push(center.normal); + var centerIndex = mesh.points.length - 1; + var i = 0; + var j = uvs.length - 1; + while(i < uvs.length) { + mesh.faces.push([centerIndex,ids[i],ids[j]]); + j = i++; + } + return mesh; + } + ,__class__: verb_eval_AdaptiveRefinementNode +}; +var verb_exe_Dispatcher = $hx_exports.exe.Dispatcher = function() { }; +$hxClasses["verb.exe.Dispatcher"] = verb_exe_Dispatcher; +verb_exe_Dispatcher.__name__ = ["verb","exe","Dispatcher"]; +verb_exe_Dispatcher.init = function() { + if(verb_exe_Dispatcher._init) return; + verb_exe_Dispatcher._workerPool = new verb_exe_WorkerPool(verb_exe_Dispatcher.THREADS); + verb_exe_Dispatcher._init = true; +}; +verb_exe_Dispatcher.dispatchMethod = function(classType,methodName,args) { + verb_exe_Dispatcher.init(); + var def = new promhx_Deferred(); + var callback = function(x) { + def.resolve(x); + }; + verb_exe_Dispatcher._workerPool.addWork(Type.getClassName(classType),methodName,args,callback); + return new promhx_Promise(def); +}; +var verb_exe_WorkerPool = $hx_exports.exe.WorkerPool = function(numThreads,fileName) { + if(fileName == null) fileName = "verb.js"; + if(numThreads == null) numThreads = 1; + this._callbacks = new haxe_ds_IntMap(); + this._working = new haxe_ds_IntMap(); + this._pool = []; + this._queue = []; + var _g = 0; + while(_g < numThreads) { + var i = _g++; + var w; + try { + w = new Worker(verb_exe_WorkerPool.basePath + fileName); + } catch( e ) { + if (e instanceof js__$Boot_HaxeError) e = e.val; + w = new Worker(verb_exe_WorkerPool.basePath + fileName.substring(0,-3) + ".min.js"); + } + this._pool.push(w); + } +}; +$hxClasses["verb.exe.WorkerPool"] = verb_exe_WorkerPool; +verb_exe_WorkerPool.__name__ = ["verb","exe","WorkerPool"]; +verb_exe_WorkerPool.prototype = { + addWork: function(className,methodName,args,callback) { + var work = new verb_exe__$WorkerPool_Work(className,methodName,args); + this._callbacks.set(work.id,callback); + this._queue.push(work); + this.processQueue(); + } + ,processQueue: function() { + var _g = this; + while(this._queue.length > 0 && this._pool.length > 0) { + var work = this._queue.shift(); + var workId = [work.id]; + var worker = [this._pool.shift()]; + this._working.h[workId[0]] = worker[0]; + worker[0].onmessage = (function(worker,workId) { + return function(e) { + _g._working.remove(workId[0]); + _g._pool.push(worker[0]); + try { + if(_g._callbacks.h.hasOwnProperty(workId[0])) { + _g._callbacks.h[workId[0]](e.data.result); + _g._callbacks.remove(workId[0]); + } + } catch( error ) { + if (error instanceof js__$Boot_HaxeError) error = error.val; + console.log(error); + } + _g.processQueue(); + }; + })(worker,workId); + worker[0].postMessage(work); + } + } + ,__class__: verb_exe_WorkerPool +}; +var verb_exe__$WorkerPool_Work = function(className,methodName,args) { + this.className = className; + this.methodName = methodName; + this.args = args; + this.id = verb_exe__$WorkerPool_Work.uuid++; +}; +$hxClasses["verb.exe._WorkerPool.Work"] = verb_exe__$WorkerPool_Work; +verb_exe__$WorkerPool_Work.__name__ = ["verb","exe","_WorkerPool","Work"]; +verb_exe__$WorkerPool_Work.prototype = { + __class__: verb_exe__$WorkerPool_Work +}; +var verb_geom_ICurve = function() { }; +$hxClasses["verb.geom.ICurve"] = verb_geom_ICurve; +verb_geom_ICurve.__name__ = ["verb","geom","ICurve"]; +verb_geom_ICurve.__interfaces__ = [verb_core_ISerializable]; +verb_geom_ICurve.prototype = { + __class__: verb_geom_ICurve +}; +var verb_geom_NurbsCurve = $hx_exports.geom.NurbsCurve = function(data) { + this._data = verb_eval_Check.isValidNurbsCurveData(data); +}; +$hxClasses["verb.geom.NurbsCurve"] = verb_geom_NurbsCurve; +verb_geom_NurbsCurve.__name__ = ["verb","geom","NurbsCurve"]; +verb_geom_NurbsCurve.__interfaces__ = [verb_geom_ICurve]; +verb_geom_NurbsCurve.byKnotsControlPointsWeights = function(degree,knots,controlPoints,weights) { + return new verb_geom_NurbsCurve(new verb_core_NurbsCurveData(degree,knots.slice(),verb_eval_Eval.homogenize1d(controlPoints,weights))); +}; +verb_geom_NurbsCurve.byPoints = function(points,degree) { + if(degree == null) degree = 3; + return new verb_geom_NurbsCurve(verb_eval_Make.rationalInterpCurve(points,degree)); +}; +verb_geom_NurbsCurve.__super__ = verb_core_SerializableBase; +verb_geom_NurbsCurve.prototype = $extend(verb_core_SerializableBase.prototype,{ + degree: function() { + return this._data.degree; + } + ,knots: function() { + return this._data.knots.slice(0); + } + ,controlPoints: function() { + return verb_eval_Eval.dehomogenize1d(this._data.controlPoints); + } + ,weights: function() { + return verb_eval_Eval.weight1d(this._data.controlPoints); + } + ,asNurbs: function() { + return new verb_core_NurbsCurveData(this.degree(),this.knots(),verb_eval_Eval.homogenize1d(this.controlPoints(),this.weights())); + } + ,clone: function() { + return new verb_geom_NurbsCurve(this._data); + } + ,domain: function() { + return new verb_core_Interval(verb_core_ArrayExtensions.first(this._data.knots),verb_core_ArrayExtensions.last(this._data.knots)); + } + ,transform: function(mat) { + return new verb_geom_NurbsCurve(verb_eval_Modify.rationalCurveTransform(this._data,mat)); + } + ,transformAsync: function(mat) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Modify,"rationalCurveTransform",[this._data,mat]).then(function(x) { + return new verb_geom_NurbsCurve(x); + }); + } + ,point: function(u) { + return verb_eval_Eval.rationalCurvePoint(this._data,u); + } + ,pointAsync: function(u) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Eval,"rationalCurvePoint",[this._data,u]); + } + ,tangent: function(u) { + return verb_eval_Eval.rationalCurveTangent(this._data,u); + } + ,tangentAsync: function(u) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Eval,"rationalCurveTangent",[this._data,u]); + } + ,derivatives: function(u,numDerivs) { + if(numDerivs == null) numDerivs = 1; + return verb_eval_Eval.rationalCurveDerivatives(this._data,u,numDerivs); + } + ,derivativesAsync: function(u,numDerivs) { + if(numDerivs == null) numDerivs = 1; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Eval,"rationalCurveDerivatives",[this._data,u,numDerivs]); + } + ,closestPoint: function(pt) { + return verb_eval_Analyze.rationalCurveClosestPoint(this._data,pt); + } + ,closestPointAsync: function(pt) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalCurveClosestPoint",[this._data,pt]); + } + ,closestParam: function(pt) { + return verb_eval_Analyze.rationalCurveClosestParam(this._data,pt); + } + ,closestParamAsync: function(pt) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalCurveClosestParam",[this._data,pt]); + } + ,length: function() { + return verb_eval_Analyze.rationalCurveArcLength(this._data); + } + ,lengthAsync: function() { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalCurveArcLength",[this._data]); + } + ,lengthAtParam: function(u) { + return verb_eval_Analyze.rationalCurveArcLength(this._data,u); + } + ,lengthAtParamAsync: function() { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalCurveArcLength",[this._data]); + } + ,paramAtLength: function(len,tolerance) { + return verb_eval_Analyze.rationalCurveParamAtArcLength(this._data,len,tolerance); + } + ,paramAtLengthAsync: function(len,tolerance) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalCurveParamAtArcLength",[this._data,len,tolerance]); + } + ,divideByEqualArcLength: function(divisions) { + return verb_eval_Divide.rationalCurveByEqualArcLength(this._data,divisions); + } + ,divideByEqualArcLengthAsync: function(divisions) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Divide,"rationalCurveByEqualArcLength",[this._data,divisions]); + } + ,divideByArcLength: function(arcLength) { + return verb_eval_Divide.rationalCurveByArcLength(this._data,arcLength); + } + ,divideByArcLengthAsync: function(divisions) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Divide,"rationalCurveByArcLength",[this._data,divisions]); + } + ,split: function(u) { + return verb_eval_Divide.curveSplit(this._data,u).map(function(x) { + return new verb_geom_NurbsCurve(x); + }); + } + ,splitAsync: function(u) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Divide,"curveSplit",[this._data,u]).then(function(cs) { + return cs.map(function(x) { + return new verb_geom_NurbsCurve(x); + }); + }); + } + ,reverse: function() { + return new verb_geom_NurbsCurve(verb_eval_Modify.curveReverse(this._data)); + } + ,reverseAsync: function() { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Modify,"curveReverse",[this._data]).then(function(c) { + return new verb_geom_NurbsCurve(c); + }); + } + ,tessellate: function(tolerance) { + if(tolerance == null) tolerance = 1e-3; + return verb_eval_Tess.rationalCurveAdaptiveSample(this._data,tolerance,false); + } + ,tessellateAsync: function(tolerance) { + if(tolerance == null) tolerance = 1e-3; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Tess,"rationalCurveAdaptiveSample",[this._data,tolerance,false]); + } + ,__class__: verb_geom_NurbsCurve +}); +var verb_geom_Arc = $hx_exports.geom.Arc = function(center,xaxis,yaxis,radius,minAngle,maxAngle) { + verb_geom_NurbsCurve.call(this,verb_eval_Make.arc(center,xaxis,yaxis,radius,minAngle,maxAngle)); + this._center = center; + this._xaxis = xaxis; + this._yaxis = yaxis; + this._radius = radius; + this._minAngle = minAngle; + this._maxAngle = maxAngle; +}; +$hxClasses["verb.geom.Arc"] = verb_geom_Arc; +verb_geom_Arc.__name__ = ["verb","geom","Arc"]; +verb_geom_Arc.__super__ = verb_geom_NurbsCurve; +verb_geom_Arc.prototype = $extend(verb_geom_NurbsCurve.prototype,{ + center: function() { + return this._center; + } + ,xaxis: function() { + return this._xaxis; + } + ,yaxis: function() { + return this._yaxis; + } + ,radius: function() { + return this._radius; + } + ,minAngle: function() { + return this._minAngle; + } + ,maxAngle: function() { + return this._maxAngle; + } + ,__class__: verb_geom_Arc +}); +var verb_geom_BezierCurve = $hx_exports.geom.BezierCurve = function(points,weights) { + verb_geom_NurbsCurve.call(this,verb_eval_Make.rationalBezierCurve(points,weights)); +}; +$hxClasses["verb.geom.BezierCurve"] = verb_geom_BezierCurve; +verb_geom_BezierCurve.__name__ = ["verb","geom","BezierCurve"]; +verb_geom_BezierCurve.__super__ = verb_geom_NurbsCurve; +verb_geom_BezierCurve.prototype = $extend(verb_geom_NurbsCurve.prototype,{ + __class__: verb_geom_BezierCurve +}); +var verb_geom_Circle = $hx_exports.geom.Circle = function(center,xaxis,yaxis,radius) { + verb_geom_Arc.call(this,center,xaxis,yaxis,radius,0,Math.PI * 2); +}; +$hxClasses["verb.geom.Circle"] = verb_geom_Circle; +verb_geom_Circle.__name__ = ["verb","geom","Circle"]; +verb_geom_Circle.__super__ = verb_geom_Arc; +verb_geom_Circle.prototype = $extend(verb_geom_Arc.prototype,{ + __class__: verb_geom_Circle +}); +var verb_geom_ISurface = function() { }; +$hxClasses["verb.geom.ISurface"] = verb_geom_ISurface; +verb_geom_ISurface.__name__ = ["verb","geom","ISurface"]; +verb_geom_ISurface.__interfaces__ = [verb_core_ISerializable]; +verb_geom_ISurface.prototype = { + __class__: verb_geom_ISurface +}; +var verb_geom_NurbsSurface = $hx_exports.geom.NurbsSurface = function(data) { + this._data = verb_eval_Check.isValidNurbsSurfaceData(data); +}; +$hxClasses["verb.geom.NurbsSurface"] = verb_geom_NurbsSurface; +verb_geom_NurbsSurface.__name__ = ["verb","geom","NurbsSurface"]; +verb_geom_NurbsSurface.__interfaces__ = [verb_geom_ISurface]; +verb_geom_NurbsSurface.byKnotsControlPointsWeights = function(degreeU,degreeV,knotsU,knotsV,controlPoints,weights) { + return new verb_geom_NurbsSurface(new verb_core_NurbsSurfaceData(degreeU,degreeV,knotsU,knotsV,verb_eval_Eval.homogenize2d(controlPoints,weights))); +}; +verb_geom_NurbsSurface.byCorners = function(point0,point1,point2,point3) { + return new verb_geom_NurbsSurface(verb_eval_Make.fourPointSurface(point0,point1,point2,point3)); +}; +verb_geom_NurbsSurface.byLoftingCurves = function(curves,degreeV) { + return new verb_geom_NurbsSurface(verb_eval_Make.loftedSurface((function($this) { + var $r; + var _g = []; + { + var _g1 = 0; + while(_g1 < curves.length) { + var c = curves[_g1]; + ++_g1; + _g.push(c.asNurbs()); + } + } + $r = _g; + return $r; + }(this)),degreeV)); +}; +verb_geom_NurbsSurface.__super__ = verb_core_SerializableBase; +verb_geom_NurbsSurface.prototype = $extend(verb_core_SerializableBase.prototype,{ + degreeU: function() { + return this._data.degreeU; + } + ,degreeV: function() { + return this._data.degreeV; + } + ,knotsU: function() { + return this._data.knotsU.slice(0); + } + ,knotsV: function() { + return this._data.knotsV.slice(0); + } + ,controlPoints: function() { + return verb_eval_Eval.dehomogenize2d(this._data.controlPoints); + } + ,weights: function() { + return verb_eval_Eval.weight2d(this._data.controlPoints); + } + ,asNurbs: function() { + return new verb_core_NurbsSurfaceData(this.degreeU(),this.degreeV(),this.knotsU(),this.knotsV(),verb_eval_Eval.homogenize2d(this.controlPoints(),this.weights())); + } + ,clone: function() { + return new verb_geom_NurbsSurface(this.asNurbs()); + } + ,domainU: function() { + return new verb_core_Interval(verb_core_ArrayExtensions.first(this._data.knotsU),verb_core_ArrayExtensions.last(this._data.knotsU)); + } + ,domainV: function() { + return new verb_core_Interval(verb_core_ArrayExtensions.first(this._data.knotsV),verb_core_ArrayExtensions.last(this._data.knotsV)); + } + ,point: function(u,v) { + return verb_eval_Eval.rationalSurfacePoint(this._data,u,v); + } + ,pointAsync: function(u,v) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Eval,"rationalSurfacePoint",[this._data,u,v]); + } + ,normal: function(u,v) { + return verb_eval_Eval.rationalSurfaceNormal(this._data,u,v); + } + ,normalAsync: function(u,v) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Eval,"rationalSurfaceNormal",[this._data,u,v]); + } + ,derivatives: function(u,v,numDerivs) { + if(numDerivs == null) numDerivs = 1; + return verb_eval_Eval.rationalSurfaceDerivatives(this._data,u,v,numDerivs); + } + ,derivativesAsync: function(u,v,numDerivs) { + if(numDerivs == null) numDerivs = 1; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Eval,"rationalSurfaceDerivatives",[this._data,u,v,numDerivs]); + } + ,closestParam: function(pt) { + return verb_eval_Analyze.rationalSurfaceClosestParam(this._data,pt); + } + ,closestParamAsync: function(pt) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalSurfaceClosestParam",[this._data,pt]); + } + ,closestPoint: function(pt) { + return verb_eval_Analyze.rationalSurfaceClosestPoint(this._data,pt); + } + ,closestPointAsync: function(pt) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Analyze,"rationalSurfaceClosestPoint",[this._data,pt]); + } + ,split: function(u,useV) { + if(useV == null) useV = false; + return verb_eval_Divide.surfaceSplit(this._data,u,useV).map(function(x) { + return new verb_geom_NurbsSurface(x); + }); + } + ,splitAsync: function(u,useV) { + if(useV == null) useV = false; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Divide,"surfaceSplit",[this._data,u,useV]).then(function(s) { + return s.map(function(x) { + return new verb_geom_NurbsSurface(x); + }); + }); + } + ,reverse: function(useV) { + if(useV == null) useV = false; + return new verb_geom_NurbsSurface(verb_eval_Modify.surfaceReverse(this._data,useV)); + } + ,reverseAsync: function(useV) { + if(useV == null) useV = false; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Modify,"surfaceReverse",[this._data,useV]).then(function(c) { + return new verb_geom_NurbsSurface(c); + }); + } + ,isocurve: function(u,useV) { + if(useV == null) useV = false; + return new verb_geom_NurbsCurve(verb_eval_Make.surfaceIsocurve(this._data,u,useV)); + } + ,isocurveAsync: function(u,useV) { + if(useV == null) useV = false; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Make,"surfaceIsocurve",[this._data,u,useV]).then(function(x) { + return new verb_geom_NurbsCurve(x); + }); + } + ,boundaries: function(options) { + return verb_eval_Make.surfaceBoundaryCurves(this._data).map(function(x) { + return new verb_geom_NurbsCurve(x); + }); + } + ,boundariesAsync: function(options) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Make,"surfaceBoundaryCurves",[this._data]).then(function(cs) { + return cs.map(function(x) { + return new verb_geom_NurbsCurve(x); + }); + }); + } + ,tessellate: function(options) { + return verb_eval_Tess.rationalSurfaceAdaptive(this._data,options); + } + ,tessellateAsync: function(options) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Tess,"rationalSurfaceAdaptive",[this._data,options]); + } + ,transform: function(mat) { + return new verb_geom_NurbsSurface(verb_eval_Modify.rationalSurfaceTransform(this._data,mat)); + } + ,transformAsync: function(mat) { + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Modify,"rationalSurfaceTransform",[this._data,mat]).then(function(x) { + return new verb_geom_NurbsSurface(x); + }); + } + ,__class__: verb_geom_NurbsSurface +}); +var verb_geom_ConicalSurface = $hx_exports.geom.ConicalSurface = function(axis,xaxis,base,height,radius) { + verb_geom_NurbsSurface.call(this,verb_eval_Make.conicalSurface(axis,xaxis,base,height,radius)); + this._axis = axis; + this._xaxis = xaxis; + this._base = base; + this._height = height; + this._radius = radius; +}; +$hxClasses["verb.geom.ConicalSurface"] = verb_geom_ConicalSurface; +verb_geom_ConicalSurface.__name__ = ["verb","geom","ConicalSurface"]; +verb_geom_ConicalSurface.__super__ = verb_geom_NurbsSurface; +verb_geom_ConicalSurface.prototype = $extend(verb_geom_NurbsSurface.prototype,{ + axis: function() { + return this._axis; + } + ,xaxis: function() { + return this._xaxis; + } + ,base: function() { + return this._base; + } + ,height: function() { + return this._height; + } + ,radius: function() { + return this._radius; + } + ,__class__: verb_geom_ConicalSurface +}); +var verb_geom_CylindricalSurface = $hx_exports.geom.CylindricalSurface = function(axis,xaxis,base,height,radius) { + verb_geom_NurbsSurface.call(this,verb_eval_Make.cylindricalSurface(axis,xaxis,base,height,radius)); + this._axis = axis; + this._xaxis = xaxis; + this._base = base; + this._height = height; + this._radius = radius; +}; +$hxClasses["verb.geom.CylindricalSurface"] = verb_geom_CylindricalSurface; +verb_geom_CylindricalSurface.__name__ = ["verb","geom","CylindricalSurface"]; +verb_geom_CylindricalSurface.__super__ = verb_geom_NurbsSurface; +verb_geom_CylindricalSurface.prototype = $extend(verb_geom_NurbsSurface.prototype,{ + axis: function() { + return this._axis; + } + ,xaxis: function() { + return this._xaxis; + } + ,base: function() { + return this._base; + } + ,height: function() { + return this._height; + } + ,radius: function() { + return this._radius; + } + ,__class__: verb_geom_CylindricalSurface +}); +var verb_geom_EllipseArc = $hx_exports.geom.EllipseArc = function(center,xaxis,yaxis,minAngle,maxAngle) { + verb_geom_NurbsCurve.call(this,verb_eval_Make.ellipseArc(center,xaxis,yaxis,minAngle,maxAngle)); + this._center = center; + this._xaxis = xaxis; + this._yaxis = yaxis; + this._minAngle = minAngle; + this._maxAngle = maxAngle; +}; +$hxClasses["verb.geom.EllipseArc"] = verb_geom_EllipseArc; +verb_geom_EllipseArc.__name__ = ["verb","geom","EllipseArc"]; +verb_geom_EllipseArc.__super__ = verb_geom_NurbsCurve; +verb_geom_EllipseArc.prototype = $extend(verb_geom_NurbsCurve.prototype,{ + center: function() { + return this._center; + } + ,xaxis: function() { + return this._xaxis; + } + ,yaxis: function() { + return this._yaxis; + } + ,minAngle: function() { + return this._minAngle; + } + ,maxAngle: function() { + return this._maxAngle; + } + ,__class__: verb_geom_EllipseArc +}); +var verb_geom_Ellipse = $hx_exports.geom.Ellipse = function(center,xaxis,yaxis) { + verb_geom_EllipseArc.call(this,center,xaxis,yaxis,0,Math.PI * 2); +}; +$hxClasses["verb.geom.Ellipse"] = verb_geom_Ellipse; +verb_geom_Ellipse.__name__ = ["verb","geom","Ellipse"]; +verb_geom_Ellipse.__super__ = verb_geom_EllipseArc; +verb_geom_Ellipse.prototype = $extend(verb_geom_EllipseArc.prototype,{ + __class__: verb_geom_Ellipse +}); +var verb_geom_ExtrudedSurface = $hx_exports.geom.ExtrudedSurface = function(profile,direction) { + verb_geom_NurbsSurface.call(this,verb_eval_Make.extrudedSurface(verb_core_Vec.normalized(direction),verb_core_Vec.norm(direction),profile.asNurbs())); + this._profile = profile; + this._direction = direction; +}; +$hxClasses["verb.geom.ExtrudedSurface"] = verb_geom_ExtrudedSurface; +verb_geom_ExtrudedSurface.__name__ = ["verb","geom","ExtrudedSurface"]; +verb_geom_ExtrudedSurface.__super__ = verb_geom_NurbsSurface; +verb_geom_ExtrudedSurface.prototype = $extend(verb_geom_NurbsSurface.prototype,{ + profile: function() { + return this._profile; + } + ,direction: function() { + return this._direction; + } + ,__class__: verb_geom_ExtrudedSurface +}); +var verb_geom_Intersect = $hx_exports.geom.Intersect = function() { }; +$hxClasses["verb.geom.Intersect"] = verb_geom_Intersect; +verb_geom_Intersect.__name__ = ["verb","geom","Intersect"]; +verb_geom_Intersect.curves = function(first,second,tol) { + if(tol == null) tol = 1e-3; + return verb_eval_Intersect.curves(first.asNurbs(),second.asNurbs(),tol); +}; +verb_geom_Intersect.curvesAsync = function(first,second,tol) { + if(tol == null) tol = 1e-3; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Intersect,"curves",[first.asNurbs(),second.asNurbs(),tol]); +}; +verb_geom_Intersect.curveAndSurface = function(curve,surface,tol) { + if(tol == null) tol = 1e-3; + return verb_eval_Intersect.curveAndSurface(curve.asNurbs(),surface.asNurbs(),tol); +}; +verb_geom_Intersect.curveAndSurfaceAsync = function(curve,surface,tol) { + if(tol == null) tol = 1e-3; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Intersect,"curveAndSurface",[curve.asNurbs(),surface.asNurbs(),tol]); +}; +verb_geom_Intersect.surfaces = function(first,second,tol) { + if(tol == null) tol = 1e-3; + return verb_eval_Intersect.surfaces(first.asNurbs(),second.asNurbs(),tol).map(function(cd) { + return new verb_geom_NurbsCurve(cd); + }); +}; +verb_geom_Intersect.surfacesAsync = function(first,second,tol) { + if(tol == null) tol = 1e-3; + return verb_exe_Dispatcher.dispatchMethod(verb_eval_Intersect,"surfaces",[first.asNurbs(),second.asNurbs(),tol]).then(function(cds) { + return cds.map(function(cd) { + return new verb_geom_NurbsCurve(cd); + }); + }); +}; +var verb_geom_Line = $hx_exports.geom.Line = function(start,end) { + verb_geom_NurbsCurve.call(this,verb_eval_Make.polyline([start,end])); + this._start = start; + this._end = end; +}; +$hxClasses["verb.geom.Line"] = verb_geom_Line; +verb_geom_Line.__name__ = ["verb","geom","Line"]; +verb_geom_Line.__super__ = verb_geom_NurbsCurve; +verb_geom_Line.prototype = $extend(verb_geom_NurbsCurve.prototype,{ + start: function() { + return this._start; + } + ,end: function() { + return this._end; + } + ,__class__: verb_geom_Line +}); +var verb_geom_RevolvedSurface = $hx_exports.geom.RevolvedSurface = function(profile,center,axis,angle) { + verb_geom_NurbsSurface.call(this,verb_eval_Make.revolvedSurface(profile.asNurbs(),center,axis,angle)); + this._profile = profile; + this._center = center; + this._axis = axis; + this._angle = angle; +}; +$hxClasses["verb.geom.RevolvedSurface"] = verb_geom_RevolvedSurface; +verb_geom_RevolvedSurface.__name__ = ["verb","geom","RevolvedSurface"]; +verb_geom_RevolvedSurface.__super__ = verb_geom_NurbsSurface; +verb_geom_RevolvedSurface.prototype = $extend(verb_geom_NurbsSurface.prototype,{ + profile: function() { + return this._profile; + } + ,center: function() { + return this._center; + } + ,axis: function() { + return this._center; + } + ,angle: function() { + return this._angle; + } + ,__class__: verb_geom_RevolvedSurface +}); +var verb_geom_SphericalSurface = $hx_exports.geom.SphericalSurface = function(center,radius) { + verb_geom_NurbsSurface.call(this,verb_eval_Make.sphericalSurface(center,[0,0,1],[1,0,0],radius)); + this._center = center; + this._radius = radius; +}; +$hxClasses["verb.geom.SphericalSurface"] = verb_geom_SphericalSurface; +verb_geom_SphericalSurface.__name__ = ["verb","geom","SphericalSurface"]; +verb_geom_SphericalSurface.__super__ = verb_geom_NurbsSurface; +verb_geom_SphericalSurface.prototype = $extend(verb_geom_NurbsSurface.prototype,{ + center: function() { + return this._center; + } + ,radius: function() { + return this._radius; + } + ,__class__: verb_geom_SphericalSurface +}); +var verb_geom_SweptSurface = $hx_exports.geom.SweptSurface = function(profile,rail) { + verb_geom_NurbsSurface.call(this,verb_eval_Make.rationalTranslationalSurface(profile.asNurbs(),rail.asNurbs())); + this._profile = profile; + this._rail = rail; +}; +$hxClasses["verb.geom.SweptSurface"] = verb_geom_SweptSurface; +verb_geom_SweptSurface.__name__ = ["verb","geom","SweptSurface"]; +verb_geom_SweptSurface.__super__ = verb_geom_NurbsSurface; +verb_geom_SweptSurface.prototype = $extend(verb_geom_NurbsSurface.prototype,{ + profile: function() { + return this._profile; + } + ,rail: function() { + return this._rail; + } + ,__class__: verb_geom_SweptSurface +}); +function $iterator(o) { if( o instanceof Array ) return function() { return HxOverrides.iter(o); }; return typeof(o.iterator) == 'function' ? $bind(o,o.iterator) : o.iterator; } +var $_, $fid = 0; +function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; } +$hxClasses.Math = Math; +String.prototype.__class__ = $hxClasses.String = String; +String.__name__ = ["String"]; +$hxClasses.Array = Array; +Array.__name__ = ["Array"]; +Date.prototype.__class__ = $hxClasses.Date = Date; +Date.__name__ = ["Date"]; +var Int = $hxClasses.Int = { __name__ : ["Int"]}; +var Dynamic = $hxClasses.Dynamic = { __name__ : ["Dynamic"]}; +var Float = $hxClasses.Float = Number; +Float.__name__ = ["Float"]; +var Bool = $hxClasses.Bool = Boolean; +Bool.__ename__ = ["Bool"]; +var Class = $hxClasses.Class = { __name__ : ["Class"]}; +var Enum = { }; +if(Array.prototype.map == null) Array.prototype.map = function(f) { + var a = []; + var _g1 = 0; + var _g = this.length; + while(_g1 < _g) { + var i = _g1++; + a[i] = f(this[i]); + } + return a; +}; +if(Array.prototype.filter == null) Array.prototype.filter = function(f1) { + var a1 = []; + var _g11 = 0; + var _g2 = this.length; + while(_g11 < _g2) { + var i1 = _g11++; + var e = this[i1]; + if(f1(e)) a1.push(e); + } + return a1; +}; +var __map_reserved = {} +var ArrayBuffer = $global.ArrayBuffer || js_html_compat_ArrayBuffer; +if(ArrayBuffer.prototype.slice == null) ArrayBuffer.prototype.slice = js_html_compat_ArrayBuffer.sliceImpl; +var DataView = $global.DataView || js_html_compat_DataView; +var Uint8Array = $global.Uint8Array || js_html_compat_Uint8Array._new; +var global = window; +(function (global, undefined) { + "use strict"; + + if (global.setImmediate) { + return; + } + + var nextHandle = 1; // Spec says greater than zero + var tasksByHandle = {}; + var currentlyRunningATask = false; + var doc = global.document; + var setImmediate; + + function addFromSetImmediateArguments(args) { + tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args); + return nextHandle++; + } + + // This function accepts the same arguments as setImmediate, but + // returns a function that requires no arguments. + function partiallyApplied(handler) { + var args = [].slice.call(arguments, 1); + return function() { + if (typeof handler === "function") { + handler.apply(undefined, args); + } else { + (new Function("" + handler))(); + } + }; + } + + function runIfPresent(handle) { + // From the spec: "Wait until any invocations of this algorithm started before this one have completed." + // So if we're currently running a task, we'll need to delay this invocation. + if (currentlyRunningATask) { + // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a + // "too much recursion" error. + setTimeout(partiallyApplied(runIfPresent, handle), 0); + } else { + var task = tasksByHandle[handle]; + if (task) { + currentlyRunningATask = true; + try { + task(); + } finally { + clearImmediate(handle); + currentlyRunningATask = false; + } + } + } + } + + function clearImmediate(handle) { + delete tasksByHandle[handle]; + } + + function installNextTickImplementation() { + setImmediate = function() { + var handle = addFromSetImmediateArguments(arguments); + process.nextTick(partiallyApplied(runIfPresent, handle)); + return handle; + }; + } + + function canUsePostMessage() { + // The test against `importScripts` prevents this implementation from being installed inside a web worker, + // where `global.postMessage` means something completely different and can't be used for this purpose. + if (global.postMessage && !global.importScripts) { + var postMessageIsAsynchronous = true; + var oldOnMessage = global.onmessage; + global.onmessage = function() { + postMessageIsAsynchronous = false; + }; + global.postMessage("", "*"); + global.onmessage = oldOnMessage; + return postMessageIsAsynchronous; + } + } + + function installPostMessageImplementation() { + // Installs an event handler on `global` for the `message` event: see + // * https://developer.mozilla.org/en/DOM/window.postMessage + // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages + + var messagePrefix = "setImmediate$" + Math.random() + "$"; + var onGlobalMessage = function(event) { + if (event.source === global && + typeof event.data === "string" && + event.data.indexOf(messagePrefix) === 0) { + runIfPresent(+event.data.slice(messagePrefix.length)); + } + }; + + if (global.addEventListener) { + global.addEventListener("message", onGlobalMessage, false); + } else { + global.attachEvent("onmessage", onGlobalMessage); + } + + setImmediate = function() { + var handle = addFromSetImmediateArguments(arguments); + global.postMessage(messagePrefix + handle, "*"); + return handle; + }; + } + + function installMessageChannelImplementation() { + var channel = new MessageChannel(); + channel.port1.onmessage = function(event) { + var handle = event.data; + runIfPresent(handle); + }; + + setImmediate = function() { + var handle = addFromSetImmediateArguments(arguments); + channel.port2.postMessage(handle); + return handle; + }; + } + + function installReadyStateChangeImplementation() { + var html = doc.documentElement; + setImmediate = function() { + var handle = addFromSetImmediateArguments(arguments); + // Create a diff --git a/examples/curveStepLength.html b/examples/curveStepLength.html new file mode 100644 index 00000000..55ee0e8c --- /dev/null +++ b/examples/curveStepLength.html @@ -0,0 +1,71 @@ + + + + Curve step length + + + + + + + + + + + + + + + + + +
Show/Hide Code
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/examples/images/stone-wall.jpg b/examples/images/stone-wall.jpg new file mode 100644 index 00000000..96d04238 Binary files /dev/null and b/examples/images/stone-wall.jpg differ diff --git a/examples/js/threeBasic.js b/examples/js/threeBasic.js index ff80a55c..2a9c7a92 100644 --- a/examples/js/threeBasic.js +++ b/examples/js/threeBasic.js @@ -99,7 +99,7 @@ function addLineToScene(pts, mat){ } function addMeshToScene(mesh, material, wireframe ){ - material = material || new THREE.MeshNormalMaterial( { side: THREE.DoubleSide, wireframe: false, shading: THREE.SmoothShading, transparent: true, opacity: 0.4 } ) + material = material || new THREE.MeshNormalMaterial( { side: THREE.DoubleSide, wireframe: false, shading: THREE.SmoothShading, transparent: false, opacity: 0.0 } ) // new THREE.MeshPhongMaterial({ // specular: '#ffffff', diff --git a/examples/js/verbToThreeConversion.js b/examples/js/verbToThreeConversion.js index c2c68ab1..73c66d1d 100644 --- a/examples/js/verbToThreeConversion.js +++ b/examples/js/verbToThreeConversion.js @@ -24,7 +24,7 @@ function tessellateSurface(srf) { - var tess = srf.tessellate(); + var tess = srf.tessellate({ normTol : 0.0001 }); var geometry = new THREE.Geometry(); @@ -39,6 +39,8 @@ return new THREE.Face3(faceIndices[0],faceIndices[1],faceIndices[2], normals); }); + geometry.faces.push.apply(geometry.faces, threeFaces); + return geometry; } diff --git a/examples/surfaceBezierSubdivision.html b/examples/surfaceBezierSubdivision.html new file mode 100644 index 00000000..2b6b9d4b --- /dev/null +++ b/examples/surfaceBezierSubdivision.html @@ -0,0 +1,207 @@ + + + + Surface Bezier Subdivision + + + + + + + + + + + + + + + + + +
Show/Hide Code
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/examples/surfaceStepLength.html b/examples/surfaceStepLength.html new file mode 100644 index 00000000..28603af7 --- /dev/null +++ b/examples/surfaceStepLength.html @@ -0,0 +1,115 @@ + + + + Surface step length + + + + + + + + + + + + + + + + + +
Show/Hide Code
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/src/verb/Verb.hx b/src/verb/Verb.hx index 5e35d913..1a286b19 100644 --- a/src/verb/Verb.hx +++ b/src/verb/Verb.hx @@ -41,7 +41,7 @@ import verb.eval.Divide; import verb.eval.Check; class Verb { - public static function main():Void { - trace("verb 2.0.0"); - } + public static function main( ) : Void { + trace( "verb 2.1.0" ); + } } \ No newline at end of file diff --git a/src/verb/core/ArrayExtensions.hx b/src/verb/core/ArrayExtensions.hx index 1f3754b0..04e5d7a6 100644 --- a/src/verb/core/ArrayExtensions.hx +++ b/src/verb/core/ArrayExtensions.hx @@ -13,10 +13,10 @@ class ArrayExtensions { // //* nothing, just mutates the given array - public static function alloc( a : Array, n : Int ){ - if (n < 0) return; - while (a.length < n) { - a.push(null); + public static function alloc( a : Array, n : Int ) { + if ( n < 0 ) return; + while ( a.length < n ) { + a.push( null ); } } @@ -30,9 +30,9 @@ class ArrayExtensions { // //* a reversed copy of the array - public static function reversed(a : Array) : Array { - var ac = a.copy(); - ac.reverse(); + public static function reversed( a : Array ) : Array { + var ac = a.copy( ); + ac.reverse( ); return ac; } @@ -46,8 +46,8 @@ class ArrayExtensions { // //* the last element of the array - public static function last(a : Array) : T { - return a[a.length-1]; + public static function last( a : Array ) : T { + return a[a.length - 1]; } //Get the first element of an array @@ -60,13 +60,13 @@ class ArrayExtensions { // //* the last element of the array - public static function first(a : Array) : T { + public static function first( a : Array ) : T { return a[0]; } - public static function spliceAndInsert(a : Array, start : Int, end : Int, ele : T) : Void { - a.splice(start, end); - a.insert(start, ele); + public static function spliceAndInsert( a : Array, start : Int, end : Int, ele : T ) : Void { + a.splice( start, end ); + a.insert( start, ele ); } //Get the first half of an array including the pivot @@ -79,8 +79,8 @@ class ArrayExtensions { // //* the left half - public static function left(arr : Array) : Array{ - if (arr.length == 0) return []; + public static function left( arr : Array ) : Array { + if ( arr.length == 0 ) return []; var len = Math.ceil( arr.length / 2 ); return arr.slice( 0, len ); } @@ -95,8 +95,8 @@ class ArrayExtensions { // //* the right half - public static function right(arr : Array) : Array{ - if (arr.length == 0) return []; + public static function right( arr : Array ) : Array { + if ( arr.length == 0 ) return []; var len = Math.ceil( arr.length / 2 ); return arr.slice( len ); } @@ -111,10 +111,10 @@ class ArrayExtensions { // //* the right half - public static function rightWithPivot(arr : Array) : Array{ - if (arr.length == 0) return []; + public static function rightWithPivot( arr : Array ) : Array { + if ( arr.length == 0 ) return []; var len = Math.ceil( arr.length / 2 ); - return arr.slice( len-1 ); + return arr.slice( len - 1 ); } //Obtain the unique set of elements in an array @@ -129,25 +129,25 @@ class ArrayExtensions { // //* array of unique elements - public static function unique( arr : Array, comp : T -> T -> Bool ){ + public static function unique( arr : Array, comp : T -> T -> Bool ) { - if (arr.length == 0) return []; + if ( arr.length == 0 ) return []; - var uniques = [ arr.pop() ]; + var uniques = [ arr.pop( ) ]; - while (arr.length > 0){ + while ( arr.length > 0 ) { - var ele = arr.pop(); + var ele = arr.pop( ); var isUnique = true; - for (unique in uniques){ - if ( comp( ele, unique ) ){ + for ( unique in uniques ) { + if ( comp( ele, unique ) ) { isUnique = false; break; } } - if ( isUnique ){ + if ( isUnique ) { uniques.push( ele ); } } diff --git a/src/verb/core/Binomial.hx b/src/verb/core/Binomial.hx index 422c482e..0deb5a7d 100644 --- a/src/verb/core/Binomial.hx +++ b/src/verb/core/Binomial.hx @@ -6,61 +6,61 @@ class Binomial { static var memo = new IntMap>(); - public static function get(n : Int, k : Int) : Float { - if (k == 0.0) { + public static function get( n : Int, k : Int ) : Float { + if ( k == 0.0 ) { return 1.0; } - if (n == 0 || k > n) { + if ( n == 0 || k > n ) { return 0.0; } - if (k > n - k) { + if ( k > n - k ) { k = n - k; } - if ( memo_exists(n,k) ) { - return get_memo(n,k); + if ( memo_exists( n, k ) ) { + return get_memo( n, k ); } var r : Float = 1, n_o = n; - for (d in 1...k+1){ + for ( d in 1...k + 1 ) { - if ( memo_exists(n_o, d) ) { + if ( memo_exists( n_o, d ) ) { n--; - r = get_memo(n_o, d); + r = get_memo( n_o, d ); continue; } r *= n--; r /= d; - memoize(n_o, d, r); + memoize( n_o, d, r ); } return r; } - public static function get_no_memo(n : Int, k : Int) : Float { - if (k == 0) { + public static function get_no_memo( n : Int, k : Int ) : Float { + if ( k == 0 ) { return 1; } - if (n == 0 || k > n) { + if ( n == 0 || k > n ) { return 0; } - if (k > n - k) { + if ( k > n - k ) { k = n - k; } var r : Float = 1, n_o = n; - for (d in 1...k+1){ + for ( d in 1...k + 1 ) { r *= n--; r /= d; } @@ -68,16 +68,16 @@ class Binomial { return r; } - private static function memo_exists(n : Int, k : Int) : Bool { - return ( memo.exists(n) && memo.get(n).exists(k) ); + private static function memo_exists( n : Int, k : Int ) : Bool { + return ( memo.exists( n ) && memo.get( n ).exists( k ) ); } - private static function get_memo(n : Int, k : Int) : Float { - return memo.get(n).get(k); + private static function get_memo( n : Int, k : Int ) : Float { + return memo.get( n ).get( k ); } - private static function memoize(n, k, val) { - if ( !memo.exists(n) ) { + private static function memoize( n, k, val ) { + if ( !memo.exists( n ) ) { memo.set( n, new IntMap() ); } diff --git a/src/verb/core/BoundingBox.hx b/src/verb/core/BoundingBox.hx index 279cde0e..a635442c 100644 --- a/src/verb/core/BoundingBox.hx +++ b/src/verb/core/BoundingBox.hx @@ -43,7 +43,7 @@ class BoundingBox { // //* This BoundingBox for chaining - public function fromPoint( pt ){ + public function fromPoint( pt ) { return new BoundingBox( [ pt ] ); } @@ -58,21 +58,19 @@ class BoundingBox { // //* This BoundingBox for chaining - public function add( point : Point ) : BoundingBox - { - if ( !this.initialized ) - { + public function add( point : Point ) : BoundingBox { + if ( !this.initialized ) { this.dim = point.length; - this.min = point.slice(0); - this.max = point.slice(0); + this.min = point.slice( 0 ); + this.max = point.slice( 0 ); this.initialized = true; return this; } - for (i in 0...this.dim){ - if (point[i] > this.max[i] ) this.max[i] = point[i]; - if (point[i] < this.min[i] ) this.min[i] = point[i]; + for ( i in 0...this.dim ) { + if ( point[i] > this.max[i] ) this.max[i] = point[i]; + if ( point[i] < this.min[i] ) this.min[i] = point[i]; } return this; @@ -89,12 +87,11 @@ class BoundingBox { // //* this BoundingBox for chaining - public function addRange( points : Array ) : BoundingBox - { + public function addRange( points : Array ) : BoundingBox { var l = points.length; - for (i in 0...l){ - this.add(points[i]); + for ( i in 0...l ) { + this.add( points[i] ); } return this; @@ -111,10 +108,9 @@ class BoundingBox { // //* true if the two intervals overlap, otherwise false - public function contains(point : Point, tol : Float = -1) : Bool { + public function contains( point : Point, tol : Float = -1 ) : Bool { - if ( !this.initialized ) - { + if ( !this.initialized ) { return false; } @@ -134,13 +130,13 @@ class BoundingBox { // //* true if the two intervals overlap, otherwise false - public static function intervalsOverlap( a1 : Float, a2: Float, b1: Float, b2: Float, tol : Float = -1 ) : Bool { + public static function intervalsOverlap( a1 : Float, a2 : Float, b1 : Float, b2 : Float, tol : Float = -1 ) : Bool { var tol = tol < -0.5 ? Constants.TOLERANCE : tol - , x1 = Math.min(a1, a2) - tol - , x2 = Math.max(a1, a2) + tol - , y1 = Math.min(b1, b2) - tol - , y2 = Math.max(b1, b2) + tol; + , x1 = Math.min( a1, a2 ) - tol + , x2 = Math.max( a1, a2 ) + tol + , y1 = Math.min( b1, b2 ) - tol + , y2 = Math.max( b1, b2 ) + tol; return (x1 >= y1 && x1 <= y2) || (x2 >= y1 && x2 <= y2) || (y1 >= x1 && y1 <= x2) || (y2 >= x1 && y2 <= x2) ; } @@ -164,8 +160,8 @@ class BoundingBox { , b1 = bb.min , b2 = bb.max; - for (i in 0...dim){ - if (!intervalsOverlap(a1[i], a2[i], b1[i], b2[i], tol )) return false; + for ( i in 0...dim ) { + if ( !intervalsOverlap( a1[i], a2[i], b1[i], b2[i], tol ) ) return false; } return true; @@ -178,7 +174,7 @@ class BoundingBox { // //* this BoundingBox for chaining - public function clear() : BoundingBox { + public function clear( ) : BoundingBox { this.initialized = false; return this; } @@ -189,14 +185,14 @@ class BoundingBox { // //* Index of longest axis - public function getLongestAxis() : Int { + public function getLongestAxis( ) : Int { var max = 0.0; var id = 0; - for ( i in 0...dim ){ - var l = this.getAxisLength(i); - if (l > max) { + for ( i in 0...dim ) { + var l = this.getAxisLength( i ); + if ( l > max ) { max = l; id = i; } @@ -216,7 +212,7 @@ class BoundingBox { //* Length of the given axis. If axis is out of bounds, returns 0. public function getAxisLength( i : Int ) : Float { - if (i < 0 || i > this.dim-1) return 0.0; + if ( i < 0 || i > this.dim - 1 ) return 0.0; return Math.abs( this.min[i] - this.max[i] ); } @@ -245,7 +241,7 @@ class BoundingBox { var maxbb = [] , minbb = []; - for (i in 0...dim){ + for ( i in 0...dim ) { maxbb.push( Math.min( a2[i], b2[i] ) ); minbb.push( Math.max( a1[i], b1[i] ) ); } diff --git a/src/verb/core/Constants.hx b/src/verb/core/Constants.hx index f355d74a..73b7bad6 100644 --- a/src/verb/core/Constants.hx +++ b/src/verb/core/Constants.hx @@ -8,7 +8,7 @@ class Constants { //The default euclidean distance that identifies whether two points are coincident @:expose("TOLERANCE") public static var TOLERANCE : Float = 1e-6; - + //The minimum value to determine whether two floating point numbers are the same @:expose("EPSILON") public static var EPSILON : Float = 1e-10; diff --git a/src/verb/core/Data.hx b/src/verb/core/Data.hx index 3e3b762b..e0a48cb0 100644 --- a/src/verb/core/Data.hx +++ b/src/verb/core/Data.hx @@ -32,7 +32,7 @@ class Plane extends SerializableBase { public var normal : Vector; public var origin : Point; - public function new(origin, normal){ + public function new( origin, normal ) { this.origin = origin; this.normal = normal; } @@ -46,7 +46,7 @@ class Ray extends SerializableBase { public var dir : Vector; public var origin : Point; - public function new(origin, dir){ + public function new( origin, dir ) { this.origin = origin; this.dir = dir; } @@ -58,7 +58,7 @@ class Ray extends SerializableBase { @:expose("core.NurbsCurveData") class NurbsCurveData extends SerializableBase { - public function new(degree, knots, controlPoints){ + public function new( degree, knots, controlPoints ) { this.degree = degree; this.controlPoints = controlPoints; this.knots = knots; @@ -81,7 +81,7 @@ class NurbsCurveData extends SerializableBase { @:expose("core.NurbsSurfaceData") class NurbsSurfaceData extends SerializableBase { - public function new(degreeU, degreeV, knotsU, knotsV, controlPoints){ + public function new( degreeU, degreeV, knotsU, knotsV, controlPoints ) { this.degreeU = degreeU; this.degreeV = degreeV; this.knotsU = knotsU; @@ -127,15 +127,15 @@ class MeshData extends SerializableBase { public var normals : Array; public var uvs : Array; - public function new(faces : Array, points : Array, normals : Array, uvs : Array ) { + public function new( faces : Array, points : Array, normals : Array, uvs : Array ) { this.faces = faces; this.points = points; this.normals = normals; this.uvs = uvs; } - public static function empty() : MeshData { - return new MeshData([],[],[],[]); + public static function empty( ) : MeshData { + return new MeshData([], [], [], []); } } @@ -150,7 +150,7 @@ class PolylineData extends SerializableBase { // The parameters of the individual points public var params : Array; - public function new(points, params){ + public function new( points, params ) { this.points = points; this.params = params; } @@ -162,7 +162,7 @@ class PolylineData extends SerializableBase { @:expose("core.VolumeData") class VolumeData extends SerializableBase { - public function new(degreeU, degreeV, degreeW, knotsU, knotsV, knotsW, controlPoints){ + public function new( degreeU, degreeV, degreeW, knotsU, knotsV, knotsW, controlPoints ) { this.degreeU = degreeU; this.degreeV = degreeV; this.degreeW = degreeW; @@ -203,7 +203,7 @@ class Pair { public var item0 : T1; public var item1 : T2; - public function new(item1 : T1, item2 : T2) { + public function new( item1 : T1, item2 : T2 ) { this.item0 = item1; this.item1 = item2; } @@ -216,7 +216,7 @@ class Interval { public var min : T; public var max : T; - public function new(min, max){ + public function new( min, max ) { this.min = min; this.max = max; } diff --git a/src/verb/core/Intersections.hx b/src/verb/core/Intersections.hx index a270dbe3..a6dbe38c 100644 --- a/src/verb/core/Intersections.hx +++ b/src/verb/core/Intersections.hx @@ -17,7 +17,7 @@ class CurveCurveIntersection { //the parameter on the second curve public var u1 : Float; - public function new(point0, point1, u0, u1){ + public function new( point0, point1, u0, u1 ) { this.point0 = point0; this.point1 = point1; this.u0 = u0; @@ -33,7 +33,7 @@ class CurveSurfaceIntersection { public var curvePoint : Point; public var surfacePoint : Point; - public function new( u, uv, curvePoint, surfacePoint ){ + public function new( u, uv, curvePoint, surfacePoint ) { this.u = u; this.uv = uv; this.curvePoint = curvePoint; @@ -56,7 +56,7 @@ class MeshIntersectionPoint { public var adj : MeshIntersectionPoint = null; public var visited : Bool = false; - public function new(uv0, uv1, point, faceIndex0, faceIndex1){ + public function new( uv0, uv1, point, faceIndex0, faceIndex1 ) { this.uv0 = uv0; this.uv1 = uv1; this.point = point; @@ -74,7 +74,7 @@ class PolylineMeshIntersection { public var polylineIndex : Int; public var faceIndex : Int; - public function new(point, u, uv, polylineIndex, faceIndex){ + public function new( point, u, uv, polylineIndex, faceIndex ) { this.point = point; this.u = u; this.uv = uv; @@ -91,7 +91,7 @@ class SurfaceSurfaceIntersectionPoint { public var point : Point; public var dist : Float; - public function new( uv0, uv1, point, dist ){ + public function new( uv0, uv1, point, dist ) { this.uv0 = uv0; this.uv1 = uv1; this.point = point; @@ -114,7 +114,7 @@ class TriSegmentIntersection { //the parameter along the segment public var p : Float; - public function new(point, s, t, r){ + public function new( point, s, t, r ) { this.point = point; this.s = s; this.t = t; @@ -128,7 +128,7 @@ class CurveTriPoint { public var uv : UV; public var point : Point; - public function new(u : Float, point : Point, uv : UV){ + public function new( u : Float, point : Point, uv : UV ) { this.u = u; this.point = point; this.uv = uv; @@ -143,7 +143,7 @@ class SurfacePoint { public var id : Int; public var degen : Bool; - public function new(point : Point, normal : Point, uv : UV, id : Int = -1, degen : Bool = false) { + public function new( point : Point, normal : Point, uv : UV, id : Int = -1, degen : Bool = false ) { this.uv = uv; this.point = point; this.normal = normal; @@ -151,8 +151,8 @@ class SurfacePoint { this.degen = degen; } - public static function fromUv(u,v){ - return new SurfacePoint(null, null, [u,v] ); + public static function fromUv( u, v ) { + return new SurfacePoint(null, null, [u, v] ); } } @@ -161,7 +161,7 @@ class CurvePoint { public var u : Float; public var pt : Point; - public function new(u, pt) { + public function new( u, pt ) { this.u = u; this.pt = pt; } diff --git a/src/verb/core/KdTree.hx b/src/verb/core/KdTree.hx index 1c851947..1dcab98e 100644 --- a/src/verb/core/KdTree.hx +++ b/src/verb/core/KdTree.hx @@ -21,68 +21,68 @@ class KdTree { private var dim : Int = 3; private var root : KdNode; - public function new(points, distanceFunction) { + public function new( points, distanceFunction ) { this.points = points; this.distanceFunction = distanceFunction; this.dim = points[0].point.length; - this.root = buildTree(points, 0, null); + this.root = buildTree( points, 0, null ); } - private function buildTree(points : Array>, depth : Int, parent : KdNode) : KdNode { + private function buildTree( points : Array>, depth : Int, parent : KdNode ) : KdNode { var dim = depth % dim, - median, - node; + median, + node; - if (points.length == 0) return null; - if (points.length == 1) return new KdNode(points[0], dim, parent); + if ( points.length == 0 ) return null; + if ( points.length == 1 ) return new KdNode(points[0], dim, parent); - points.sort(function(a : KdPoint, b : KdPoint) { + points.sort( function( a : KdPoint, b : KdPoint ) { var diff = a.point[dim] - b.point[dim]; - if (diff == 0.0){ + if ( diff == 0.0 ) { return 0; - } else if (diff > 0) { + } else if ( diff > 0 ) { return 1; } else { return -1; } - }); + } ); - median = Math.floor(points.length / 2); + median = Math.floor( points.length / 2 ); node = new KdNode(points[median], dim, parent); - node.left = buildTree( points.slice(0, median), depth + 1, node); - node.right = buildTree( points.slice(median + 1), depth + 1, node); + node.left = buildTree( points.slice( 0, median ), depth + 1, node ); + node.right = buildTree( points.slice( median + 1 ), depth + 1, node ); return node; } - public function nearest(point : Point, maxNodes : Int, maxDistance : Float ) : Array, Float>> { + public function nearest( point : Point, maxNodes : Int, maxDistance : Float ) : Array, Float>> { var bestNodes = new BinaryHeap>( - function (e : Pair, Float>) { return -e.item1; } + function( e : Pair, Float> ) { return -e.item1; } ); - function nearestSearch(node : KdNode) { + function nearestSearch( node : KdNode ) { var bestChild, - dimension = node.dimension, - ownDistance = distanceFunction( point, node.kdPoint.point ), - linearPoint = [for (i in 0...dim) 0.0], - linearDistance, - otherChild, - i; - - function saveNode(node : KdNode, distance : Float) : Void { - bestNodes.push(new Pair(node, distance)); - if (bestNodes.size() > maxNodes) { - bestNodes.pop(); + dimension = node.dimension, + ownDistance = distanceFunction( point, node.kdPoint.point ), + linearPoint = [for ( i in 0...dim ) 0.0], + linearDistance, + otherChild, + i; + + function saveNode( node : KdNode, distance : Float ) : Void { + bestNodes.push( new Pair(node, distance) ); + if ( bestNodes.size( ) > maxNodes ) { + bestNodes.pop( ); } } - for (i in 0...dim){ - if (i == node.dimension) { + for ( i in 0...dim ) { + if ( i == node.dimension ) { linearPoint[i] = point[i]; } else { linearPoint[i] = node.kdPoint.point[i]; @@ -91,19 +91,19 @@ class KdTree { linearDistance = distanceFunction( linearPoint, node.kdPoint.point ); - if (node.right == null && node.left == null) { - if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek().item1) { - saveNode(node, ownDistance); + if ( node.right == null && node.left == null ) { + if ( bestNodes.size( ) < maxNodes || ownDistance < bestNodes.peek( ).item1 ) { + saveNode( node, ownDistance ); } return; } - if (node.right == null) { + if ( node.right == null ) { bestChild = node.left; - } else if (node.left == null) { + } else if ( node.left == null ) { bestChild = node.right; } else { - if (point[dimension] < node.kdPoint.point[dimension]) { + if ( point[dimension] < node.kdPoint.point[dimension] ) { bestChild = node.left; } else { bestChild = node.right; @@ -112,33 +112,33 @@ class KdTree { nearestSearch( bestChild ); - if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek().item1) { - saveNode(node, ownDistance); + if ( bestNodes.size( ) < maxNodes || ownDistance < bestNodes.peek( ).item1 ) { + saveNode( node, ownDistance ); } - if (bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek().item1) { - if (bestChild == node.left) { + if ( bestNodes.size( ) < maxNodes || Math.abs( linearDistance ) < bestNodes.peek( ).item1 ) { + if ( bestChild == node.left ) { otherChild = node.right; } else { otherChild = node.left; } - if (otherChild != null) { - nearestSearch(otherChild); + if ( otherChild != null ) { + nearestSearch( otherChild ); } } } - for (i in 0...maxNodes){ - bestNodes.push(new Pair, Float>(null, maxDistance)); + for ( i in 0...maxNodes ) { + bestNodes.push( new Pair, Float>(null, maxDistance) ); } nearestSearch( this.root ); var result = []; - for (i in 0...maxNodes){ - if (bestNodes.content[i].item0 != null) { - result.push(new Pair, Float>(bestNodes.content[i].item0.kdPoint, bestNodes.content[i].item1)); + for ( i in 0...maxNodes ) { + if ( bestNodes.content[i].item0 != null ) { + result.push( new Pair, Float>(bestNodes.content[i].item0.kdPoint, bestNodes.content[i].item1) ); } } @@ -154,51 +154,51 @@ class BinaryHeap { public var content : Array>; private var scoreFunction : Pair -> Float; - public function new(scoreFunction){ + public function new( scoreFunction ) { this.content = []; this.scoreFunction = scoreFunction; } - public function push(element : Pair) : Void { + public function push( element : Pair ) : Void { //Add the new element to the end of the array. - this.content.push(element); + this.content.push( element ); //Allow it to bubble up. - this.bubbleUp(this.content.length - 1); + this.bubbleUp( this.content.length - 1 ); } - public function pop() : Pair { + public function pop( ) : Pair { //Store the first element so we can return it later. var result = this.content[0]; //Get the element at the end of the array. - var end = this.content.pop(); + var end = this.content.pop( ); //If there are any elements left, put the end element at the //start, and let it sink down. - if (this.content.length > 0) { + if ( this.content.length > 0 ) { this.content[0] = end; - this.sinkDown(0); + this.sinkDown( 0 ); } return result; } - public function peek() : Pair { + public function peek( ) : Pair { return this.content[0]; } - public function remove(node : Pair) : Void { + public function remove( node : Pair ) : Void { var len = this.content.length; //To remove a value, we must search through the array to find //it. - for (i in 0...len){ - if (this.content[i] == node) { + for ( i in 0...len ) { + if ( this.content[i] == node ) { //When it is found, the process seen in 'pop' is repeated //to fill up the hole. - var end = this.content.pop(); - if (i != len - 1) { + var end = this.content.pop( ); + if ( i != len - 1 ) { this.content[i] = end; - if (this.scoreFunction(end) < this.scoreFunction(node)) - this.bubbleUp(i); + if ( this.scoreFunction( end ) < this.scoreFunction( node ) ) + this.bubbleUp( i ); else - this.sinkDown(i); + this.sinkDown( i ); } return; } @@ -206,39 +206,39 @@ class BinaryHeap { throw "Node not found."; } - public function size() : Int { + public function size( ) : Int { return this.content.length; } - private function bubbleUp(n : Int) : Void { + private function bubbleUp( n : Int ) : Void { //Fetch the element that has to be moved. var element = this.content[n]; //When at 0, an element can not go up any further. - while (n > 0) { + while ( n > 0 ) { //Compute the parent element's index, and fetch it. - var parentN = Math.floor((n + 1.0) / 2) - 1, + var parentN = Math.floor( (n + 1.0) / 2 ) - 1, parent = this.content[parentN]; //Swap the elements if the parent is greater. - if (this.scoreFunction(element) < this.scoreFunction(parent)) { + if ( this.scoreFunction( element ) < this.scoreFunction( parent ) ) { this.content[parentN] = element; this.content[n] = parent; //Update 'n' to continue at the new position. n = parentN; } - //Found a parent that is less, no need to move it further. + //Found a parent that is less, no need to move it further. else { break; } } } - private function sinkDown(n : Int) : Void { + private function sinkDown( n : Int ) : Void { //Look up the target element and its score. var length = this.content.length, element = this.content[n], - elemScore = this.scoreFunction(element); + elemScore = this.scoreFunction( element ); - while(true) { + while ( true ) { //Compute the indices of the child elements. var child2N = (n + 1) * 2; var child1N = child2N - 1; @@ -248,30 +248,30 @@ class BinaryHeap { var child1Score : Float = 0.0; //If the first child exists (is inside the array)... - if (child1N < length) { + if ( child1N < length ) { //Look it up and compute its score. var child1 = this.content[child1N]; - child1Score = this.scoreFunction(child1); + child1Score = this.scoreFunction( child1 ); //If the score is less than our element's, we need to swap. - if (child1Score < elemScore) + if ( child1Score < elemScore ) swap = child1N; } //Do the same checks for the other child. - if (child2N < length) { + if ( child2N < length ) { var child2 = this.content[child2N]; - var child2Score = this.scoreFunction(child2); - if (child2Score < (swap == -1 ? elemScore : child1Score)){ + var child2Score = this.scoreFunction( child2 ); + if ( child2Score < (swap == -1 ? elemScore : child1Score) ) { swap = child2N; } } //If the element needs to be moved, swap it, and continue. - if (swap != -1) { + if ( swap != -1 ) { this.content[n] = this.content[swap]; this.content[swap] = element; n = swap; } - //Otherwise, we are done. + //Otherwise, we are done. else { break; } @@ -289,7 +289,7 @@ class KdPoint { // An arbitrary object to attach public var obj : T; - public function new(point, obj){ + public function new( point, obj ) { this.point = point; this.obj = obj; } @@ -314,7 +314,7 @@ class KdNode { // The dimensionality of the point public var dimension : Int; - public function new(kdPoint : KdPoint, dimension : Int, parent : KdNode) { + public function new( kdPoint : KdPoint, dimension : Int, parent : KdNode ) { this.kdPoint = kdPoint; this.left = null; this.right = null; diff --git a/src/verb/core/LazyCurveBoundingBoxTree.hx b/src/verb/core/LazyCurveBoundingBoxTree.hx index ff99ee61..c1fb5ee7 100644 --- a/src/verb/core/LazyCurveBoundingBoxTree.hx +++ b/src/verb/core/LazyCurveBoundingBoxTree.hx @@ -14,42 +14,42 @@ class LazyCurveBoundingBoxTree implements IBoundingBoxTree { var _boundingBox : BoundingBox = null; var _knotTol : Float; - public function new(curve, knotTol : Float = null){ + public function new( curve, knotTol : Float = null ) { _curve = curve; - if (knotTol == null){ - knotTol = _curve.knots.domain() / 64; + if ( knotTol == null ) { + knotTol = _curve.knots.domain( ) / 64; } _knotTol = knotTol; } - public function split() : Pair, IBoundingBoxTree> { - var min = _curve.knots.first(); - var max = _curve.knots.last(); + public function split( ) : Pair, IBoundingBoxTree> { + var min = _curve.knots.first( ); + var max = _curve.knots.last( ); var dom = max - min; - var crvs = Divide.curveSplit( _curve, (max + min) / 2.0 + dom * 0.1 * Math.random()); + var crvs = Divide.curveSplit( _curve, (max + min) / 2.0 + dom * 0.1 * Math.random( ) ); return new Pair, IBoundingBoxTree>( - new LazyCurveBoundingBoxTree( crvs[0], _knotTol ), - new LazyCurveBoundingBoxTree( crvs[1], _knotTol )); + new LazyCurveBoundingBoxTree( crvs[0], _knotTol ), + new LazyCurveBoundingBoxTree( crvs[1], _knotTol )); } - public function boundingBox(){ - if (_boundingBox == null){ - _boundingBox = new BoundingBox( Eval.dehomogenize1d(_curve.controlPoints) ); + public function boundingBox( ) { + if ( _boundingBox == null ) { + _boundingBox = new BoundingBox( Eval.dehomogenize1d( _curve.controlPoints ) ); } return _boundingBox; } - public function yield(){ + public function yield( ) { return _curve; } - public function indivisible( tolerance : Float ){ - return _curve.knots.domain() < _knotTol; + public function indivisible( tolerance : Float ) { + return _curve.knots.domain( ) < _knotTol; } - public function empty(){ + public function empty( ) { return false; } } \ No newline at end of file diff --git a/src/verb/core/LazyMeshBoundingBoxTree.hx b/src/verb/core/LazyMeshBoundingBoxTree.hx index 9791dde6..85ce4840 100644 --- a/src/verb/core/LazyMeshBoundingBoxTree.hx +++ b/src/verb/core/LazyMeshBoundingBoxTree.hx @@ -10,40 +10,40 @@ class LazyMeshBoundingBoxTree implements IBoundingBoxTree { var _faceIndices : Array; var _boundingBox : BoundingBox = null; - public function new(mesh, faceIndices = null){ + public function new( mesh, faceIndices = null ) { _mesh = mesh; - if (faceIndices == null) { - faceIndices = [ for (i in 0...mesh.faces.length) i ]; + if ( faceIndices == null ) { + faceIndices = [ for ( i in 0...mesh.faces.length ) i ]; } _faceIndices = faceIndices; } - public function split() : Pair, IBoundingBoxTree> { - var as = Mesh.sortTrianglesOnLongestAxis( boundingBox(), _mesh, _faceIndices ) - , l = as.left() - , r = as.right(); + public function split( ) : Pair, IBoundingBoxTree> { + var as = Mesh.sortTrianglesOnLongestAxis( boundingBox( ), _mesh, _faceIndices ) + , l = as.left( ) + , r = as.right( ); return new Pair, IBoundingBoxTree>( - new LazyMeshBoundingBoxTree( _mesh, l), - new LazyMeshBoundingBoxTree( _mesh, r )); + new LazyMeshBoundingBoxTree( _mesh, l), + new LazyMeshBoundingBoxTree( _mesh, r )); } - public function boundingBox(){ - if (_boundingBox == null){ + public function boundingBox( ) { + if ( _boundingBox == null ) { _boundingBox = Mesh.makeMeshAabb( _mesh, _faceIndices ); } return _boundingBox; } - public function yield(){ + public function yield( ) { return _faceIndices[0]; } - public function indivisible( tolerance : Float ){ + public function indivisible( tolerance : Float ) { return _faceIndices.length == 1; } - public function empty(){ + public function empty( ) { return _faceIndices.length == 0; } } \ No newline at end of file diff --git a/src/verb/core/LazyPolylineBoundingBoxTree.hx b/src/verb/core/LazyPolylineBoundingBoxTree.hx index 56486881..1ddd2223 100644 --- a/src/verb/core/LazyPolylineBoundingBoxTree.hx +++ b/src/verb/core/LazyPolylineBoundingBoxTree.hx @@ -9,47 +9,47 @@ class LazyPolylineBoundingBoxTree implements IBoundingBoxTree { var _polyline : PolylineData; var _boundingBox : BoundingBox = null; - public function new(polyline, interval = null){ + public function new( polyline, interval = null ) { _polyline = polyline; - if (interval == null) { - interval = new Interval(0, polyline.points.length != 0 ? polyline.points.length-1 : 0); + if ( interval == null ) { + interval = new Interval(0, polyline.points.length != 0 ? polyline.points.length - 1 : 0); } _interval = interval; } - public function split() : Pair, IBoundingBoxTree> { + public function split( ) : Pair, IBoundingBoxTree> { var min = _interval.min; var max = _interval.max; - var pivot = min + Math.ceil( (max-min) / 2 ); + var pivot = min + Math.ceil( (max - min) / 2 ); var l = new Interval( min, pivot ) , r = new Interval( pivot, max ); return new Pair, IBoundingBoxTree>( - new LazyPolylineBoundingBoxTree( _polyline, l ), - new LazyPolylineBoundingBoxTree( _polyline, r )); + new LazyPolylineBoundingBoxTree( _polyline, l ), + new LazyPolylineBoundingBoxTree( _polyline, r )); } - public function boundingBox(){ - if (_boundingBox == null){ + public function boundingBox( ) { + if ( _boundingBox == null ) { _boundingBox = new BoundingBox( _polyline.points ); } return _boundingBox; } - public function yield(){ + public function yield( ) { return _interval.min; } - public function indivisible( tolerance : Float ){ + public function indivisible( tolerance : Float ) { return _interval.max - _interval.min == 1; } - public function empty(){ + public function empty( ) { return _interval.max - _interval.min == 0; } } \ No newline at end of file diff --git a/src/verb/core/LazySurfaceBoundingBoxTree.hx b/src/verb/core/LazySurfaceBoundingBoxTree.hx index 2edc703c..916103d3 100644 --- a/src/verb/core/LazySurfaceBoundingBoxTree.hx +++ b/src/verb/core/LazySurfaceBoundingBoxTree.hx @@ -16,32 +16,32 @@ class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { var _knotTolU : Float; var _knotTolV : Float; - public function new(surface, splitV = false, knotTolU = null, knotTolV = null){ + public function new( surface, splitV = false, knotTolU = null, knotTolV = null ) { _surface = surface; _splitV = splitV; - if (knotTolU == null){ - knotTolU = (surface.knotsU.domain()) / 16; + if ( knotTolU == null ) { + knotTolU = (surface.knotsU.domain( )) / 16; } - if (knotTolV == null){ - knotTolV = (surface.knotsV.domain()) / 16; + if ( knotTolV == null ) { + knotTolV = (surface.knotsV.domain( )) / 16; } _knotTolU = knotTolU; _knotTolV = knotTolV; } - public function split() : Pair, IBoundingBoxTree> { + public function split( ) : Pair, IBoundingBoxTree> { var min : Float; var max : Float; - if (_splitV){ - min = _surface.knotsV.first(); - max = _surface.knotsV.last(); + if ( _splitV ) { + min = _surface.knotsV.first( ); + max = _surface.knotsV.last( ); } else { - min = _surface.knotsU.first(); - max = _surface.knotsU.last(); + min = _surface.knotsU.first( ); + max = _surface.knotsU.last( ); } var dom = max - min; @@ -50,29 +50,29 @@ class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { var srfs = Divide.surfaceSplit( _surface, pivot, _splitV ); return new Pair, IBoundingBoxTree>( - new LazySurfaceBoundingBoxTree( srfs[0], !_splitV, _knotTolU, _knotTolV ), - new LazySurfaceBoundingBoxTree( srfs[1], !_splitV, _knotTolU, _knotTolV )); + new LazySurfaceBoundingBoxTree( srfs[0], !_splitV, _knotTolU, _knotTolV ), + new LazySurfaceBoundingBoxTree( srfs[1], !_splitV, _knotTolU, _knotTolV )); } - public function boundingBox(){ - if (_boundingBox == null){ + public function boundingBox( ) { + if ( _boundingBox == null ) { _boundingBox = new BoundingBox(); - for (row in _surface.controlPoints){ - _boundingBox.addRange( Eval.dehomogenize1d(row) ); + for ( row in _surface.controlPoints ) { + _boundingBox.addRange( Eval.dehomogenize1d( row ) ); } } return _boundingBox; } - public function yield(){ + public function yield( ) { return _surface; } - public function indivisible( tolerance : Float ){ - return _surface.knotsV.domain() < _knotTolV && _surface.knotsU.domain() < _knotTolU; + public function indivisible( tolerance : Float ) { + return _surface.knotsV.domain( ) < _knotTolV && _surface.knotsU.domain( ) < _knotTolU; } - public function empty(){ + public function empty( ) { return false; } } \ No newline at end of file diff --git a/src/verb/core/Mat.hx b/src/verb/core/Mat.hx index 468e703a..d085d4f7 100644 --- a/src/verb/core/Mat.hx +++ b/src/verb/core/Mat.hx @@ -10,40 +10,40 @@ class Mat { // Multiply a `Matrix` by a constant - public static function mul(a : Float, b : Matrix ) : Matrix { - return [ for (i in 0...b.length) Vec.mul(a, b[i]) ]; + public static function mul( a : Float, b : Matrix ) : Matrix { + return [ for ( i in 0...b.length ) Vec.mul( a, b[i] ) ]; } // Multiply two matrices assuming they are of compatible dimensions. // // Based on the numeric.js routine - `numeric.dotMMsmall` - public static function mult(x : Matrix, y : Matrix) : Matrix { + public static function mult( x : Matrix, y : Matrix ) : Matrix { - var p,q,r,ret,foo,bar,woo,i0,k0,p0,r0; + var p, q, r, ret, foo, bar, woo, i0, k0, p0, r0; p = x.length; q = y.length; r = y[0].length; ret = new Matrix(); - var i = p-1; + var i = p - 1; var j = 0; var k = 0; - while (i>=0){ + while ( i >= 0 ) { foo = new Vector(); bar = x[i]; - k = r-1; - while( k >= 0 ){ - woo = bar[q-1]*y[q-1][k]; + k = r - 1; + while ( k >= 0 ) { + woo = bar[q - 1] * y[q - 1][k]; - j = q-2; - while ( j >= 1 ){ - i0 = j-1; - woo += bar[j]*y[j][k] + bar[i0]*y[i0][k]; + j = q - 2; + while ( j >= 1 ) { + i0 = j - 1; + woo += bar[j] * y[j][k] + bar[i0] * y[i0][k]; j -= 2; } - if(j==0) { woo += bar[0]*y[0][k]; } + if ( j == 0 ) { woo += bar[0] * y[0][k]; } foo[k] = woo; k--; } @@ -55,69 +55,69 @@ class Mat { // Add two matrices - public static function add(a : Matrix, b : Matrix ) : Matrix { - return [ for (i in 0...a.length) Vec.add(a[i], b[i]) ]; + public static function add( a : Matrix, b : Matrix ) : Matrix { + return [ for ( i in 0...a.length ) Vec.add( a[i], b[i] ) ]; } // Divide each of entry of a Matrix by a constant - public static function div(a : Matrix, b : Float ) : Matrix { - return [ for (i in 0...a.length) Vec.div(a[i], b) ]; + public static function div( a : Matrix, b : Float ) : Matrix { + return [ for ( i in 0...a.length ) Vec.div( a[i], b ) ]; } // Subtract two matrices - public static function sub(a : Matrix, b : Matrix ) : Matrix { - return [ for (i in 0...a.length) Vec.sub(a[i], b[i]) ]; + public static function sub( a : Matrix, b : Matrix ) : Matrix { + return [ for ( i in 0...a.length ) Vec.sub( a[i], b[i] ) ]; } // Multiply a `Matrix` by a `Vector` - public static function dot(a : Matrix, b : Vector ) : Vector { - return [ for (i in 0...a.length) Vec.dot(a[i], b) ]; + public static function dot( a : Matrix, b : Vector ) : Vector { + return [ for ( i in 0...a.length ) Vec.dot( a[i], b ) ]; } // Build an identity matrix of a given size - public static function identity(n : Int) : Matrix { - var zeros = Vec.zeros2d(n, n); - for (i in 0...n){ zeros[i][i] = 1.0; } + public static function identity( n : Int ) : Matrix { + var zeros = Vec.zeros2d( n, n ); + for ( i in 0...n ) { zeros[i][i] = 1.0; } return zeros; } // Transpose a matrix - public static function transpose(a : Array>) : Array> { - if (a.length == 0) return []; - return [ for (i in 0...a[0].length) [for (j in 0...a.length) a[j][i] ] ]; + public static function transpose( a : Array> ) : Array> { + if ( a.length == 0 ) return []; + return [ for ( i in 0...a[0].length ) [for ( j in 0...a.length ) a[j][i] ] ]; } // Solve a system of equations - public static function solve(A : Matrix, b : Vector) : Vector { - return LUsolve( LU(A), b ); + public static function solve( A : Matrix, b : Vector ) : Vector { + return LUsolve( LU( A ), b ); } // Based on methods from numeric.js - private static function LUsolve(LUP : LUDecomp, b : Vector) : Vector { + private static function LUsolve( LUP : LUDecomp, b : Vector ) : Vector { var i, j; var LU = LUP.LU; - var n = LU.length; - var x = b.copy(); - var P = LUP.P; + var n = LU.length; + var x = b.copy( ); + var P = LUP.P; var Pi, LUi, LUii, tmp; - i = n-1; - while ( i != -1 ){ + i = n - 1; + while ( i != -1 ) { x[i] = b[i]; --i; } i = 0; - while (i < n){ + while ( i < n ) { Pi = P[i]; - if (P[i] != i) { + if ( P[i] != i ) { tmp = x[i]; x[i] = x[Pi]; x[Pi] = tmp; @@ -125,18 +125,18 @@ class Mat { LUi = LU[i]; j = 0; - while (j < i){ + while ( j < i ) { x[i] -= x[j] * LUi[j]; ++j; } ++i; } - i = n-1; - while (i >= 0){ + i = n - 1; + while ( i >= 0 ) { LUi = LU[i]; - j = i+1; - while (j < n){ + j = i + 1; + while ( j < n ) { x[i] -= x[j] * LUi[j]; ++j; } @@ -156,20 +156,20 @@ class Mat { var i, j, k, absAjk, Akk, Ak, Pk, Ai; var max; //copy A - A = [ for (i in 0...A.length) A[i].copy() ]; - var n = A.length, n1 = n-1; + A = [ for ( i in 0...A.length ) A[i].copy( ) ]; + var n = A.length, n1 = n - 1; var P = new Array(); //new Array(n); k = 0; - while (k < n){ + while ( k < n ) { Pk = k; Ak = A[k]; - max = Math.abs(Ak[k]); + max = Math.abs( Ak[k] ); - j = k+1; - while (j < n){ - absAjk = Math.abs(A[j][k]); - if (max < absAjk) { + j = k + 1; + while ( j < n ) { + absAjk = Math.abs( A[j][k] ); + if ( max < absAjk ) { max = absAjk; Pk = j; } @@ -177,7 +177,7 @@ class Mat { } P[k] = Pk; - if (Pk != k) { + if ( Pk != k ) { A[k] = A[Pk]; A[Pk] = Ak; Ak = A[k]; @@ -185,23 +185,23 @@ class Mat { Akk = Ak[k]; - i = k+1; - while (i < n){ + i = k + 1; + while ( i < n ) { A[i][k] /= Akk; ++i; } - i = k+1; - while (i < n){ + i = k + 1; + while ( i < n ) { Ai = A[i]; - j = k+1; - while (j < n1){ + j = k + 1; + while ( j < n1 ) { Ai[j] -= Ai[k] * Ak[j]; ++j; Ai[j] -= Ai[k] * Ak[j]; ++j; } - if(j==n1) Ai[j] -= Ai[k] * Ak[j]; + if ( j == n1 ) Ai[j] -= Ai[k] * Ak[j]; ++i; } @@ -219,7 +219,8 @@ private class LUDecomp { public var LU : Matrix; public var P : Array; - public function new( lu : Matrix, p : Array ){ + + public function new( lu : Matrix, p : Array ) { this.LU = lu; this.P = p; } diff --git a/src/verb/core/Mesh.hx b/src/verb/core/Mesh.hx index c131af64..f66c05d9 100644 --- a/src/verb/core/Mesh.hx +++ b/src/verb/core/Mesh.hx @@ -51,7 +51,7 @@ class Mesh { var bb = new verb.core.BoundingBox(); - for ( x in faceIndices ){ + for ( x in faceIndices ) { bb.add( mesh.points[ mesh.faces[ x ][0] ] ); bb.add( mesh.points[ mesh.faces[ x ][1] ] ); bb.add( mesh.points[ mesh.faces[ x ][2] ] ); @@ -75,23 +75,23 @@ class Mesh { public static function sortTrianglesOnLongestAxis( bb : BoundingBox, mesh : MeshData, faceIndices : Array ) : Array { - var longAxis = bb.getLongestAxis(); + var longAxis = bb.getLongestAxis( ); var minCoordFaceMap = new Array>(); - for ( faceIndex in faceIndices){ + for ( faceIndex in faceIndices ) { var tri_min = getMinCoordOnAxis( mesh.points, mesh.faces[ faceIndex ], longAxis ); - minCoordFaceMap.push( new Pair(tri_min, faceIndex) ); + minCoordFaceMap.push( new Pair(tri_min, faceIndex) ); } - minCoordFaceMap.sort(function(a : Pair, b : Pair):Int { + minCoordFaceMap.sort( function( a : Pair, b : Pair ) : Int { var a0 = a.item0; var b0 = b.item0; - if (a0 == b0) return 0 else if (a0 > b0) return 1 else return -1; - }); + if ( a0 == b0 ) return 0 else if ( a0 > b0 ) return 1 else return -1; + } ); var sortedFaceIndices = new Array(); - for ( i in 0...minCoordFaceMap.length){ + for ( i in 0...minCoordFaceMap.length ) { sortedFaceIndices.push( minCoordFaceMap[i].item1 ); } @@ -114,9 +114,9 @@ class Mesh { var min = Math.POSITIVE_INFINITY; - for (i in 0...3){ + for ( i in 0...3 ) { var coord = points[ tri[i] ][ axis ]; - if (coord < min) min = coord; + if ( coord < min ) min = coord; } return min; @@ -136,15 +136,15 @@ class Mesh { public static function getTriangleCentroid( points : Array, tri : Tri ) : Point { - var centroid = [0.0,0.0,0.0]; + var centroid = [0.0, 0.0, 0.0]; - for (i in 0...3){ - for (j in 0...3){ + for ( i in 0...3 ) { + for ( j in 0...3 ) { centroid[j] += points[ tri[i] ][j]; } } - for (i in 0...3){ + for ( i in 0...3 ) { centroid[i] /= 3; } @@ -175,17 +175,17 @@ class Mesh { var uv2 = mesh.uvs[ tri[1] ]; var uv3 = mesh.uvs[ tri[2] ]; - var f1 = Vec.sub(p1, f); - var f2 = Vec.sub(p2, f); - var f3 = Vec.sub(p3, f); + var f1 = Vec.sub( p1, f ); + var f2 = Vec.sub( p2, f ); + var f3 = Vec.sub( p3, f ); //calculate the areas and factors (order of parameters doesn't matter): - var a = Vec.norm( Vec.cross( Vec.sub(p1, p2), Vec.sub(p1, p3) ) ); //main triangle area a - var a1 = Vec.norm( Vec.cross(f2, f3) ) / a; //p1's triangle area / a - var a2 = Vec.norm( Vec.cross(f3, f1) ) / a; //p2's triangle area / a - var a3 = Vec.norm( Vec.cross(f1, f2) ) / a; //p3's triangle area / a + var a = Vec.norm( Vec.cross( Vec.sub( p1, p2 ), Vec.sub( p1, p3 ) ) ); //main triangle area a + var a1 = Vec.norm( Vec.cross( f2, f3 ) ) / a; //p1's triangle area / a + var a2 = Vec.norm( Vec.cross( f3, f1 ) ) / a; //p2's triangle area / a + var a3 = Vec.norm( Vec.cross( f1, f2 ) ) / a; //p3's triangle area / a //find the uv corresponding to point f (uv1/uv2/uv3 are associated to p1/p2/p3): - return Vec.add( Vec.mul( a1, uv1), Vec.add( Vec.mul( a2, uv2), Vec.mul( a3, uv3))); + return Vec.add( Vec.mul( a1, uv1 ), Vec.add( Vec.mul( a2, uv2 ), Vec.mul( a3, uv3 ) ) ); } } diff --git a/src/verb/core/MeshBoundingBoxTree.hx b/src/verb/core/MeshBoundingBoxTree.hx index fa858696..e7c4d1f5 100644 --- a/src/verb/core/MeshBoundingBoxTree.hx +++ b/src/verb/core/MeshBoundingBoxTree.hx @@ -12,49 +12,49 @@ class MeshBoundingBoxTree implements IBoundingBoxTree { var _face : Int = -1; var _empty : Bool = false; - public function new(mesh : MeshData, faceIndices : Array = null){ + public function new( mesh : MeshData, faceIndices : Array = null ) { - if (faceIndices == null) { - faceIndices = [ for (i in 0...mesh.faces.length) i ]; + if ( faceIndices == null ) { + faceIndices = [ for ( i in 0...mesh.faces.length ) i ]; } _boundingBox = Mesh.makeMeshAabb( mesh, faceIndices ); - if (faceIndices.length < 1) { + if ( faceIndices.length < 1 ) { _empty = true; return; - } else if (faceIndices.length < 2){ + } else if ( faceIndices.length < 2 ) { _face = faceIndices[0]; return; } var as = Mesh.sortTrianglesOnLongestAxis( _boundingBox, mesh, faceIndices ); - var l = as.left(); - var r = as.right(); + var l = as.left( ); + var r = as.right( ); _children = new Pair, IBoundingBoxTree>( - new MeshBoundingBoxTree(mesh, l), - new MeshBoundingBoxTree(mesh, r) + new MeshBoundingBoxTree(mesh, l), + new MeshBoundingBoxTree(mesh, r) ); } - public function split() : Pair, IBoundingBoxTree> { + public function split( ) : Pair, IBoundingBoxTree> { return _children; } - public function boundingBox(){ + public function boundingBox( ) { return _boundingBox; } - public function yield(){ + public function yield( ) { return _face; } - public function indivisible( tolerance : Float ){ + public function indivisible( tolerance : Float ) { return _children == null; } - public function empty(){ + public function empty( ) { return _empty; } } diff --git a/src/verb/core/Minimizer.hx b/src/verb/core/Minimizer.hx index 143b4a4f..1fe0a4cd 100644 --- a/src/verb/core/Minimizer.hx +++ b/src/verb/core/Minimizer.hx @@ -7,45 +7,45 @@ import verb.core.Data; @:expose("core.Minimizer") class Minimizer { - public static function uncmin(f : Vector -> Float, x0 : Vector, tol : Float = null, gradient : Vector -> Vector= null, maxit : Int = null) : MinimizationResult { + public static function uncmin( f : Vector -> Float, x0 : Vector, tol : Float = null, gradient : Vector -> Vector = null, maxit : Int = null ) : MinimizationResult { - if(tol == null) { tol = 1e-8; } - if(gradient == null) { gradient = function(x) { return numericalGradient(f,x); }; } - if(maxit == null) maxit = 1000; + if ( tol == null ) { tol = 1e-8; } + if ( gradient == null ) { gradient = function( x ) { return numericalGradient( f, x ); }; } + if ( maxit == null ) maxit = 1000; - x0 = x0.slice(0); + x0 = x0.slice( 0 ); var n = x0.length; - var f0 = f(x0),f1 = f0, df0; + var f0 = f( x0 ), f1 = f0, df0; - if(Math.isNaN(f0)) throw 'uncmin: f(x0) is a NaN!'; + if ( Math.isNaN( f0 ) ) throw 'uncmin: f(x0) is a NaN!'; - tol = Math.max(tol, Constants.EPSILON); - var step,g0,g1,H1 = Mat.identity(n); - var it=0,i,s =[],x1,y,Hy,Hs,ys,i0,t,nstep,t1,t2; + tol = Math.max( tol, Constants.EPSILON ); + var step, g0, g1, H1 = Mat.identity( n ); + var it = 0, i, s = [], x1, y, Hy, Hs, ys, i0, t, nstep, t1, t2; var msg = ""; g0 = gradient( x0 ); - while(it < maxit) { + while ( it < maxit ) { - if(!Vec.all(Vec.finite(g0))) { msg = "Gradient has Infinity or NaN"; break; } - step = Vec.neg(Mat.dot(H1,g0)); + if ( !Vec.all( Vec.finite( g0 ) ) ) { msg = "Gradient has Infinity or NaN"; break; } + step = Vec.neg( Mat.dot( H1, g0 ) ); - if(!Vec.all(Vec.finite(step))) { msg = "Search direction has Infinity or NaN"; break; } + if ( !Vec.all( Vec.finite( step ) ) ) { msg = "Search direction has Infinity or NaN"; break; } - nstep = Vec.norm(step); - if(nstep < tol) { msg= "Newton step smaller than tol"; break; } + nstep = Vec.norm( step ); + if ( nstep < tol ) { msg = "Newton step smaller than tol"; break; } t = 1.0; - df0 = Vec.dot(g0,step); + df0 = Vec.dot( g0, step ); -//line search + //line search x1 = x0; - while(it < maxit) { - if(t*nstep < tol) { break; } - s = Vec.mul(t, step); - x1 = Vec.add(x0,s); - f1 = f(x1); - if(f1-f0 >= 0.1*t*df0 || Math.isNaN(f1)) { + while ( it < maxit ) { + if ( t * nstep < tol ) { break; } + s = Vec.mul( t, step ); + x1 = Vec.add( x0, s ); + f1 = f( x1 ); + if ( f1 - f0 >= 0.1 * t * df0 || Math.isNaN( f1 ) ) { t *= 0.5; ++it; continue; @@ -53,16 +53,16 @@ class Minimizer { break; } - if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; } - if(it == maxit) { msg = "maxit reached during line search"; break; } + if ( t * nstep < tol ) { msg = "Line search step size smaller than tol"; break; } + if ( it == maxit ) { msg = "maxit reached during line search"; break; } - g1 = gradient(x1); - y = Vec.sub(g1,g0); - ys = Vec.dot(y,s); - Hy = Mat.dot(H1,y); + g1 = gradient( x1 ); + y = Vec.sub( g1, g0 ); + ys = Vec.dot( y, s ); + Hy = Mat.dot( H1, y ); H1 = Mat.sub( - Mat.add(H1, Mat.mul( (ys+Vec.dot(y,Hy))/(ys*ys), tensor(s,s) )), - Mat.div(Mat.add(tensor(Hy,s),tensor(s,Hy)),ys)); + Mat.add( H1, Mat.mul( (ys + Vec.dot( y, Hy )) / (ys * ys), tensor( s, s ) ) ), + Mat.div( Mat.add( tensor( Hy, s ), tensor( s, Hy ) ), ys ) ); x0 = x1; f0 = f1; g0 = g1; @@ -72,60 +72,60 @@ class Minimizer { return new MinimizationResult( x0, f0, g0, H1, it, msg); } - private static function numericalGradient(f : Vector -> Float, x : Vector) : Vector { + private static function numericalGradient( f : Vector -> Float, x : Vector ) : Vector { var n = x.length; - var f0 = f(x); + var f0 = f( x ); - if(f0 == Math.NaN) throw 'gradient: f(x) is a NaN!'; + if ( f0 == Math.NaN ) throw 'gradient: f(x) is a NaN!'; - var i, x0 = x.slice(0),f1,f2, J = []; + var i, x0 = x.slice( 0 ), f1, f2, J = []; - var errest,roundoff,eps = 1e-3; - var t0,t1,t2,it=0,d1,d2,N; + var errest, roundoff, eps = 1e-3; + var t0, t1, t2, it = 0, d1, d2, N; - for (i in 0...n){ + for ( i in 0...n ) { - var h = Math.max(1e-6 * f0, 1e-8); + var h = Math.max( 1e-6 * f0, 1e-8 ); - while(true) { + while ( true ) { ++it; - if( it>20 ) { throw "Numerical gradient fails"; } - x0[i] = x[i]+h; - f1 = f(x0); - x0[i] = x[i]-h; - f2 = f(x0); + if ( it > 20 ) { throw "Numerical gradient fails"; } + x0[i] = x[i] + h; + f1 = f( x0 ); + x0[i] = x[i] - h; + f2 = f( x0 ); x0[i] = x[i]; - if(Math.isNaN(f1) || Math.isNaN(f2)) { h/=16; continue; } + if ( Math.isNaN( f1 ) || Math.isNaN( f2 ) ) { h /= 16; continue; } - J[i] = (f1-f2)/(2*h); - t0 = x[i]-h; + J[i] = (f1 - f2) / (2 * h); + t0 = x[i] - h; t1 = x[i]; - t2 = x[i]+h; - d1 = (f1-f0)/h; - d2 = (f0-f2)/h; - N = Vec.max([ Math.abs(J[i]), Math.abs(f0), Math.abs(f1), Math.abs(f2), Math.abs(t0), Math.abs(t1), Math.abs(t2), 1e-8 ]); + t2 = x[i] + h; + d1 = (f1 - f0) / h; + d2 = (f0 - f2) / h; + N = Vec.max( [ Math.abs( J[i] ), Math.abs( f0 ), Math.abs( f1 ), Math.abs( f2 ), Math.abs( t0 ), Math.abs( t1 ), Math.abs( t2 ), 1e-8 ] ); - errest = Math.min( Vec.max([Math.abs(d1-J[i]), Math.abs(d2-J[i]), Math.abs(d1-d2)])/N, h/N); + errest = Math.min( Vec.max( [Math.abs( d1 - J[i] ), Math.abs( d2 - J[i] ), Math.abs( d1 - d2 )] ) / N, h / N ); - if(errest>eps) { h/=16; } else break; + if ( errest > eps ) { h /= 16; } else break; } } return J; } - private static function tensor(x : Vector, y : Vector) : Matrix { + private static function tensor( x : Vector, y : Vector ) : Matrix { var m = x.length, n = y.length, A = [], Ai, xi; - var i = m-1; - while (i >= 0){ + var i = m - 1; + while ( i >= 0 ) { Ai = []; xi = x[i]; - var j = n-1; - while(j >= 3){ + var j = n - 1; + while ( j >= 3 ) { Ai[j] = xi * y[j]; --j; Ai[j] = xi * y[j]; @@ -135,7 +135,7 @@ class Minimizer { Ai[j] = xi * y[j]; --j; } - while(j>=0) { Ai[j] = xi * y[j]; --j; } + while ( j >= 0 ) { Ai[j] = xi * y[j]; --j; } A[i] = Ai; i--; } @@ -153,7 +153,7 @@ class MinimizationResult { public var iterations : Int; public var message : String; - public function new(solution, value, gradient, invHessian, iterations, message){ + public function new( solution, value, gradient, invHessian, iterations, message ) { this.solution = solution; this.value = value; this.gradient = gradient; diff --git a/src/verb/core/Serialization.hx b/src/verb/core/Serialization.hx index c5b5c9b8..68947726 100644 --- a/src/verb/core/Serialization.hx +++ b/src/verb/core/Serialization.hx @@ -10,17 +10,17 @@ import haxe.Unserializer; // [http://haxe.org/manual/std-serialization.html](http://haxe.org/manual/std-serialization.html) for details. interface ISerializable { - function serialize() : String; + function serialize( ) : String; } // Forms a base class for serializable data types @:expose("core.SerializableBase") class SerializableBase { - public function serialize() : String { + public function serialize( ) : String { var serializer = new Serializer(); - serializer.serialize(this); - return serializer.toString(); + serializer.serialize( this ); + return serializer.toString( ); } } @@ -40,9 +40,9 @@ class Deserializer { // //* A new T from the string - public static function deserialize(s : String) : T { + public static function deserialize( s : String ) : T { var unserializer = new Unserializer(s); - var r : T = unserializer.unserialize(); + var r : T = unserializer.unserialize( ); return r; } } diff --git a/src/verb/core/SurfaceBoundingBoxTree.hx b/src/verb/core/SurfaceBoundingBoxTree.hx index 5d6d5711..45d69fbe 100644 --- a/src/verb/core/SurfaceBoundingBoxTree.hx +++ b/src/verb/core/SurfaceBoundingBoxTree.hx @@ -13,23 +13,23 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { var _surface : NurbsSurfaceData; var _boundingBox : BoundingBox = null; - public function new(surface, splitV = false, knotTolU = null, knotTolV = null){ + public function new( surface, splitV = false, knotTolU = null, knotTolV = null ) { _surface = surface; - if (knotTolU == null){ - knotTolU = (surface.knotsU.domain()) / 16; + if ( knotTolU == null ) { + knotTolU = (surface.knotsU.domain( )) / 16; } - if (knotTolV == null){ - knotTolV = (surface.knotsV.domain()) / 16; + if ( knotTolV == null ) { + knotTolV = (surface.knotsV.domain( )) / 16; } var divisible = false; - if (splitV){ - divisible = _surface.knotsV.domain() > knotTolV; + if ( splitV ) { + divisible = _surface.knotsV.domain( ) > knotTolV; } else { - divisible = _surface.knotsU.domain() > knotTolU; + divisible = _surface.knotsU.domain( ) > knotTolU; } if ( !divisible ) return; @@ -37,48 +37,48 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { var min : Float; var max : Float; - if (splitV){ - min = _surface.knotsV.first(); - max = _surface.knotsV.last(); + if ( splitV ) { + min = _surface.knotsV.first( ); + max = _surface.knotsV.last( ); } else { - min = _surface.knotsU.first(); - max = _surface.knotsU.last(); + min = _surface.knotsU.first( ); + max = _surface.knotsU.last( ); } var dom = max - min; - var pivot = (min + max) / 2.0 + dom * 0.1 * Math.random(); + var pivot = (min + max) / 2.0 + dom * 0.1 * Math.random( ); var srfs = Divide.surfaceSplit( _surface, pivot, splitV ); _children = new Pair, IBoundingBoxTree>( - new SurfaceBoundingBoxTree( srfs[0], !splitV, knotTolU, knotTolV ), - new SurfaceBoundingBoxTree( srfs[1], !splitV, knotTolU, knotTolV )); + new SurfaceBoundingBoxTree( srfs[0], !splitV, knotTolU, knotTolV ), + new SurfaceBoundingBoxTree( srfs[1], !splitV, knotTolU, knotTolV )); } - public function split() : Pair, IBoundingBoxTree> { + public function split( ) : Pair, IBoundingBoxTree> { return _children; } - public function boundingBox(){ - if (_boundingBox == null){ + public function boundingBox( ) { + if ( _boundingBox == null ) { _boundingBox = new BoundingBox(); - for (row in _surface.controlPoints){ - _boundingBox.addRange( Eval.dehomogenize1d(row) ); + for ( row in _surface.controlPoints ) { + _boundingBox.addRange( Eval.dehomogenize1d( row ) ); } } return _boundingBox; } - public function yield(){ + public function yield( ) { return _surface; } - public function indivisible( tolerance : Float ){ + public function indivisible( tolerance : Float ) { return _children == null; } - public function empty(){ + public function empty( ) { return false; } } \ No newline at end of file diff --git a/src/verb/core/Trig.hx b/src/verb/core/Trig.hx index a219e34d..3687b36d 100644 --- a/src/verb/core/Trig.hx +++ b/src/verb/core/Trig.hx @@ -10,11 +10,11 @@ using verb.core.Vec; @:expose("core.Trig") class Trig { - public static function isPointInPlane( pt : Point, p : Plane, tol : Float ) : Bool{ + public static function isPointInPlane( pt : Point, p : Plane, tol : Float ) : Bool { return Math.abs( pt.sub( p.origin ).dot( p.normal ) ) < tol; } - public static function distToSegment(a : Point, b : Point, c : Point){ + public static function distToSegment( a : Point, b : Point, c : Point ) { var res = segmentClosestPoint( b, a, c, 0.0, 1.0 ); return Vec.dist( b, res.pt ); } @@ -32,9 +32,9 @@ class Trig { //* pt public static function rayClosestPoint( pt, o, r ) { - var o2pt = Vec.sub(pt,o) - , do2ptr = Vec.dot(o2pt, r) - , proj = Vec.add(o, Vec.mul(do2ptr, r)); + var o2pt = Vec.sub( pt, o ) + , do2ptr = Vec.dot( o2pt, r ) + , proj = Vec.add( o, Vec.mul( do2ptr, r ) ); return proj; } @@ -112,22 +112,22 @@ class Trig { var dif = Vec.sub( segpt1, segpt0 ) , l = Vec.norm( dif ); - if (l < Constants.EPSILON ) { + if ( l < Constants.EPSILON ) { return { u: u0, pt : segpt0 }; } var o = segpt0 , r = Vec.mul( 1 / l, dif ) - , o2pt = Vec.sub(pt, o) - , do2ptr = Vec.dot(o2pt, r); + , o2pt = Vec.sub( pt, o ) + , do2ptr = Vec.dot( o2pt, r ); - if (do2ptr < 0){ - return { u: u0, pt : segpt0 }; - } else if (do2ptr > l){ - return { u: u1, pt : segpt1 }; + if ( do2ptr < 0 ) { + return { u: u0, pt : segpt0 }; + } else if ( do2ptr > l ) { + return { u: u1, pt : segpt1 }; } - return { u: u0 + (u1 - u0) * do2ptr / l, pt : Vec.add(o, Vec.mul( do2ptr, r ) ) }; + return { u: u0 + (u1 - u0) * do2ptr / l, pt : Vec.add( o, Vec.mul( do2ptr, r ) ) }; } diff --git a/src/verb/core/Vec.hx b/src/verb/core/Vec.hx index 64740454..1124442e 100644 --- a/src/verb/core/Vec.hx +++ b/src/verb/core/Vec.hx @@ -13,212 +13,243 @@ import verb.core.Data; @:expose("core.Vec") class Vec { - public static function angleBetween(a : Array, b : Array) : Float{ - return Math.acos( dot(a, b) / ( norm(a) * norm(b) ) ); + public static function angleBetween( a : Array, b : Array ) : Float { + return Math.acos( dot( a, b ) / ( norm( a ) * norm( b ) ) ); } - public static function positiveAngleBetween(a : Array, b : Array, n : Array) : Float{ - var nab = Vec.cross(a,b); + public static function positiveAngleBetween( a : Array, b : Array, n : Array ) : Float { + var nab = Vec.cross( a, b ); - var al = Vec.norm(a); - var bl = Vec.norm(b); + var al = Vec.norm( a ); + var bl = Vec.norm( b ); var abl = al * bl; - var adb = Vec.dot(a,b); + var adb = Vec.dot( a, b ); - var sina = Vec.norm(nab) / abl; + var sina = Vec.norm( nab ) / abl; var cosa = adb / abl; var w = Math.atan2( sina, cosa ); - var s = Vec.dot(n, nab); + var s = Vec.dot( n, nab ); - if (Math.abs(s) < Constants.EPSILON) return w; + if ( Math.abs( s ) < Constants.EPSILON ) return w; return s > 0 ? w : -w; } - public static function signedAngleBetween(a : Array, b : Array, n : Array) : Float{ - var nab = Vec.cross(a,b); + public static function signedAngleBetween( a : Array, b : Array, n : Array ) : Float { + var nab = Vec.cross( a, b ); - var al = Vec.norm(a); - var bl = Vec.norm(b); + var al = Vec.norm( a ); + var bl = Vec.norm( b ); var abl = al * bl; - var adb = Vec.dot(a,b); + var adb = Vec.dot( a, b ); - var sina = Vec.norm(nab) / abl; + var sina = Vec.norm( nab ) / abl; var cosa = adb / abl; var w = Math.atan2( sina, cosa ); - var s = Vec.dot(n, nab); + var s = Vec.dot( n, nab ); return s > 0.0 ? w : 2 * Math.PI - w; } - public static function angleBetweenNormalized2d(a : Array, b : Array) : Float { - var perpDot = a[0] * b[1]-a[1] * b[0]; - return Math.atan2(perpDot, dot(a, b)); + public static function angleBetweenNormalized2d( a : Array, b : Array ) : Float { + var perpDot = a[0] * b[1] - a[1] * b[0]; + return Math.atan2( perpDot, dot( a, b ) ); } - public static inline function domain(a : Array) : Float { - return a.last() - a.first(); + public static inline function domain( a : Array ) : Float { + return a.last( ) - a.first( ); } - public static function range(max : Int) : Array { + public static function range( max : Int ) : Array { var l = []; var f = 0.0; - for ( i in 0...max ){ - l.push(f); + for ( i in 0...max ) { + l.push( f ); f += 1.0; } return l; } - public static function span(min : Float, max : Float, step : Float) : Array { + public static function span( min : Float, max : Float, step : Float ) : Array { #if (!cs && !cpp && !java) - if (step == null) return []; + if ( step == null ) return []; #end - if (step < Constants.EPSILON) return []; //infinite - if (min > max && step > 0.0) return []; //infinite - if (max > min && step < 0.0) return []; //infinite + if ( step < Constants.EPSILON ) return []; //infinite + if ( min > max && step > 0.0 ) return []; //infinite + if ( max > min && step < 0.0 ) return []; //infinite var l = []; var cur = min; - while( cur <= max ){ - l.push(cur); + while ( cur <= max ) { + l.push( cur ); cur += step; } return l; } - public static function neg(arr : Array) : Array { - return arr.map(function(x){ return -x; }); + public static function neg( arr : Array ) : Array { + return arr.map( function( x ) { return -x; } ); } - public static function min(arr : Array) : Float { - return arr.fold(function(x,a){ return Math.min(x,a); }, Math.POSITIVE_INFINITY); + public static function min( arr : Array ) : Float { + return arr.fold( function( x, a ) { return Math.min( x, a ); }, Math.POSITIVE_INFINITY ); } - public static function max(arr : Array) : Float { - return arr.fold(function(x,a){ return Math.max(x,a); }, Math.NEGATIVE_INFINITY); + public static function max( arr : Array ) : Float { + return arr.fold( function( x, a ) { return Math.max( x, a ); }, Math.NEGATIVE_INFINITY ); } - public static function all(arr : Array) : Bool { - return arr.fold(function(x,a){ return a && x; }, true); + public static function all( arr : Array ) : Bool { + return arr.fold( function( x, a ) { return a && x; }, true ); } - public static function finite(arr : Array) : Array { - return arr.map(function(x){ return Math.isFinite(x); }); + public static function finite( arr : Array ) : Array { + return arr.map( function( x ) { return Math.isFinite( x ); } ); } - public static function onRay(origin : Point, dir : Vector, u : Float) : Array { - return Vec.add( origin, Vec.mul(u, dir) ); + public static function onRay( origin : Point, dir : Vector, u : Float ) : Array { + return Vec.add( origin, Vec.mul( u, dir ) ); } - public static function lerp(i : Float, u : Array, v : Array) : Array{ - return Vec.add( Vec.mul( i, u ), Vec.mul( 1.0 - i, v) ); + public static function lerp( i : Float, u : Array, v : Array ) : Array { + return Vec.add( Vec.mul( i, u ), Vec.mul( 1.0 - i, v ) ); } - public static function normalized( arr : Array ){ - return div( arr, norm(arr) ); + public static function normalized( arr : Array ) { + return div( arr, norm( arr ) ); } - public static function cross(u : Array, v : Array) : Array{ - return [u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]]; + public static function cross( u : Array, v : Array ) : Array { + return [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]]; } - public static function dist(a : Array, b : Array ) : Float { - return norm(sub(a,b)); + public static function dist( a : Array, b : Array ) : Float { + return norm( sub( a, b ) ); } - public static function distSquared(a : Array, b : Array ) : Float { - return normSquared(sub(a,b)); + public static function distSquared( a : Array, b : Array ) : Float { + return normSquared( sub( a, b ) ); } - public static function sum(a : Iterable) : Float { - return a.fold(function(x,a){ return a + x; }, 0); + public static function sum( a : Iterable ) : Float { + return a.fold( function( x, a ) { return a + x; }, 0 ); } - public static function addAll(a : Iterable>) : Array { - var i = a.iterator(); - if (!i.hasNext()) return null; + public static function addAll( a : Iterable> ) : Array { + var i = a.iterator( ); + if ( !i.hasNext( ) ) return null; - var f = i.next().length; + var f = i.next( ).length; - return a.fold(function(x,a){ return add(a,x); }, rep(f, 0.0)); + return a.fold( function( x, a ) { return add( a, x ); }, rep( f, 0.0 ) ); } - public static function norm(a : Iterable ) : Float { - var norm2 = normSquared(a); + public static function addAllMutate( a : Array> ) { + var f = a[0]; + for ( i in 1...a.length ) + addMutate( f, a[i] ); + } + + public static function addMulMutate( a : Array, s : Float, b : Array ) { + for ( i in 0...a.length ) + a[i] = a[i] + s * b[i]; + } + + public static function subMulMutate( a : Array, s : Float, b : Array ) { + for ( i in 0...a.length ) + a[i] = a[i] - s * b[i]; + } + + public static function addMutate( a : Array, b : Array ) { + for ( i in 0...a.length ) + a[i] = a[i] + b[i]; + } + + public static function subMutate( a : Array, b : Array ) { + for ( i in 0...a.length ) + a[i] = a[i] - b[i]; + } + + public static function mulMutate( a : Float, b : Array ) { + for ( i in 0...b.length ) + b[i] = b[i] * a; + } + + public static function norm( a : Iterable ) : Float { + var norm2 = normSquared( a ); return norm2 != 0.0 ? Math.sqrt( norm2 ) : norm2; } - public static function normSquared(a : Iterable ) : Float { - return a.fold(function(x,a){ return a + x * x; }, 0); + public static function normSquared( a : Iterable ) : Float { + return a.fold( function( x, a ) { return a + x * x; }, 0 ); } - public static function rep(num : Int, ele : T ) : Array { - return [ for (i in 0...num) ele ]; + public static function rep( num : Int, ele : T ) : Array { + return [ for ( i in 0...num ) ele ]; } - public static function zeros1d(rows : Int) : Array { - return [ for (i in 0...rows) 0.0 ]; + public static function zeros1d( rows : Int ) : Array { + return [ for ( i in 0...rows ) 0.0 ]; } - public static function zeros2d(rows : Int, cols : Int) : Array> { - return [ for (i in 0...rows) zeros1d(cols) ]; + public static function zeros2d( rows : Int, cols : Int ) : Array> { + return [ for ( i in 0...rows ) zeros1d( cols ) ]; } - public static function zeros3d(rows : Int, cols : Int, depth : Int) : Array>> { - return [ for (i in 0...rows) zeros2d(cols, depth) ]; + public static function zeros3d( rows : Int, cols : Int, depth : Int ) : Array>> { + return [ for ( i in 0...rows ) zeros2d( cols, depth ) ]; } - public static function dot(a : Array, b : Array) : Float { + public static function dot( a : Array, b : Array ) : Float { var sum : Float = 0; - for (i in 0...a.length){ + for ( i in 0...a.length ) { sum += a[i] * b[i]; } return sum; } - public static function add(a : Array, b : Array) : Array{ - return [ for (i in 0...a.length) a[i] + b[i] ]; + public static function add( a : Array, b : Array ) : Array { + return [ for ( i in 0...a.length ) a[i] + b[i] ]; } - public static function mul(a : Float, b : Array) : Array{ - return [ for (i in 0...b.length) a * b[i] ]; + public static function mul( a : Float, b : Array ) : Array { + return [ for ( i in 0...b.length ) a * b[i] ]; } - public static function div(a : Array, b : Float ) : Array{ - return [ for (i in 0...a.length) a[i] / b ]; + public static function div( a : Array, b : Float ) : Array { + return [ for ( i in 0...a.length ) a[i] / b ]; } - public static function sub(a : Array, b : Array) : Array{ - return [ for (i in 0...a.length) a[i] - b[i] ]; + public static function sub( a : Array, b : Array ) : Array { + return [ for ( i in 0...a.length ) a[i] - b[i] ]; } - public static function isZero( vec : Array ){ + public static function isZero( vec : Array ) { - for (i in 0...vec.length){ - if (Math.abs( vec[i] ) > verb.core.Constants.TOLERANCE ) return false; + for ( i in 0...vec.length ) { + if ( Math.abs( vec[i] ) > verb.core.Constants.TOLERANCE ) return false; } return true; } - public static function sortedSetUnion( a : Array, b : Array) : Array { + public static function sortedSetUnion( a : Array, b : Array ) : Array { var merged = []; var ai = 0; var bi = 0; - while ( ai < a.length || bi < b.length ){ + while ( ai < a.length || bi < b.length ) { - if ( ai >= a.length ){ + if ( ai >= a.length ) { merged.push( b[bi] ); bi++; continue; - } else if ( bi >= b.length ){ + } else if ( bi >= b.length ) { merged.push( a[ai] ); ai++; continue; @@ -226,14 +257,14 @@ class Vec { var diff = a[ai] - b[bi]; - if ( Math.abs(diff) < Constants.EPSILON ){ + if ( Math.abs( diff ) < Constants.EPSILON ) { merged.push( a[ai] ); ai++; bi++; continue; } - if (diff > 0.0){ + if ( diff > 0.0 ) { //add the smaller merged.push( b[bi] ); bi++; @@ -250,21 +281,22 @@ class Vec { } //a is superset, hence it is always longer or equal - public static function sortedSetSub( a : Array, b : Array) : Array { + + public static function sortedSetSub( a : Array, b : Array ) : Array { var result = []; var ai = 0; var bi = 0; - while ( ai < a.length ){ + while ( ai < a.length ) { - if ( bi >= b.length ){ + if ( bi >= b.length ) { result.push( a[ai] ); ai++; continue; } - if ( Math.abs( a[ai] - b[bi] ) < Constants.EPSILON ){ + if ( Math.abs( a[ai] - b[bi] ) < Constants.EPSILON ) { ai++; bi++; continue; @@ -276,4 +308,4 @@ class Vec { return result; } -} \ No newline at end of file +} diff --git a/src/verb/eval/Analyze.hx b/src/verb/eval/Analyze.hx index a4b3031a..62ef00fb 100644 --- a/src/verb/eval/Analyze.hx +++ b/src/verb/eval/Analyze.hx @@ -38,16 +38,16 @@ class Analyze { public static function knotMultiplicities( knots : KnotArray ) : Array { - var mults = [ new KnotMultiplicity( knots[0], 0 ) ]; + var mults = [ new KnotMultiplicity( knots[0], 0 ) ]; var curr : KnotMultiplicity = mults[0]; - for (knot in knots){ - if ( (Math.abs(knot - curr.knot)) > Constants.EPSILON ){ + for ( knot in knots ) { + if ( (Math.abs( knot - curr.knot )) > Constants.EPSILON ) { curr = new KnotMultiplicity(knot, 0); - mults.push(curr); + mults.push( curr ); } - curr.inc(); + curr.inc( ); } return mults; @@ -65,13 +65,13 @@ class Analyze { // //* Whether the surface is continuous or not in the supplied direction. - public static function isRationalSurfaceClosed(surface : NurbsSurfaceData, uDir : Bool = true ) : Bool { + public static function isRationalSurfaceClosed( surface : NurbsSurfaceData, uDir : Bool = true ) : Bool { - var cpts = if (uDir) surface.controlPoints else surface.controlPoints.transpose(); + var cpts = if ( uDir ) surface.controlPoints else surface.controlPoints.transpose( ); - for (i in 0...cpts[0].length){ - var test = Vec.dist( cpts.first()[i], cpts.last()[i] ) < Constants.EPSILON; - if (!test) return false; + for ( i in 0...cpts[0].length ) { + var test = Vec.dist( cpts.first( )[i], cpts.last( )[i] ) < Constants.EPSILON; + if ( !test ) return false; } return true; @@ -155,11 +155,11 @@ class Analyze { , eps2 = 0.0005 , dif , minu = surface.knotsU[0] - , maxu = surface.knotsU.last() + , maxu = surface.knotsU.last( ) , minv = surface.knotsV[0] - , maxv = surface.knotsV.last() - , closedu = isRationalSurfaceClosed(surface) - , closedv = isRationalSurfaceClosed(surface, false) + , maxv = surface.knotsV.last( ) + , closedu = isRationalSurfaceClosed( surface ) + , closedv = isRationalSurfaceClosed( surface, false ) , cuv; //todo: divide surface instead of a full on tessellation @@ -169,21 +169,21 @@ class Analyze { var dmin = Math.POSITIVE_INFINITY; - for ( i in 0...tess.points.length ){ + for ( i in 0...tess.points.length ) { var x = tess.points[i]; var d = Vec.normSquared( Vec.sub( p, x ) ); - if ( d < dmin ){ + if ( d < dmin ) { dmin = d; cuv = tess.uvs[i]; } } - function f(uv : UV) : Array> { + function f( uv : UV ) : Array> { return Eval.rationalSurfaceDerivatives( surface, uv[0], uv[1], 2 ); } - function n(uv : UV, e : Array>, r : Array) : UV { + function n( uv : UV, e : Array>, r : Array ) : UV { //f = Su(u,v) * r = 0 //g = Sv(u,v) * r = 0 @@ -222,10 +222,10 @@ class Analyze { } - while( i < maxits ){ + while ( i < maxits ) { - e = f(cuv); - dif = Vec.sub(e[0][0], p ); + e = f( cuv ); + dif = Vec.sub( e[0][0], p ); // point coincidence // @@ -243,10 +243,10 @@ class Analyze { // ---------------------- < e2 // |Sv(u,v)| |S(u,v) - P| // - var c2an = Vec.dot( e[1][0], dif); + var c2an = Vec.dot( e[1][0], dif ); var c2ad = Vec.norm( e[1][0] ) * c1v; - var c2bn = Vec.dot( e[0][1], dif); + var c2bn = Vec.dot( e[0][1], dif ); var c2bd = Vec.norm( e[0][1] ) * c1v; var c2av = c2an / c2ad; @@ -257,31 +257,31 @@ class Analyze { var c2b = c2bv < eps2; //if all of the tolerance are met, we're done - if (c1 && c2a && c2b){ + if ( c1 && c2a && c2b ) { return cuv; } //otherwise, take a step - var ct = n(cuv, e, dif); + var ct = n( cuv, e, dif ); //correct for exceeding bounds - if ( ct[0] < minu ){ + if ( ct[0] < minu ) { ct = closedu ? [ maxu - ( ct[0] - minu ), ct[1] ] : [ minu + Constants.EPSILON, ct[1] ]; - } else if (ct[0] > maxu){ + } else if ( ct[0] > maxu ) { ct = closedu ? [ minu + ( ct[0] - maxu ), ct[1] ] : [ maxu - Constants.EPSILON, ct[1] ]; } - if ( ct[1] < minv ){ + if ( ct[1] < minv ) { ct = closedv ? [ ct[0], maxv - ( ct[1] - minv ) ] : [ ct[0], minv + Constants.EPSILON ]; - } else if (ct[1] > maxv){ + } else if ( ct[1] > maxv ) { ct = closedv ? [ ct[0], minv + ( ct[0] - maxv ) ] : [ ct[0], maxv - Constants.EPSILON ]; } //if |(u* - u) C'(u)| < e1, halt - var c3v0 = Vec.norm( Vec.mul(ct[0] - cuv[0], e[1][0] ) ); - var c3v1 = Vec.norm( Vec.mul(ct[1] - cuv[1], e[0][1] ) ); + var c3v0 = Vec.norm( Vec.mul( ct[0] - cuv[0], e[1][0] ) ); + var c3v1 = Vec.norm( Vec.mul( ct[1] - cuv[1], e[0][1] ) ); - if (c3v0 + c3v1 < eps1) { + if ( c3v0 + c3v1 < eps1 ) { return cuv; } @@ -306,7 +306,7 @@ class Analyze { //* The closest point on the surface, bounded by the parametric domain of the surface public static function rationalCurveClosestPoint( curve : NurbsCurveData, p : Point ) : Point { - return Eval.rationalCurvePoint( curve, rationalCurveClosestParam(curve, p)); + return Eval.rationalCurvePoint( curve, rationalCurveClosestParam( curve, p ) ); } //Determine the closest parameters on a NURBS curve to a given point. @@ -357,18 +357,19 @@ class Analyze { var pts = Tess.rationalCurveRegularSample( curve, curve.controlPoints.length * curve.degree, true ); - for ( i in 0...pts.length-1){ + for ( i in 0...pts.length - 1 ) { - var u0 = pts[i][0]; - var u1 = pts[i+1][0]; + var u0 = pts[i].pop(); + var u1 = pts[i + 1].pop(); - var p0 = pts[i].slice(1); - var p1 = pts[i+1].slice(1); + var p0 = pts[i]; + var p0 = pts[i]; + var p1 = pts[i + 1]; var proj = Trig.segmentClosestPoint( p, p0, p1, u0, u1 ); var d = Vec.norm( Vec.sub( p, proj.pt ) ); - if ( d < min ){ + if ( d < min ) { min = d; u = proj.u; } @@ -381,15 +382,15 @@ class Analyze { , eps2 = 0.0005 , dif , minu = curve.knots[0] - , maxu = curve.knots.last() - , closed = Vec.normSquared( Vec.sub( curve.controlPoints[0], curve.controlPoints.last() ) ) < Constants.EPSILON + , maxu = curve.knots.last( ) + , closed = Vec.normSquared( Vec.sub( curve.controlPoints[0], curve.controlPoints.last( ) ) ) < Constants.EPSILON , cu = u; - function f(u : Float) : Array { + function f( u : Float ) : Array { return Eval.rationalCurveDerivatives( curve, u, 2 ); } - function n(u : Float, e: Array, d : Array) : Float { + function n( u : Float, e : Array, d : Array ) : Float { // C'(u) * ( C(u) - P ) = 0 = f(u) var f = Vec.dot( e[1], d ); @@ -401,7 +402,7 @@ class Analyze { return u - f / df; } - while( i < maxits ){ + while ( i < maxits ) { e = f( cu ); dif = Vec.sub( e[0], p ); @@ -412,32 +413,32 @@ class Analyze { //C'(u) * (C(u) - P) // ------------------ < e2 // |C'(u)| |C(u) - P| - var c2n = Vec.dot( e[1], dif); + var c2n = Vec.dot( e[1], dif ); var c2d = Vec.norm( e[1] ) * c1v; var c2v = c2n / c2d; var c1 = c1v < eps1; - var c2 = Math.abs(c2v) < eps2; + var c2 = Math.abs( c2v ) < eps2; //if both tolerances are met - if (c1 && c2){ + if ( c1 && c2 ) { return cu; } - var ct = n(cu, e, dif); + var ct = n( cu, e, dif ); //are we outside of the bounds of the curve? - if ( ct < minu ){ + if ( ct < minu ) { ct = closed ? maxu - ( ct - minu ) : minu; - } else if (ct > maxu){ + } else if ( ct > maxu ) { ct = closed ? minu + ( ct - maxu ) : maxu; } //will our next step force us out of the curve? - var c3v = Vec.norm( Vec.mul(ct - cu, e[1] ) ); + var c3v = Vec.norm( Vec.mul( ct - cu, e[1] ) ); - if (c3v < eps1) { + if ( c3v < eps1 ) { return cu; } @@ -464,29 +465,29 @@ class Analyze { // //* The parameter - public static function rationalCurveParamAtArcLength(curve : NurbsCurveData, - len : Float, - tol : Float = 1e-3, - beziers : Array = null, - bezierLengths : Array = null) : Float { + public static function rationalCurveParamAtArcLength( curve : NurbsCurveData, + len : Float, + tol : Float = 1e-3, + beziers : Array = null, + bezierLengths : Array = null ) : Float { - if (len < Constants.EPSILON) return curve.knots[0]; + if ( len < Constants.EPSILON ) return curve.knots[0]; - var crvs = if (beziers != null) beziers else Modify.decomposeCurveIntoBeziers( curve ) + var crvs = if ( beziers != null ) beziers else Modify.decomposeCurveIntoBeziers( curve ) , i = 0 , cc = crvs[i] , cl = -Constants.EPSILON - , bezier_lengths = if (bezierLengths != null) bezierLengths else []; + , bezier_lengths = if ( bezierLengths != null ) bezierLengths else []; //iterate through the curves consuming the bezier's, summing their length along the way - while (cl < len && i < crvs.length){ + while ( cl < len && i < crvs.length ) { bezier_lengths[i] = i < bezier_lengths.length ? bezier_lengths[i] : rationalBezierCurveArcLength( curve ); cl += bezier_lengths[i]; - if (len < cl + Constants.EPSILON){ - return rationalBezierCurveParamAtArcLength(curve, len, tol, bezier_lengths[i]); + if ( len < cl + Constants.EPSILON ) { + return rationalBezierCurveParamAtArcLength( curve, len, tol, bezier_lengths[i] ); } i++; @@ -508,30 +509,30 @@ class Analyze { // //* the parameter - public static function rationalBezierCurveParamAtArcLength(curve : NurbsCurveData, - len : Float, - tol : Float = null, - totalLength : Float = null) : Float { - if (len < 0) return curve.knots[0]; + public static function rationalBezierCurveParamAtArcLength( curve : NurbsCurveData, + len : Float, + tol : Float = null, + totalLength : Float = null ) : Float { + if ( len < 0 ) return curve.knots[0]; //we compute the whole length. if desired length is outside of that, give up var totalLen = totalLength != null ? totalLength : rationalBezierCurveArcLength( curve ); - if (len > totalLen) return curve.knots.last(); + if ( len > totalLen ) return curve.knots.last( ); //divide & conquer //TODO: can we use derivative? var start = { p : curve.knots[0], l : 0.0 } - , end = { p : curve.knots.last(), l : totalLen } + , end = { p : curve.knots.last( ), l : totalLen } , mid = { p : 0.0, l : 0.0 } - , tol = if (tol != null) tol else Constants.TOLERANCE * 2; + , tol = if ( tol != null ) tol else Constants.TOLERANCE * 2; - while ( (end.l - start.l) > tol ){ + while ( (end.l - start.l) > tol ) { mid.p = (start.p + end.p) / 2; - mid.l = rationalBezierCurveArcLength(curve, mid.p ); + mid.l = rationalBezierCurveArcLength( curve, mid.p ); - if (mid.l > len){ + if ( mid.l > len ) { end.p = mid.p; end.l = mid.l; } else { @@ -556,16 +557,16 @@ class Analyze { // //* the approximate length - public static function rationalCurveArcLength(curve : NurbsCurveData, u : Float = null, gaussDegIncrease : Int = 16){ - u = (u == null) ? curve.knots.last() : u; + public static function rationalCurveArcLength( curve : NurbsCurveData, u : Float = null, gaussDegIncrease : Int = 16 ) { + u = (u == null) ? curve.knots.last( ) : u; var crvs = Modify.decomposeCurveIntoBeziers( curve ) , i = 0 , cc = crvs[0] , sum = 0.0; - while ( i < crvs.length && cc.knots[0] + Constants.EPSILON < u ){ - var param = Math.min(cc.knots.last(), u); + while ( i < crvs.length && cc.knots[0] + Constants.EPSILON < u ) { + var param = Math.min( cc.knots.last( ), u ); sum += rationalBezierCurveArcLength( cc, param, gaussDegIncrease ); cc = crvs[++i]; } @@ -585,16 +586,16 @@ class Analyze { // //* the approximate length - public static function rationalBezierCurveArcLength(curve : NurbsCurveData, u : Float = null, gaussDegIncrease : Int = 16) : Float { + public static function rationalBezierCurveArcLength( curve : NurbsCurveData, u : Float = null, gaussDegIncrease : Int = 16 ) : Float { - var u = u == null ? curve.knots.last() : u + var u = u == null ? curve.knots.last( ) : u , z = (u - curve.knots[0]) / 2 , sum = 0.0 , gaussDeg = curve.degree + gaussDegIncrease , cu , tan; - for (i in 0...gaussDeg){ + for ( i in 0...gaussDeg ) { cu = z * Tvalues[gaussDeg][i] + z + curve.knots[0]; tan = Eval.rationalCurveDerivatives( curve, cu, 1 ); @@ -609,57 +610,57 @@ class Analyze { //Legendre-Gauss abscissae (xi values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x)) static var Tvalues : Array> = [ [], [], - [ -0.5773502691896257645091487805019574556476,0.5773502691896257645091487805019574556476], - [0,-0.7745966692414833770358530799564799221665,0.7745966692414833770358530799564799221665], - [ -0.3399810435848562648026657591032446872005,0.3399810435848562648026657591032446872005,-0.8611363115940525752239464888928095050957,0.8611363115940525752239464888928095050957], - [0,-0.5384693101056830910363144207002088049672,0.5384693101056830910363144207002088049672,-0.9061798459386639927976268782993929651256,0.9061798459386639927976268782993929651256], - [ 0.6612093864662645136613995950199053470064,-0.6612093864662645136613995950199053470064,-0.2386191860831969086305017216807119354186,0.2386191860831969086305017216807119354186,-0.9324695142031520278123015544939946091347,0.9324695142031520278123015544939946091347], - [0, 0.4058451513773971669066064120769614633473,-0.4058451513773971669066064120769614633473,-0.7415311855993944398638647732807884070741,0.7415311855993944398638647732807884070741,-0.9491079123427585245261896840478512624007,0.9491079123427585245261896840478512624007], - [ -0.1834346424956498049394761423601839806667,0.1834346424956498049394761423601839806667,-0.5255324099163289858177390491892463490419,0.5255324099163289858177390491892463490419,-0.7966664774136267395915539364758304368371,0.7966664774136267395915539364758304368371,-0.9602898564975362316835608685694729904282,0.9602898564975362316835608685694729904282], - [0,-0.8360311073266357942994297880697348765441,0.8360311073266357942994297880697348765441,-0.9681602395076260898355762029036728700494,0.9681602395076260898355762029036728700494,-0.3242534234038089290385380146433366085719,0.3242534234038089290385380146433366085719,-0.6133714327005903973087020393414741847857,0.6133714327005903973087020393414741847857], - [ -0.1488743389816312108848260011297199846175,0.1488743389816312108848260011297199846175,-0.4333953941292471907992659431657841622000,0.4333953941292471907992659431657841622000,-0.6794095682990244062343273651148735757692,0.6794095682990244062343273651148735757692,-0.8650633666889845107320966884234930485275,0.8650633666889845107320966884234930485275,-0.9739065285171717200779640120844520534282,0.9739065285171717200779640120844520534282], - [0,-0.2695431559523449723315319854008615246796,0.2695431559523449723315319854008615246796,-0.5190961292068118159257256694586095544802,0.5190961292068118159257256694586095544802,-0.7301520055740493240934162520311534580496,0.7301520055740493240934162520311534580496,-0.8870625997680952990751577693039272666316,0.8870625997680952990751577693039272666316,-0.9782286581460569928039380011228573907714,0.9782286581460569928039380011228573907714], - [ -0.1252334085114689154724413694638531299833,0.1252334085114689154724413694638531299833,-0.3678314989981801937526915366437175612563,0.3678314989981801937526915366437175612563,-0.5873179542866174472967024189405342803690,0.5873179542866174472967024189405342803690,-0.7699026741943046870368938332128180759849,0.7699026741943046870368938332128180759849,-0.9041172563704748566784658661190961925375,0.9041172563704748566784658661190961925375,-0.9815606342467192506905490901492808229601,0.9815606342467192506905490901492808229601], - [0,-0.2304583159551347940655281210979888352115,0.2304583159551347940655281210979888352115,-0.4484927510364468528779128521276398678019,0.4484927510364468528779128521276398678019,-0.6423493394403402206439846069955156500716,0.6423493394403402206439846069955156500716,-0.8015780907333099127942064895828598903056,0.8015780907333099127942064895828598903056,-0.9175983992229779652065478365007195123904,0.9175983992229779652065478365007195123904,-0.9841830547185881494728294488071096110649,0.9841830547185881494728294488071096110649], - [ -0.1080549487073436620662446502198347476119,0.1080549487073436620662446502198347476119,-0.3191123689278897604356718241684754668342,0.3191123689278897604356718241684754668342,-0.5152486363581540919652907185511886623088,0.5152486363581540919652907185511886623088,-0.6872929048116854701480198030193341375384,0.6872929048116854701480198030193341375384,-0.8272013150697649931897947426503949610397,0.8272013150697649931897947426503949610397,-0.9284348836635735173363911393778742644770,0.9284348836635735173363911393778742644770,-0.9862838086968123388415972667040528016760,0.9862838086968123388415972667040528016760], - [0,-0.2011940939974345223006283033945962078128,0.2011940939974345223006283033945962078128,-0.3941513470775633698972073709810454683627,0.3941513470775633698972073709810454683627,-0.5709721726085388475372267372539106412383,0.5709721726085388475372267372539106412383,-0.7244177313601700474161860546139380096308,0.7244177313601700474161860546139380096308,-0.8482065834104272162006483207742168513662,0.8482065834104272162006483207742168513662,-0.9372733924007059043077589477102094712439,0.9372733924007059043077589477102094712439,-0.9879925180204854284895657185866125811469,0.9879925180204854284895657185866125811469], - [ -0.0950125098376374401853193354249580631303,0.0950125098376374401853193354249580631303,-0.2816035507792589132304605014604961064860,0.2816035507792589132304605014604961064860,-0.4580167776572273863424194429835775735400,0.4580167776572273863424194429835775735400,-0.6178762444026437484466717640487910189918,0.6178762444026437484466717640487910189918,-0.7554044083550030338951011948474422683538,0.7554044083550030338951011948474422683538,-0.8656312023878317438804678977123931323873,0.8656312023878317438804678977123931323873,-0.9445750230732325760779884155346083450911,0.9445750230732325760779884155346083450911,-0.9894009349916499325961541734503326274262,0.9894009349916499325961541734503326274262], - [0,-0.1784841814958478558506774936540655574754,0.1784841814958478558506774936540655574754,-0.3512317634538763152971855170953460050405,0.3512317634538763152971855170953460050405,-0.5126905370864769678862465686295518745829,0.5126905370864769678862465686295518745829,-0.6576711592166907658503022166430023351478,0.6576711592166907658503022166430023351478,-0.7815140038968014069252300555204760502239,0.7815140038968014069252300555204760502239,-0.8802391537269859021229556944881556926234,0.8802391537269859021229556944881556926234,-0.9506755217687677612227169578958030214433,0.9506755217687677612227169578958030214433,-0.9905754753144173356754340199406652765077,0.9905754753144173356754340199406652765077], - [ -0.0847750130417353012422618529357838117333,0.0847750130417353012422618529357838117333,-0.2518862256915055095889728548779112301628,0.2518862256915055095889728548779112301628,-0.4117511614628426460359317938330516370789,0.4117511614628426460359317938330516370789,-0.5597708310739475346078715485253291369276,0.5597708310739475346078715485253291369276,-0.6916870430603532078748910812888483894522,0.6916870430603532078748910812888483894522,-0.8037049589725231156824174550145907971032,0.8037049589725231156824174550145907971032,-0.8926024664975557392060605911271455154078,0.8926024664975557392060605911271455154078,-0.9558239495713977551811958929297763099728,0.9558239495713977551811958929297763099728,-0.9915651684209309467300160047061507702525,0.9915651684209309467300160047061507702525], - [0,-0.1603586456402253758680961157407435495048,0.1603586456402253758680961157407435495048,-0.3165640999636298319901173288498449178922,0.3165640999636298319901173288498449178922,-0.4645707413759609457172671481041023679762,0.4645707413759609457172671481041023679762,-0.6005453046616810234696381649462392798683,0.6005453046616810234696381649462392798683,-0.7209661773352293786170958608237816296571,0.7209661773352293786170958608237816296571,-0.8227146565371428249789224867127139017745,0.8227146565371428249789224867127139017745,-0.9031559036148179016426609285323124878093,0.9031559036148179016426609285323124878093,-0.9602081521348300308527788406876515266150,0.9602081521348300308527788406876515266150,-0.9924068438435844031890176702532604935893,0.9924068438435844031890176702532604935893], - [ -0.0765265211334973337546404093988382110047,0.0765265211334973337546404093988382110047,-0.2277858511416450780804961953685746247430,0.2277858511416450780804961953685746247430,-0.3737060887154195606725481770249272373957,0.3737060887154195606725481770249272373957,-0.5108670019508270980043640509552509984254,0.5108670019508270980043640509552509984254,-0.6360536807265150254528366962262859367433,0.6360536807265150254528366962262859367433,-0.7463319064601507926143050703556415903107,0.7463319064601507926143050703556415903107,-0.8391169718222188233945290617015206853296,0.8391169718222188233945290617015206853296,-0.9122344282513259058677524412032981130491,0.9122344282513259058677524412032981130491,-0.9639719272779137912676661311972772219120,0.9639719272779137912676661311972772219120,-0.9931285991850949247861223884713202782226,0.9931285991850949247861223884713202782226], - [0,-0.1455618541608950909370309823386863301163,0.1455618541608950909370309823386863301163,-0.2880213168024010966007925160646003199090,0.2880213168024010966007925160646003199090,-0.4243421202074387835736688885437880520964,0.4243421202074387835736688885437880520964,-0.5516188358872198070590187967243132866220,0.5516188358872198070590187967243132866220,-0.6671388041974123193059666699903391625970,0.6671388041974123193059666699903391625970,-0.7684399634756779086158778513062280348209,0.7684399634756779086158778513062280348209,-0.8533633645833172836472506385875676702761,0.8533633645833172836472506385875676702761,-0.9200993341504008287901871337149688941591,0.9200993341504008287901871337149688941591,-0.9672268385663062943166222149076951614246,0.9672268385663062943166222149076951614246,-0.9937521706203895002602420359379409291933,0.9937521706203895002602420359379409291933], - [ -0.0697392733197222212138417961186280818222,0.0697392733197222212138417961186280818222,-0.2078604266882212854788465339195457342156,0.2078604266882212854788465339195457342156,-0.3419358208920842251581474204273796195591,0.3419358208920842251581474204273796195591,-0.4693558379867570264063307109664063460953,0.4693558379867570264063307109664063460953,-0.5876404035069115929588769276386473488776,0.5876404035069115929588769276386473488776,-0.6944872631866827800506898357622567712673,0.6944872631866827800506898357622567712673,-0.7878168059792081620042779554083515213881,0.7878168059792081620042779554083515213881,-0.8658125777203001365364256370193787290847,0.8658125777203001365364256370193787290847,-0.9269567721871740005206929392590531966353,0.9269567721871740005206929392590531966353,-0.9700604978354287271239509867652687108059,0.9700604978354287271239509867652687108059,-0.9942945854823992920730314211612989803930,0.9942945854823992920730314211612989803930], - [0,-0.1332568242984661109317426822417661370104,0.1332568242984661109317426822417661370104,-0.2641356809703449305338695382833096029790,0.2641356809703449305338695382833096029790,-0.3903010380302908314214888728806054585780,0.3903010380302908314214888728806054585780,-0.5095014778460075496897930478668464305448,0.5095014778460075496897930478668464305448,-0.6196098757636461563850973116495956533871,0.6196098757636461563850973116495956533871,-0.7186613631319501944616244837486188483299,0.7186613631319501944616244837486188483299,-0.8048884016188398921511184069967785579414,0.8048884016188398921511184069967785579414,-0.8767523582704416673781568859341456716389,0.8767523582704416673781568859341456716389,-0.9329710868260161023491969890384229782357,0.9329710868260161023491969890384229782357,-0.9725424712181152319560240768207773751816,0.9725424712181152319560240768207773751816,-0.9947693349975521235239257154455743605736,0.9947693349975521235239257154455743605736], - [ -0.0640568928626056260850430826247450385909,0.0640568928626056260850430826247450385909,-0.1911188674736163091586398207570696318404,0.1911188674736163091586398207570696318404,-0.3150426796961633743867932913198102407864,0.3150426796961633743867932913198102407864,-0.4337935076260451384870842319133497124524,0.4337935076260451384870842319133497124524,-0.5454214713888395356583756172183723700107,0.5454214713888395356583756172183723700107,-0.6480936519369755692524957869107476266696,0.6480936519369755692524957869107476266696,-0.7401241915785543642438281030999784255232,0.7401241915785543642438281030999784255232,-0.8200019859739029219539498726697452080761,0.8200019859739029219539498726697452080761,-0.8864155270044010342131543419821967550873,0.8864155270044010342131543419821967550873,-0.9382745520027327585236490017087214496548,0.9382745520027327585236490017087214496548,-0.9747285559713094981983919930081690617411,0.9747285559713094981983919930081690617411,-0.9951872199970213601799974097007368118745,0.9951872199970213601799974097007368118745] + [ -0.5773502691896257645091487805019574556476, 0.5773502691896257645091487805019574556476], + [0, -0.7745966692414833770358530799564799221665, 0.7745966692414833770358530799564799221665], + [ -0.3399810435848562648026657591032446872005, 0.3399810435848562648026657591032446872005, -0.8611363115940525752239464888928095050957, 0.8611363115940525752239464888928095050957], + [0, -0.5384693101056830910363144207002088049672, 0.5384693101056830910363144207002088049672, -0.9061798459386639927976268782993929651256, 0.9061798459386639927976268782993929651256], + [ 0.6612093864662645136613995950199053470064, -0.6612093864662645136613995950199053470064, -0.2386191860831969086305017216807119354186, 0.2386191860831969086305017216807119354186, -0.9324695142031520278123015544939946091347, 0.9324695142031520278123015544939946091347], + [0, 0.4058451513773971669066064120769614633473, -0.4058451513773971669066064120769614633473, -0.7415311855993944398638647732807884070741, 0.7415311855993944398638647732807884070741, -0.9491079123427585245261896840478512624007, 0.9491079123427585245261896840478512624007], + [ -0.1834346424956498049394761423601839806667, 0.1834346424956498049394761423601839806667, -0.5255324099163289858177390491892463490419, 0.5255324099163289858177390491892463490419, -0.7966664774136267395915539364758304368371, 0.7966664774136267395915539364758304368371, -0.9602898564975362316835608685694729904282, 0.9602898564975362316835608685694729904282], + [0, -0.8360311073266357942994297880697348765441, 0.8360311073266357942994297880697348765441, -0.9681602395076260898355762029036728700494, 0.9681602395076260898355762029036728700494, -0.3242534234038089290385380146433366085719, 0.3242534234038089290385380146433366085719, -0.6133714327005903973087020393414741847857, 0.6133714327005903973087020393414741847857], + [ -0.1488743389816312108848260011297199846175, 0.1488743389816312108848260011297199846175, -0.4333953941292471907992659431657841622000, 0.4333953941292471907992659431657841622000, -0.6794095682990244062343273651148735757692, 0.6794095682990244062343273651148735757692, -0.8650633666889845107320966884234930485275, 0.8650633666889845107320966884234930485275, -0.9739065285171717200779640120844520534282, 0.9739065285171717200779640120844520534282], + [0, -0.2695431559523449723315319854008615246796, 0.2695431559523449723315319854008615246796, -0.5190961292068118159257256694586095544802, 0.5190961292068118159257256694586095544802, -0.7301520055740493240934162520311534580496, 0.7301520055740493240934162520311534580496, -0.8870625997680952990751577693039272666316, 0.8870625997680952990751577693039272666316, -0.9782286581460569928039380011228573907714, 0.9782286581460569928039380011228573907714], + [ -0.1252334085114689154724413694638531299833, 0.1252334085114689154724413694638531299833, -0.3678314989981801937526915366437175612563, 0.3678314989981801937526915366437175612563, -0.5873179542866174472967024189405342803690, 0.5873179542866174472967024189405342803690, -0.7699026741943046870368938332128180759849, 0.7699026741943046870368938332128180759849, -0.9041172563704748566784658661190961925375, 0.9041172563704748566784658661190961925375, -0.9815606342467192506905490901492808229601, 0.9815606342467192506905490901492808229601], + [0, -0.2304583159551347940655281210979888352115, 0.2304583159551347940655281210979888352115, -0.4484927510364468528779128521276398678019, 0.4484927510364468528779128521276398678019, -0.6423493394403402206439846069955156500716, 0.6423493394403402206439846069955156500716, -0.8015780907333099127942064895828598903056, 0.8015780907333099127942064895828598903056, -0.9175983992229779652065478365007195123904, 0.9175983992229779652065478365007195123904, -0.9841830547185881494728294488071096110649, 0.9841830547185881494728294488071096110649], + [ -0.1080549487073436620662446502198347476119, 0.1080549487073436620662446502198347476119, -0.3191123689278897604356718241684754668342, 0.3191123689278897604356718241684754668342, -0.5152486363581540919652907185511886623088, 0.5152486363581540919652907185511886623088, -0.6872929048116854701480198030193341375384, 0.6872929048116854701480198030193341375384, -0.8272013150697649931897947426503949610397, 0.8272013150697649931897947426503949610397, -0.9284348836635735173363911393778742644770, 0.9284348836635735173363911393778742644770, -0.9862838086968123388415972667040528016760, 0.9862838086968123388415972667040528016760], + [0, -0.2011940939974345223006283033945962078128, 0.2011940939974345223006283033945962078128, -0.3941513470775633698972073709810454683627, 0.3941513470775633698972073709810454683627, -0.5709721726085388475372267372539106412383, 0.5709721726085388475372267372539106412383, -0.7244177313601700474161860546139380096308, 0.7244177313601700474161860546139380096308, -0.8482065834104272162006483207742168513662, 0.8482065834104272162006483207742168513662, -0.9372733924007059043077589477102094712439, 0.9372733924007059043077589477102094712439, -0.9879925180204854284895657185866125811469, 0.9879925180204854284895657185866125811469], + [ -0.0950125098376374401853193354249580631303, 0.0950125098376374401853193354249580631303, -0.2816035507792589132304605014604961064860, 0.2816035507792589132304605014604961064860, -0.4580167776572273863424194429835775735400, 0.4580167776572273863424194429835775735400, -0.6178762444026437484466717640487910189918, 0.6178762444026437484466717640487910189918, -0.7554044083550030338951011948474422683538, 0.7554044083550030338951011948474422683538, -0.8656312023878317438804678977123931323873, 0.8656312023878317438804678977123931323873, -0.9445750230732325760779884155346083450911, 0.9445750230732325760779884155346083450911, -0.9894009349916499325961541734503326274262, 0.9894009349916499325961541734503326274262], + [0, -0.1784841814958478558506774936540655574754, 0.1784841814958478558506774936540655574754, -0.3512317634538763152971855170953460050405, 0.3512317634538763152971855170953460050405, -0.5126905370864769678862465686295518745829, 0.5126905370864769678862465686295518745829, -0.6576711592166907658503022166430023351478, 0.6576711592166907658503022166430023351478, -0.7815140038968014069252300555204760502239, 0.7815140038968014069252300555204760502239, -0.8802391537269859021229556944881556926234, 0.8802391537269859021229556944881556926234, -0.9506755217687677612227169578958030214433, 0.9506755217687677612227169578958030214433, -0.9905754753144173356754340199406652765077, 0.9905754753144173356754340199406652765077], + [ -0.0847750130417353012422618529357838117333, 0.0847750130417353012422618529357838117333, -0.2518862256915055095889728548779112301628, 0.2518862256915055095889728548779112301628, -0.4117511614628426460359317938330516370789, 0.4117511614628426460359317938330516370789, -0.5597708310739475346078715485253291369276, 0.5597708310739475346078715485253291369276, -0.6916870430603532078748910812888483894522, 0.6916870430603532078748910812888483894522, -0.8037049589725231156824174550145907971032, 0.8037049589725231156824174550145907971032, -0.8926024664975557392060605911271455154078, 0.8926024664975557392060605911271455154078, -0.9558239495713977551811958929297763099728, 0.9558239495713977551811958929297763099728, -0.9915651684209309467300160047061507702525, 0.9915651684209309467300160047061507702525], + [0, -0.1603586456402253758680961157407435495048, 0.1603586456402253758680961157407435495048, -0.3165640999636298319901173288498449178922, 0.3165640999636298319901173288498449178922, -0.4645707413759609457172671481041023679762, 0.4645707413759609457172671481041023679762, -0.6005453046616810234696381649462392798683, 0.6005453046616810234696381649462392798683, -0.7209661773352293786170958608237816296571, 0.7209661773352293786170958608237816296571, -0.8227146565371428249789224867127139017745, 0.8227146565371428249789224867127139017745, -0.9031559036148179016426609285323124878093, 0.9031559036148179016426609285323124878093, -0.9602081521348300308527788406876515266150, 0.9602081521348300308527788406876515266150, -0.9924068438435844031890176702532604935893, 0.9924068438435844031890176702532604935893], + [ -0.0765265211334973337546404093988382110047, 0.0765265211334973337546404093988382110047, -0.2277858511416450780804961953685746247430, 0.2277858511416450780804961953685746247430, -0.3737060887154195606725481770249272373957, 0.3737060887154195606725481770249272373957, -0.5108670019508270980043640509552509984254, 0.5108670019508270980043640509552509984254, -0.6360536807265150254528366962262859367433, 0.6360536807265150254528366962262859367433, -0.7463319064601507926143050703556415903107, 0.7463319064601507926143050703556415903107, -0.8391169718222188233945290617015206853296, 0.8391169718222188233945290617015206853296, -0.9122344282513259058677524412032981130491, 0.9122344282513259058677524412032981130491, -0.9639719272779137912676661311972772219120, 0.9639719272779137912676661311972772219120, -0.9931285991850949247861223884713202782226, 0.9931285991850949247861223884713202782226], + [0, -0.1455618541608950909370309823386863301163, 0.1455618541608950909370309823386863301163, -0.2880213168024010966007925160646003199090, 0.2880213168024010966007925160646003199090, -0.4243421202074387835736688885437880520964, 0.4243421202074387835736688885437880520964, -0.5516188358872198070590187967243132866220, 0.5516188358872198070590187967243132866220, -0.6671388041974123193059666699903391625970, 0.6671388041974123193059666699903391625970, -0.7684399634756779086158778513062280348209, 0.7684399634756779086158778513062280348209, -0.8533633645833172836472506385875676702761, 0.8533633645833172836472506385875676702761, -0.9200993341504008287901871337149688941591, 0.9200993341504008287901871337149688941591, -0.9672268385663062943166222149076951614246, 0.9672268385663062943166222149076951614246, -0.9937521706203895002602420359379409291933, 0.9937521706203895002602420359379409291933], + [ -0.0697392733197222212138417961186280818222, 0.0697392733197222212138417961186280818222, -0.2078604266882212854788465339195457342156, 0.2078604266882212854788465339195457342156, -0.3419358208920842251581474204273796195591, 0.3419358208920842251581474204273796195591, -0.4693558379867570264063307109664063460953, 0.4693558379867570264063307109664063460953, -0.5876404035069115929588769276386473488776, 0.5876404035069115929588769276386473488776, -0.6944872631866827800506898357622567712673, 0.6944872631866827800506898357622567712673, -0.7878168059792081620042779554083515213881, 0.7878168059792081620042779554083515213881, -0.8658125777203001365364256370193787290847, 0.8658125777203001365364256370193787290847, -0.9269567721871740005206929392590531966353, 0.9269567721871740005206929392590531966353, -0.9700604978354287271239509867652687108059, 0.9700604978354287271239509867652687108059, -0.9942945854823992920730314211612989803930, 0.9942945854823992920730314211612989803930], + [0, -0.1332568242984661109317426822417661370104, 0.1332568242984661109317426822417661370104, -0.2641356809703449305338695382833096029790, 0.2641356809703449305338695382833096029790, -0.3903010380302908314214888728806054585780, 0.3903010380302908314214888728806054585780, -0.5095014778460075496897930478668464305448, 0.5095014778460075496897930478668464305448, -0.6196098757636461563850973116495956533871, 0.6196098757636461563850973116495956533871, -0.7186613631319501944616244837486188483299, 0.7186613631319501944616244837486188483299, -0.8048884016188398921511184069967785579414, 0.8048884016188398921511184069967785579414, -0.8767523582704416673781568859341456716389, 0.8767523582704416673781568859341456716389, -0.9329710868260161023491969890384229782357, 0.9329710868260161023491969890384229782357, -0.9725424712181152319560240768207773751816, 0.9725424712181152319560240768207773751816, -0.9947693349975521235239257154455743605736, 0.9947693349975521235239257154455743605736], + [ -0.0640568928626056260850430826247450385909, 0.0640568928626056260850430826247450385909, -0.1911188674736163091586398207570696318404, 0.1911188674736163091586398207570696318404, -0.3150426796961633743867932913198102407864, 0.3150426796961633743867932913198102407864, -0.4337935076260451384870842319133497124524, 0.4337935076260451384870842319133497124524, -0.5454214713888395356583756172183723700107, 0.5454214713888395356583756172183723700107, -0.6480936519369755692524957869107476266696, 0.6480936519369755692524957869107476266696, -0.7401241915785543642438281030999784255232, 0.7401241915785543642438281030999784255232, -0.8200019859739029219539498726697452080761, 0.8200019859739029219539498726697452080761, -0.8864155270044010342131543419821967550873, 0.8864155270044010342131543419821967550873, -0.9382745520027327585236490017087214496548, 0.9382745520027327585236490017087214496548, -0.9747285559713094981983919930081690617411, 0.9747285559713094981983919930081690617411, -0.9951872199970213601799974097007368118745, 0.9951872199970213601799974097007368118745] ]; //Legendre-Gauss weights - static var Cvalues : Array> = [ - [],[], - [1.0,1.0], - [0.8888888888888888888888888888888888888888,0.5555555555555555555555555555555555555555,0.5555555555555555555555555555555555555555], - [0.6521451548625461426269360507780005927646,0.6521451548625461426269360507780005927646,0.3478548451374538573730639492219994072353,0.3478548451374538573730639492219994072353], - [0.5688888888888888888888888888888888888888,0.4786286704993664680412915148356381929122,0.4786286704993664680412915148356381929122,0.2369268850561890875142640407199173626432,0.2369268850561890875142640407199173626432], - [0.3607615730481386075698335138377161116615,0.3607615730481386075698335138377161116615,0.4679139345726910473898703439895509948116,0.4679139345726910473898703439895509948116,0.1713244923791703450402961421727328935268,0.1713244923791703450402961421727328935268], - [0.4179591836734693877551020408163265306122,0.3818300505051189449503697754889751338783,0.3818300505051189449503697754889751338783,0.2797053914892766679014677714237795824869,0.2797053914892766679014677714237795824869,0.1294849661688696932706114326790820183285,0.1294849661688696932706114326790820183285], - [0.3626837833783619829651504492771956121941,0.3626837833783619829651504492771956121941,0.3137066458778872873379622019866013132603,0.3137066458778872873379622019866013132603,0.2223810344533744705443559944262408844301,0.2223810344533744705443559944262408844301,0.1012285362903762591525313543099621901153,0.1012285362903762591525313543099621901153], - [0.3302393550012597631645250692869740488788,0.1806481606948574040584720312429128095143,0.1806481606948574040584720312429128095143,0.0812743883615744119718921581105236506756,0.0812743883615744119718921581105236506756,0.3123470770400028400686304065844436655987,0.3123470770400028400686304065844436655987,0.2606106964029354623187428694186328497718,0.2606106964029354623187428694186328497718], - [0.2955242247147528701738929946513383294210,0.2955242247147528701738929946513383294210,0.2692667193099963550912269215694693528597,0.2692667193099963550912269215694693528597,0.2190863625159820439955349342281631924587,0.2190863625159820439955349342281631924587,0.1494513491505805931457763396576973324025,0.1494513491505805931457763396576973324025,0.0666713443086881375935688098933317928578,0.0666713443086881375935688098933317928578], - [0.2729250867779006307144835283363421891560,0.2628045445102466621806888698905091953727,0.2628045445102466621806888698905091953727,0.2331937645919904799185237048431751394317,0.2331937645919904799185237048431751394317,0.1862902109277342514260976414316558916912,0.1862902109277342514260976414316558916912,0.1255803694649046246346942992239401001976,0.1255803694649046246346942992239401001976,0.0556685671161736664827537204425485787285,0.0556685671161736664827537204425485787285], - [0.2491470458134027850005624360429512108304,0.2491470458134027850005624360429512108304,0.2334925365383548087608498989248780562594,0.2334925365383548087608498989248780562594,0.2031674267230659217490644558097983765065,0.2031674267230659217490644558097983765065,0.1600783285433462263346525295433590718720,0.1600783285433462263346525295433590718720,0.1069393259953184309602547181939962242145,0.1069393259953184309602547181939962242145,0.0471753363865118271946159614850170603170,0.0471753363865118271946159614850170603170], - [0.2325515532308739101945895152688359481566,0.2262831802628972384120901860397766184347,0.2262831802628972384120901860397766184347,0.2078160475368885023125232193060527633865,0.2078160475368885023125232193060527633865,0.1781459807619457382800466919960979955128,0.1781459807619457382800466919960979955128,0.1388735102197872384636017768688714676218,0.1388735102197872384636017768688714676218,0.0921214998377284479144217759537971209236,0.0921214998377284479144217759537971209236,0.0404840047653158795200215922009860600419,0.0404840047653158795200215922009860600419], - [0.2152638534631577901958764433162600352749,0.2152638534631577901958764433162600352749,0.2051984637212956039659240656612180557103,0.2051984637212956039659240656612180557103,0.1855383974779378137417165901251570362489,0.1855383974779378137417165901251570362489,0.1572031671581935345696019386238421566056,0.1572031671581935345696019386238421566056,0.1215185706879031846894148090724766259566,0.1215185706879031846894148090724766259566,0.0801580871597602098056332770628543095836,0.0801580871597602098056332770628543095836,0.0351194603317518630318328761381917806197,0.0351194603317518630318328761381917806197], - [0.2025782419255612728806201999675193148386,0.1984314853271115764561183264438393248186,0.1984314853271115764561183264438393248186,0.1861610000155622110268005618664228245062,0.1861610000155622110268005618664228245062,0.1662692058169939335532008604812088111309,0.1662692058169939335532008604812088111309,0.1395706779261543144478047945110283225208,0.1395706779261543144478047945110283225208,0.1071592204671719350118695466858693034155,0.1071592204671719350118695466858693034155,0.0703660474881081247092674164506673384667,0.0703660474881081247092674164506673384667,0.0307532419961172683546283935772044177217,0.0307532419961172683546283935772044177217], - [0.1894506104550684962853967232082831051469,0.1894506104550684962853967232082831051469,0.1826034150449235888667636679692199393835,0.1826034150449235888667636679692199393835,0.1691565193950025381893120790303599622116,0.1691565193950025381893120790303599622116,0.1495959888165767320815017305474785489704,0.1495959888165767320815017305474785489704,0.1246289712555338720524762821920164201448,0.1246289712555338720524762821920164201448,0.0951585116824927848099251076022462263552,0.0951585116824927848099251076022462263552,0.0622535239386478928628438369943776942749,0.0622535239386478928628438369943776942749,0.0271524594117540948517805724560181035122,0.0271524594117540948517805724560181035122], - [0.1794464703562065254582656442618856214487,0.1765627053669926463252709901131972391509,0.1765627053669926463252709901131972391509,0.1680041021564500445099706637883231550211,0.1680041021564500445099706637883231550211,0.1540457610768102880814315948019586119404,0.1540457610768102880814315948019586119404,0.1351363684685254732863199817023501973721,0.1351363684685254732863199817023501973721,0.1118838471934039710947883856263559267358,0.1118838471934039710947883856263559267358,0.0850361483171791808835353701910620738504,0.0850361483171791808835353701910620738504,0.0554595293739872011294401653582446605128,0.0554595293739872011294401653582446605128,0.0241483028685479319601100262875653246916,0.0241483028685479319601100262875653246916], - [0.1691423829631435918406564701349866103341,0.1691423829631435918406564701349866103341,0.1642764837458327229860537764659275904123,0.1642764837458327229860537764659275904123,0.1546846751262652449254180038363747721932,0.1546846751262652449254180038363747721932,0.1406429146706506512047313037519472280955,0.1406429146706506512047313037519472280955,0.1225552067114784601845191268002015552281,0.1225552067114784601845191268002015552281,0.1009420441062871655628139849248346070628,0.1009420441062871655628139849248346070628,0.0764257302548890565291296776166365256053,0.0764257302548890565291296776166365256053,0.0497145488949697964533349462026386416808,0.0497145488949697964533349462026386416808,0.0216160135264833103133427102664524693876,0.0216160135264833103133427102664524693876], - [0.1610544498487836959791636253209167350399,0.1589688433939543476499564394650472016787,0.1589688433939543476499564394650472016787,0.1527660420658596667788554008976629984610,0.1527660420658596667788554008976629984610,0.1426067021736066117757461094419029724756,0.1426067021736066117757461094419029724756,0.1287539625393362276755157848568771170558,0.1287539625393362276755157848568771170558,0.1115666455473339947160239016817659974813,0.1115666455473339947160239016817659974813,0.0914900216224499994644620941238396526609,0.0914900216224499994644620941238396526609,0.0690445427376412265807082580060130449618,0.0690445427376412265807082580060130449618,0.0448142267656996003328381574019942119517,0.0448142267656996003328381574019942119517,0.0194617882297264770363120414644384357529,0.0194617882297264770363120414644384357529], - [0.1527533871307258506980843319550975934919,0.1527533871307258506980843319550975934919,0.1491729864726037467878287370019694366926,0.1491729864726037467878287370019694366926,0.1420961093183820513292983250671649330345,0.1420961093183820513292983250671649330345,0.1316886384491766268984944997481631349161,0.1316886384491766268984944997481631349161,0.1181945319615184173123773777113822870050,0.1181945319615184173123773777113822870050,0.1019301198172404350367501354803498761666,0.1019301198172404350367501354803498761666,0.0832767415767047487247581432220462061001,0.0832767415767047487247581432220462061001,0.0626720483341090635695065351870416063516,0.0626720483341090635695065351870416063516,0.0406014298003869413310399522749321098790,0.0406014298003869413310399522749321098790,0.0176140071391521183118619623518528163621,0.0176140071391521183118619623518528163621], - [0.1460811336496904271919851476833711882448,0.1445244039899700590638271665537525436099,0.1445244039899700590638271665537525436099,0.1398873947910731547221334238675831108927,0.1398873947910731547221334238675831108927,0.1322689386333374617810525744967756043290,0.1322689386333374617810525744967756043290,0.1218314160537285341953671771257335983563,0.1218314160537285341953671771257335983563,0.1087972991671483776634745780701056420336,0.1087972991671483776634745780701056420336,0.0934444234560338615532897411139320884835,0.0934444234560338615532897411139320884835,0.0761001136283793020170516533001831792261,0.0761001136283793020170516533001831792261,0.0571344254268572082836358264724479574912,0.0571344254268572082836358264724479574912,0.0369537897708524937999506682993296661889,0.0369537897708524937999506682993296661889,0.0160172282577743333242246168584710152658,0.0160172282577743333242246168584710152658], - [0.1392518728556319933754102483418099578739,0.1392518728556319933754102483418099578739,0.1365414983460151713525738312315173965863,0.1365414983460151713525738312315173965863,0.1311735047870623707329649925303074458757,0.1311735047870623707329649925303074458757,0.1232523768105124242855609861548144719594,0.1232523768105124242855609861548144719594,0.1129322960805392183934006074217843191142,0.1129322960805392183934006074217843191142,0.1004141444428809649320788378305362823508,0.1004141444428809649320788378305362823508,0.0859416062170677274144436813727028661891,0.0859416062170677274144436813727028661891,0.0697964684245204880949614189302176573987,0.0697964684245204880949614189302176573987,0.0522933351526832859403120512732112561121,0.0522933351526832859403120512732112561121,0.0337749015848141547933022468659129013491,0.0337749015848141547933022468659129013491,0.0146279952982722006849910980471854451902,0.0146279952982722006849910980471854451902], - [0.1336545721861061753514571105458443385831,0.1324620394046966173716424647033169258050,0.1324620394046966173716424647033169258050,0.1289057221880821499785953393997936532597,0.1289057221880821499785953393997936532597,0.1230490843067295304675784006720096548158,0.1230490843067295304675784006720096548158,0.1149966402224113649416435129339613014914,0.1149966402224113649416435129339613014914,0.1048920914645414100740861850147438548584,0.1048920914645414100740861850147438548584,0.0929157660600351474770186173697646486034,0.0929157660600351474770186173697646486034,0.0792814117767189549228925247420432269137,0.0792814117767189549228925247420432269137,0.0642324214085258521271696151589109980391,0.0642324214085258521271696151589109980391,0.0480376717310846685716410716320339965612,0.0480376717310846685716410716320339965612,0.0309880058569794443106942196418845053837,0.0309880058569794443106942196418845053837,0.0134118594871417720813094934586150649766,0.0134118594871417720813094934586150649766], - [0.1279381953467521569740561652246953718517,0.1279381953467521569740561652246953718517,0.1258374563468282961213753825111836887264,0.1258374563468282961213753825111836887264,0.1216704729278033912044631534762624256070,0.1216704729278033912044631534762624256070,0.1155056680537256013533444839067835598622,0.1155056680537256013533444839067835598622,0.1074442701159656347825773424466062227946,0.1074442701159656347825773424466062227946,0.0976186521041138882698806644642471544279,0.0976186521041138882698806644642471544279,0.0861901615319532759171852029837426671850,0.0861901615319532759171852029837426671850,0.0733464814110803057340336152531165181193,0.0733464814110803057340336152531165181193,0.0592985849154367807463677585001085845412,0.0592985849154367807463677585001085845412,0.0442774388174198061686027482113382288593,0.0442774388174198061686027482113382288593,0.0285313886289336631813078159518782864491,0.0285313886289336631813078159518782864491,0.0123412297999871995468056670700372915759,0.0123412297999871995468056670700372915759] + static var Cvalues : Array> = [ + [], [], + [1.0, 1.0], + [0.8888888888888888888888888888888888888888, 0.5555555555555555555555555555555555555555, 0.5555555555555555555555555555555555555555], + [0.6521451548625461426269360507780005927646, 0.6521451548625461426269360507780005927646, 0.3478548451374538573730639492219994072353, 0.3478548451374538573730639492219994072353], + [0.5688888888888888888888888888888888888888, 0.4786286704993664680412915148356381929122, 0.4786286704993664680412915148356381929122, 0.2369268850561890875142640407199173626432, 0.2369268850561890875142640407199173626432], + [0.3607615730481386075698335138377161116615, 0.3607615730481386075698335138377161116615, 0.4679139345726910473898703439895509948116, 0.4679139345726910473898703439895509948116, 0.1713244923791703450402961421727328935268, 0.1713244923791703450402961421727328935268], + [0.4179591836734693877551020408163265306122, 0.3818300505051189449503697754889751338783, 0.3818300505051189449503697754889751338783, 0.2797053914892766679014677714237795824869, 0.2797053914892766679014677714237795824869, 0.1294849661688696932706114326790820183285, 0.1294849661688696932706114326790820183285], + [0.3626837833783619829651504492771956121941, 0.3626837833783619829651504492771956121941, 0.3137066458778872873379622019866013132603, 0.3137066458778872873379622019866013132603, 0.2223810344533744705443559944262408844301, 0.2223810344533744705443559944262408844301, 0.1012285362903762591525313543099621901153, 0.1012285362903762591525313543099621901153], + [0.3302393550012597631645250692869740488788, 0.1806481606948574040584720312429128095143, 0.1806481606948574040584720312429128095143, 0.0812743883615744119718921581105236506756, 0.0812743883615744119718921581105236506756, 0.3123470770400028400686304065844436655987, 0.3123470770400028400686304065844436655987, 0.2606106964029354623187428694186328497718, 0.2606106964029354623187428694186328497718], + [0.2955242247147528701738929946513383294210, 0.2955242247147528701738929946513383294210, 0.2692667193099963550912269215694693528597, 0.2692667193099963550912269215694693528597, 0.2190863625159820439955349342281631924587, 0.2190863625159820439955349342281631924587, 0.1494513491505805931457763396576973324025, 0.1494513491505805931457763396576973324025, 0.0666713443086881375935688098933317928578, 0.0666713443086881375935688098933317928578], + [0.2729250867779006307144835283363421891560, 0.2628045445102466621806888698905091953727, 0.2628045445102466621806888698905091953727, 0.2331937645919904799185237048431751394317, 0.2331937645919904799185237048431751394317, 0.1862902109277342514260976414316558916912, 0.1862902109277342514260976414316558916912, 0.1255803694649046246346942992239401001976, 0.1255803694649046246346942992239401001976, 0.0556685671161736664827537204425485787285, 0.0556685671161736664827537204425485787285], + [0.2491470458134027850005624360429512108304, 0.2491470458134027850005624360429512108304, 0.2334925365383548087608498989248780562594, 0.2334925365383548087608498989248780562594, 0.2031674267230659217490644558097983765065, 0.2031674267230659217490644558097983765065, 0.1600783285433462263346525295433590718720, 0.1600783285433462263346525295433590718720, 0.1069393259953184309602547181939962242145, 0.1069393259953184309602547181939962242145, 0.0471753363865118271946159614850170603170, 0.0471753363865118271946159614850170603170], + [0.2325515532308739101945895152688359481566, 0.2262831802628972384120901860397766184347, 0.2262831802628972384120901860397766184347, 0.2078160475368885023125232193060527633865, 0.2078160475368885023125232193060527633865, 0.1781459807619457382800466919960979955128, 0.1781459807619457382800466919960979955128, 0.1388735102197872384636017768688714676218, 0.1388735102197872384636017768688714676218, 0.0921214998377284479144217759537971209236, 0.0921214998377284479144217759537971209236, 0.0404840047653158795200215922009860600419, 0.0404840047653158795200215922009860600419], + [0.2152638534631577901958764433162600352749, 0.2152638534631577901958764433162600352749, 0.2051984637212956039659240656612180557103, 0.2051984637212956039659240656612180557103, 0.1855383974779378137417165901251570362489, 0.1855383974779378137417165901251570362489, 0.1572031671581935345696019386238421566056, 0.1572031671581935345696019386238421566056, 0.1215185706879031846894148090724766259566, 0.1215185706879031846894148090724766259566, 0.0801580871597602098056332770628543095836, 0.0801580871597602098056332770628543095836, 0.0351194603317518630318328761381917806197, 0.0351194603317518630318328761381917806197], + [0.2025782419255612728806201999675193148386, 0.1984314853271115764561183264438393248186, 0.1984314853271115764561183264438393248186, 0.1861610000155622110268005618664228245062, 0.1861610000155622110268005618664228245062, 0.1662692058169939335532008604812088111309, 0.1662692058169939335532008604812088111309, 0.1395706779261543144478047945110283225208, 0.1395706779261543144478047945110283225208, 0.1071592204671719350118695466858693034155, 0.1071592204671719350118695466858693034155, 0.0703660474881081247092674164506673384667, 0.0703660474881081247092674164506673384667, 0.0307532419961172683546283935772044177217, 0.0307532419961172683546283935772044177217], + [0.1894506104550684962853967232082831051469, 0.1894506104550684962853967232082831051469, 0.1826034150449235888667636679692199393835, 0.1826034150449235888667636679692199393835, 0.1691565193950025381893120790303599622116, 0.1691565193950025381893120790303599622116, 0.1495959888165767320815017305474785489704, 0.1495959888165767320815017305474785489704, 0.1246289712555338720524762821920164201448, 0.1246289712555338720524762821920164201448, 0.0951585116824927848099251076022462263552, 0.0951585116824927848099251076022462263552, 0.0622535239386478928628438369943776942749, 0.0622535239386478928628438369943776942749, 0.0271524594117540948517805724560181035122, 0.0271524594117540948517805724560181035122], + [0.1794464703562065254582656442618856214487, 0.1765627053669926463252709901131972391509, 0.1765627053669926463252709901131972391509, 0.1680041021564500445099706637883231550211, 0.1680041021564500445099706637883231550211, 0.1540457610768102880814315948019586119404, 0.1540457610768102880814315948019586119404, 0.1351363684685254732863199817023501973721, 0.1351363684685254732863199817023501973721, 0.1118838471934039710947883856263559267358, 0.1118838471934039710947883856263559267358, 0.0850361483171791808835353701910620738504, 0.0850361483171791808835353701910620738504, 0.0554595293739872011294401653582446605128, 0.0554595293739872011294401653582446605128, 0.0241483028685479319601100262875653246916, 0.0241483028685479319601100262875653246916], + [0.1691423829631435918406564701349866103341, 0.1691423829631435918406564701349866103341, 0.1642764837458327229860537764659275904123, 0.1642764837458327229860537764659275904123, 0.1546846751262652449254180038363747721932, 0.1546846751262652449254180038363747721932, 0.1406429146706506512047313037519472280955, 0.1406429146706506512047313037519472280955, 0.1225552067114784601845191268002015552281, 0.1225552067114784601845191268002015552281, 0.1009420441062871655628139849248346070628, 0.1009420441062871655628139849248346070628, 0.0764257302548890565291296776166365256053, 0.0764257302548890565291296776166365256053, 0.0497145488949697964533349462026386416808, 0.0497145488949697964533349462026386416808, 0.0216160135264833103133427102664524693876, 0.0216160135264833103133427102664524693876], + [0.1610544498487836959791636253209167350399, 0.1589688433939543476499564394650472016787, 0.1589688433939543476499564394650472016787, 0.1527660420658596667788554008976629984610, 0.1527660420658596667788554008976629984610, 0.1426067021736066117757461094419029724756, 0.1426067021736066117757461094419029724756, 0.1287539625393362276755157848568771170558, 0.1287539625393362276755157848568771170558, 0.1115666455473339947160239016817659974813, 0.1115666455473339947160239016817659974813, 0.0914900216224499994644620941238396526609, 0.0914900216224499994644620941238396526609, 0.0690445427376412265807082580060130449618, 0.0690445427376412265807082580060130449618, 0.0448142267656996003328381574019942119517, 0.0448142267656996003328381574019942119517, 0.0194617882297264770363120414644384357529, 0.0194617882297264770363120414644384357529], + [0.1527533871307258506980843319550975934919, 0.1527533871307258506980843319550975934919, 0.1491729864726037467878287370019694366926, 0.1491729864726037467878287370019694366926, 0.1420961093183820513292983250671649330345, 0.1420961093183820513292983250671649330345, 0.1316886384491766268984944997481631349161, 0.1316886384491766268984944997481631349161, 0.1181945319615184173123773777113822870050, 0.1181945319615184173123773777113822870050, 0.1019301198172404350367501354803498761666, 0.1019301198172404350367501354803498761666, 0.0832767415767047487247581432220462061001, 0.0832767415767047487247581432220462061001, 0.0626720483341090635695065351870416063516, 0.0626720483341090635695065351870416063516, 0.0406014298003869413310399522749321098790, 0.0406014298003869413310399522749321098790, 0.0176140071391521183118619623518528163621, 0.0176140071391521183118619623518528163621], + [0.1460811336496904271919851476833711882448, 0.1445244039899700590638271665537525436099, 0.1445244039899700590638271665537525436099, 0.1398873947910731547221334238675831108927, 0.1398873947910731547221334238675831108927, 0.1322689386333374617810525744967756043290, 0.1322689386333374617810525744967756043290, 0.1218314160537285341953671771257335983563, 0.1218314160537285341953671771257335983563, 0.1087972991671483776634745780701056420336, 0.1087972991671483776634745780701056420336, 0.0934444234560338615532897411139320884835, 0.0934444234560338615532897411139320884835, 0.0761001136283793020170516533001831792261, 0.0761001136283793020170516533001831792261, 0.0571344254268572082836358264724479574912, 0.0571344254268572082836358264724479574912, 0.0369537897708524937999506682993296661889, 0.0369537897708524937999506682993296661889, 0.0160172282577743333242246168584710152658, 0.0160172282577743333242246168584710152658], + [0.1392518728556319933754102483418099578739, 0.1392518728556319933754102483418099578739, 0.1365414983460151713525738312315173965863, 0.1365414983460151713525738312315173965863, 0.1311735047870623707329649925303074458757, 0.1311735047870623707329649925303074458757, 0.1232523768105124242855609861548144719594, 0.1232523768105124242855609861548144719594, 0.1129322960805392183934006074217843191142, 0.1129322960805392183934006074217843191142, 0.1004141444428809649320788378305362823508, 0.1004141444428809649320788378305362823508, 0.0859416062170677274144436813727028661891, 0.0859416062170677274144436813727028661891, 0.0697964684245204880949614189302176573987, 0.0697964684245204880949614189302176573987, 0.0522933351526832859403120512732112561121, 0.0522933351526832859403120512732112561121, 0.0337749015848141547933022468659129013491, 0.0337749015848141547933022468659129013491, 0.0146279952982722006849910980471854451902, 0.0146279952982722006849910980471854451902], + [0.1336545721861061753514571105458443385831, 0.1324620394046966173716424647033169258050, 0.1324620394046966173716424647033169258050, 0.1289057221880821499785953393997936532597, 0.1289057221880821499785953393997936532597, 0.1230490843067295304675784006720096548158, 0.1230490843067295304675784006720096548158, 0.1149966402224113649416435129339613014914, 0.1149966402224113649416435129339613014914, 0.1048920914645414100740861850147438548584, 0.1048920914645414100740861850147438548584, 0.0929157660600351474770186173697646486034, 0.0929157660600351474770186173697646486034, 0.0792814117767189549228925247420432269137, 0.0792814117767189549228925247420432269137, 0.0642324214085258521271696151589109980391, 0.0642324214085258521271696151589109980391, 0.0480376717310846685716410716320339965612, 0.0480376717310846685716410716320339965612, 0.0309880058569794443106942196418845053837, 0.0309880058569794443106942196418845053837, 0.0134118594871417720813094934586150649766, 0.0134118594871417720813094934586150649766], + [0.1279381953467521569740561652246953718517, 0.1279381953467521569740561652246953718517, 0.1258374563468282961213753825111836887264, 0.1258374563468282961213753825111836887264, 0.1216704729278033912044631534762624256070, 0.1216704729278033912044631534762624256070, 0.1155056680537256013533444839067835598622, 0.1155056680537256013533444839067835598622, 0.1074442701159656347825773424466062227946, 0.1074442701159656347825773424466062227946, 0.0976186521041138882698806644642471544279, 0.0976186521041138882698806644642471544279, 0.0861901615319532759171852029837426671850, 0.0861901615319532759171852029837426671850, 0.0733464814110803057340336152531165181193, 0.0733464814110803057340336152531165181193, 0.0592985849154367807463677585001085845412, 0.0592985849154367807463677585001085845412, 0.0442774388174198061686027482113382288593, 0.0442774388174198061686027482113382288593, 0.0285313886289336631813078159518782864491, 0.0285313886289336631813078159518782864491, 0.0123412297999871995468056670700372915759, 0.0123412297999871995468056670700372915759] ]; } @@ -680,13 +681,14 @@ class KnotMultiplicity { //* The knot position //* The multiplicity of the knot - public function new(knot : Float, mult : Int ){ + public function new( knot : Float, mult : Int ) { this.knot = knot; this.mult = mult; } // Increments the multiplicity of the knot - public function inc(){ + + public function inc( ) { mult++; } } diff --git a/src/verb/eval/Check.hx b/src/verb/eval/Check.hx index 620285c5..d75585d9 100644 --- a/src/verb/eval/Check.hx +++ b/src/verb/eval/Check.hx @@ -33,21 +33,21 @@ class Check { // //* Whether the array is a valid knot vector or knot - public static function isValidKnotVector(vec : Array, degree : Int) : Bool { + public static function isValidKnotVector( vec : Array, degree : Int ) : Bool { - if (vec.length == 0) return false; - if (vec.length < (degree + 1) * 2 ) return false; + if ( vec.length == 0 ) return false; + if ( vec.length < (degree + 1) * 2 ) return false; - var rep = vec.first(); + var rep = vec.first( ); - for (i in 0...degree+1){ - if (Math.abs(vec[i]-rep) > Constants.EPSILON) return false; + for ( i in 0...degree + 1 ) { + if ( Math.abs( vec[i] - rep ) > Constants.EPSILON ) return false; } - rep = vec.last(); + rep = vec.last( ); - for (i in vec.length-degree-1...vec.length){ - if (Math.abs(vec[i]-rep) > Constants.EPSILON) return false; + for ( i in vec.length - degree - 1...vec.length ) { + if ( Math.abs( vec[i] - rep ) > Constants.EPSILON ) return false; } return isNonDecreasing( vec ); @@ -64,10 +64,10 @@ class Check { // //* Whether the array is non-decreasing - public static function isNonDecreasing(vec : Array){ - var rep = vec.first(); - for ( i in 0...vec.length ){ - if (vec[i] < rep - Constants.EPSILON ) return false; + public static function isNonDecreasing( vec : Array ) { + var rep = vec.first( ); + for ( i in 0...vec.length ) { + if ( vec[i] < rep - Constants.EPSILON ) return false; rep = vec[i]; } return true; @@ -86,16 +86,16 @@ class Check { public static function isValidNurbsCurveData( data : NurbsCurveData ) : NurbsCurveData { if ( data.controlPoints == null ) throw "Control points array cannot be null!"; #if (!cpp && !cs && !java) - if ( data.degree == null ) throw "Degree cannot be null!"; + if ( data.degree == null ) throw "Degree cannot be null!"; #end if ( data.degree < 1 ) throw "Degree must be greater than 1!"; if ( data.knots == null ) throw "Knots cannot be null!"; - if ( data.knots.length != data.controlPoints.length + data.degree + 1 ){ + if ( data.knots.length != data.controlPoints.length + data.degree + 1 ) { throw "controlPoints.length + degree + 1 must equal knots.length!"; } - if (!Check.isValidKnotVector( data.knots, data.degree )){ + if ( !Check.isValidKnotVector( data.knots, data.degree ) ) { throw "Invalid knot vector format! Should begin with degree + 1 repeats and end with degree + 1 repeats!"; } @@ -115,23 +115,23 @@ class Check { public static function isValidNurbsSurfaceData( data : NurbsSurfaceData ) : NurbsSurfaceData { if ( data.controlPoints == null ) throw "Control points array cannot be null!"; #if (!cpp && !cs && !java) - if ( data.degreeU == null ) throw "DegreeU cannot be null!"; - if ( data.degreeV == null ) throw "DegreeV cannot be null!"; + if ( data.degreeU == null ) throw "DegreeU cannot be null!"; + if ( data.degreeV == null ) throw "DegreeV cannot be null!"; #end if ( data.degreeU < 1 ) throw "DegreeU must be greater than 1!"; if ( data.degreeV < 1 ) throw "DegreeV must be greater than 1!"; if ( data.knotsU == null ) throw "KnotsU cannot be null!"; if ( data.knotsV == null ) throw "KnotsV cannot be null!"; - if ( data.knotsU.length != data.controlPoints.length + data.degreeU + 1 ){ + if ( data.knotsU.length != data.controlPoints.length + data.degreeU + 1 ) { throw "controlPointsU.length + degreeU + 1 must equal knotsU.length!"; } - if ( data.knotsV.length != data.controlPoints[0].length + data.degreeV + 1 ){ + if ( data.knotsV.length != data.controlPoints[0].length + data.degreeV + 1 ) { throw "controlPointsV.length + degreeV + 1 must equal knotsV.length!"; } - if (!Check.isValidKnotVector( data.knotsU, data.degreeU ) || !Check.isValidKnotVector( data.knotsV, data.degreeV )){ + if ( !Check.isValidKnotVector( data.knotsU, data.degreeU ) || !Check.isValidKnotVector( data.knotsV, data.degreeV ) ) { throw "Invalid knot vector format! Should begin with degree + 1 repeats and end with degree + 1 repeats!"; } diff --git a/src/verb/eval/Divide.hx b/src/verb/eval/Divide.hx index 8031465d..2443fa88 100644 --- a/src/verb/eval/Divide.hx +++ b/src/verb/eval/Divide.hx @@ -24,13 +24,13 @@ class Divide { // //* A length two array of new surfaces - public static function surfaceSplit( surface : NurbsSurfaceData, u : Float, useV : Bool = false) : Array { + public static function surfaceSplit( surface : NurbsSurfaceData, u : Float, useV : Bool = false ) : Array { var knots , degree , controlPoints; - if (!useV) { + if ( !useV ) { controlPoints = Mat.transpose( surface.controlPoints ); knots = surface.knotsU; degree = surface.degreeU; @@ -40,7 +40,7 @@ class Divide { degree = surface.degreeV; } - var knots_to_insert = [ for (i in 0...degree+1) u ]; + var knots_to_insert = [ for ( i in 0...degree + 1 ) u ]; var newpts0 = new Array>() , newpts1 = new Array>(); @@ -48,27 +48,27 @@ class Divide { var s = Eval.knotSpan( degree, u, knots ); var res : NurbsCurveData = null; - for (cps in controlPoints){ + for ( cps in controlPoints ) { res = Modify.curveKnotRefine( new NurbsCurveData(degree, knots, cps), knots_to_insert ); newpts0.push( res.controlPoints.slice( 0, s + 1 ) ); newpts1.push( res.controlPoints.slice( s + 1 ) ); } - var knots0 = res.knots.slice(0, s + degree + 2); + var knots0 = res.knots.slice( 0, s + degree + 2 ); var knots1 = res.knots.slice( s + 1 ); - if (!useV){ + if ( !useV ) { newpts0 = Mat.transpose( newpts0 ); newpts1 = Mat.transpose( newpts1 ); - return [ new NurbsSurfaceData(degree, surface.degreeV, knots0, surface.knotsV.copy(), newpts0 ), - new NurbsSurfaceData(degree, surface.degreeV, knots1, surface.knotsV.copy(), newpts1 ) ]; + return [ new NurbsSurfaceData(degree, surface.degreeV, knots0, surface.knotsV.copy( ), newpts0 ), + new NurbsSurfaceData(degree, surface.degreeV, knots1, surface.knotsV.copy( ), newpts1 ) ]; } //v dir - return [ new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots0, newpts0 ), - new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots1, newpts1 ) ]; + return [ new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy( ), knots0, newpts0 ), + new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy( ), knots1, newpts1 ) ]; } //Split a NURBS curve into two parts at a given parameter @@ -88,12 +88,12 @@ class Divide { , controlPoints = curve.controlPoints , knots = curve.knots; - var knots_to_insert = [for (i in 0...degree+1) u]; + var knots_to_insert = [for ( i in 0...degree + 1 ) u]; var res = Modify.curveKnotRefine( curve, knots_to_insert ); var s = Eval.knotSpan( degree, u, knots ); - var knots0 = res.knots.slice(0, s + degree + 2); + var knots0 = res.knots.slice( 0, s + degree + 2 ); var knots1 = res.knots.slice( s + 1 ); var cpts0 = res.controlPoints.slice( 0, s + 1 ); @@ -119,12 +119,12 @@ class Divide { // //* An array of `CurveLengthSample` objects - public static function rationalCurveByEqualArcLength(curve : NurbsCurveData, num : Int) : Array { + public static function rationalCurveByEqualArcLength( curve : NurbsCurveData, num : Int ) : Array { var tlen = Analyze.rationalCurveArcLength( curve ); var inc = tlen / num; - return Divide.rationalCurveByArcLength(curve, inc); + return Divide.rationalCurveByArcLength( curve, inc ); } @@ -139,14 +139,14 @@ class Divide { // //* A sequence of `CurveLengthSample` objects - public static function rationalCurveByArcLength(curve : NurbsCurveData, l : Float) : Array { + public static function rationalCurveByArcLength( curve : NurbsCurveData, l : Float ) : Array { var crvs = Modify.decomposeCurveIntoBeziers( curve ) - , crvlens = crvs.map(function(x){ return Analyze.rationalBezierCurveArcLength(x); }) - , totlen = Vec.sum(crvlens) + , crvlens = crvs.map( function( x ) { return Analyze.rationalBezierCurveArcLength( x ); } ) + , totlen = Vec.sum( crvlens ) , pts = [ new CurveLengthSample( curve.knots[0], 0.0 ) ]; - if (l > totlen) return pts; + if ( l > totlen ) return pts; var inc = l , i = 0 @@ -155,11 +155,11 @@ class Divide { , runsum1 = 0.0 , u; - while ( i < crvs.length ){ + while ( i < crvs.length ) { runsum += crvlens[i]; - while ( lc < runsum + Constants.EPSILON ){ + while ( lc < runsum + Constants.EPSILON ) { u = Analyze.rationalBezierCurveParamAtArcLength( crvs[i], lc - runsum1, Constants.TOLERANCE, crvlens[i] ); @@ -186,7 +186,7 @@ class CurveLengthSample { public var u : Float; public var len : Float; - public function new(u, len) { + public function new( u, len ) { this.u = u; this.len = len; } diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 4fe74a14..14db92ef 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -2,8 +2,14 @@ package verb.eval; import verb.core.Data; import verb.core.Vec; +import verb.core.Mat; import verb.core.Binomial; import verb.core.Constants; +import verb.core.BoundingBox; + +import verb.eval.Modify; + +using verb.core.ArrayExtensions; // `Eval` provides all of the core algorithms for evaluating points and derivatives on NURBS curves and surfaces. Most of the // time, it makes more sense to use the tools in verb.geom for this, but in some cases this will make more sense. @@ -44,7 +50,7 @@ class Eval { // //* a Vector represented by an array of length (dim) - public static function rationalSurfaceNormal( surface : NurbsSurfaceData, u : Float, v : Float) : Array { + public static function rationalSurfaceNormal( surface : NurbsSurfaceData, u : Float, v : Float ) : Array { var derivs = rationalSurfaceDerivatives( surface, u, v, 1 ); return Vec.cross( derivs[1][0], derivs[0][1] ); } @@ -62,41 +68,41 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalSurfaceDerivatives( surface : NurbsSurfaceData, - u : Float, - v : Float, - numDerivs : Int = 1) : Array>> { + public static function rationalSurfaceDerivatives( surface : NurbsSurfaceData, + u : Float, + v : Float, + numDerivs : Int = 1 ) : Array>> { - var ders = surfaceDerivatives( surface, u, v, numDerivs) - , Aders = rational2d(ders) - , wders = weight2d(ders) + var ders = surfaceDerivatives( surface, u, v, numDerivs ) + , Aders = rational2d( ders ) + , wders = weight2d( ders ) , SKL = new Array>>() , dim = Aders[0][0].length; - for (k in 0...numDerivs+1){ + for ( k in 0...numDerivs + 1 ) { SKL.push( new Array>() ); - for (l in 0...numDerivs-k+1){ + for ( l in 0...numDerivs - k + 1 ) { var v = Aders[k][l]; - for (j in 1...l+1){ - v = Vec.sub( v, Vec.mul( Binomial.get(l, j) * wders[0][j], SKL[k][l-j] ) ); + for ( j in 1...l + 1 ) { + Vec.subMulMutate( v, Binomial.get( l, j ) * wders[0][j], SKL[k][l - j] ); } - for (i in 1...k+1){ - v = Vec.sub( v, Vec.mul( Binomial.get(k, i) * wders[i][0], SKL[k-i][l] ) ); + for ( i in 1...k + 1 ) { + Vec.subMulMutate( v, Binomial.get( k, i ) * wders[i][0], SKL[k - i][l] ); - var v2 = Vec.zeros1d(dim); + var v2 = Vec.zeros1d( dim ); - for (j in 1...l+1){ - v2 = Vec.add( v2, Vec.mul( Binomial.get(l, j) * wders[i][j], SKL[k-i][l-j] ) ); + for ( j in 1...l + 1 ) { + Vec.addMulMutate( v2, Binomial.get( l, j ) * wders[i][j], SKL[k - i][l - j] ); } - v = Vec.sub( v, Vec.mul( Binomial.get(k, i), v2) ); - + Vec.subMulMutate( v, Binomial.get( k, i ), v2 ); } - SKL[k].push( Vec.mul(1 / wders[0][0], v )); //demogenize + Vec.mulMutate( 1 / wders[0][0], v ); + SKL[k].push( v ); //demogenize } } @@ -136,22 +142,24 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalCurveDerivatives( curve : NurbsCurveData, u : Float, numDerivs : Int = 1 ) : Array { + public static function rationalCurveDerivatives( curve : NurbsCurveData, u : Float, numDerivs : Int = 1 ) : Array { var ders = curveDerivatives( curve, u, numDerivs ) - , Aders = rational1d(ders) - , wders = weight1d(ders) + , Aders = rational1d( ders ) + , wders = weight1d( ders ) , k = 0 - , i = 0 + , i = 0 , CK = []; - for (k in 0...numDerivs+1) { + for ( k in 0...numDerivs + 1 ) { var v = Aders[k]; - for (i in 1...k+1) { - v = Vec.sub( v, Vec.mul( Binomial.get(k, i) * wders[i], CK[k-i] ) ); + for ( i in 1...k + 1 ) { + Vec.subMulMutate( v, Binomial.get( k, i ) * wders[i], CK[k - i] ); } - CK.push( Vec.mul(1/wders[0], v )); //demogenize + + Vec.mulMutate( 1 / wders[0], v ); + CK.push( v ); //demogenize } return CK; @@ -172,8 +180,8 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalCurvePoint( curve : NurbsCurveData, u : Float) : Point { - return dehomogenize( curvePoint( curve, u) ); + public static function rationalCurvePoint( curve : NurbsCurveData, u : Float ) : Point { + return dehomogenize( curvePoint( curve, u ) ); } //Compute the derivatives on a non-uniform, non-rational B spline surface @@ -198,7 +206,7 @@ class Eval { } - //Compute the derivatives on a non-uniform, non-rational B spline surface + // Compute the derivatives on a non-uniform, non-rational B spline surface // (corresponds to algorithm 3.6 from The NURBS book, Piegl & Tiller 2nd edition) // //**params** @@ -214,11 +222,11 @@ class Eval { //* a 2d jagged array representing the derivatives - u derivatives increase by row, v by column public static function surfaceDerivativesGivenNM( n : Int, - m : Int, - surface : NurbsSurfaceData, - u : Float, - v: Float, - numDerivs : Int ) : Array>{ + m : Int, + surface : NurbsSurfaceData, + u : Float, + v : Float, + numDerivs : Int ) : Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -226,8 +234,8 @@ class Eval { , knotsU = surface.knotsU , knotsV = surface.knotsV; - if ( !areValidRelations(degreeU, controlPoints.length, knotsU.length ) || - !areValidRelations(degreeV, controlPoints[0].length, knotsV.length ) ) { + if ( !areValidRelations( degreeU, controlPoints.length, knotsU.length ) || + !areValidRelations( degreeV, controlPoints[0].length, knotsV.length ) ) { throw 'Invalid relations between control points, knot vector, and n'; } @@ -235,32 +243,31 @@ class Eval { var dim = controlPoints[0][0].length , du = numDerivs < degreeU ? numDerivs : degreeU , dv = numDerivs < degreeV ? numDerivs : degreeV - , SKL = Vec.zeros3d( numDerivs+1, numDerivs+1, dim ) + , SKL = Vec.zeros3d( du + 1, dv + 1, dim ) , knotSpan_index_u = knotSpanGivenN( n, degreeU, u, knotsU ) , knotSpan_index_v = knotSpanGivenN( m, degreeV, v, knotsV ) , uders = derivativeBasisFunctionsGivenNI( knotSpan_index_u, u, degreeU, n, knotsU ) , vders = derivativeBasisFunctionsGivenNI( knotSpan_index_v, v, degreeV, m, knotsV ) - , temp = Vec.zeros2d( degreeV+1, dim ) + , temp = Vec.zeros2d( degreeV + 1, dim ) , dd = 0; - for (k in 0...du+1){ - for (s in 0...degreeV+1) { + for ( k in 0...du + 1 ) { + for ( s in 0...degreeV + 1 ) { temp[s] = Vec.zeros1d( dim ); - for (r in 0...degreeU+1){ - temp[s] = Vec.add( temp[s], - Vec.mul( uders[k][r], controlPoints[knotSpan_index_u-degreeU+r][knotSpan_index_v-degreeV+s]) ); + for ( r in 0...degreeU + 1 ) { + Vec.addMulMutate( temp[s], uders[k][r], controlPoints[knotSpan_index_u - degreeU + r][knotSpan_index_v - degreeV + s] ); } } var nk = numDerivs - k; dd = nk < dv ? nk : dv; - for (l in 0...dd+1){ + for ( l in 0...dd + 1 ) { SKL[k][l] = Vec.zeros1d( dim ); - for (s in 0...degreeV+1){ - SKL[k][l] = Vec.add( SKL[k][l], Vec.mul( vders[l][s], temp[s] ) ); + for ( s in 0...degreeV + 1 ) { + Vec.addMulMutate( SKL[k][l], vders[l][s], temp[s] ); } } } @@ -280,7 +287,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function surfacePoint( surface : NurbsSurfaceData, u : Float, v : Float) : Point { + public static function surfacePoint( surface : NurbsSurfaceData, u : Float, v : Float ) : Point { var n = surface.knotsU.length - surface.degreeU - 2 , m = surface.knotsV.length - surface.degreeV - 2; @@ -289,7 +296,7 @@ class Eval { } - //Compute a point on a non-uniform, non-rational B spline surface + // Compute a point on a non-uniform, non-rational B spline surface // (corresponds to algorithm 3.5 from The NURBS book, Piegl & Tiller 2nd edition) // //**params** @@ -312,8 +319,8 @@ class Eval { , knotsU = surface.knotsU , knotsV = surface.knotsV; - if ( !areValidRelations(degreeU, controlPoints.length, knotsU.length ) || - !areValidRelations(degreeV, controlPoints[0].length, knotsV.length ) ) { + if ( !areValidRelations( degreeU, controlPoints.length, knotsU.length ) || + !areValidRelations( degreeV, controlPoints[0].length, knotsV.length ) ) { throw 'Invalid relations between control points, knot vector, and n'; } @@ -328,23 +335,256 @@ class Eval { , position = Vec.zeros1d( dim ) , temp = Vec.zeros1d( dim ); - for (l in 0...degreeV + 1){ + for ( l in 0...degreeV + 1 ) { temp = Vec.zeros1d( dim ); vind = knotSpan_index_v - degreeV + l; //sample u isoline - for (k in 0...degreeU + 1) { - temp = Vec.add( temp, Vec.mul( u_basis_vals[k], controlPoints[uind+k][vind]) ); + for ( k in 0...degreeU + 1 ) { + Vec.addMulMutate( temp, u_basis_vals[k], controlPoints[uind + k][vind] ); } //add point from u isoline - position = Vec.add( position, Vec.mul(v_basis_vals[l], temp) ); + Vec.addMulMutate( position, v_basis_vals[l], temp ); + } + + return position; + } + + // Compute a regularly spaced grid of derivatives on a non-uniform, rational, B spline surface. Generally, this algorithm + // is faster than directly evaluating these as we can pre-compute all of the basis function arrays + // + //**params** + // + //* NurbsSurfaceData object representing the surface + //* number of divisions in the U direction + //* number of divisions in the V direction + //* number of derivatives + // + //**returns** + // + //* a 2d array of dimension (divsU+1, divsV+1) of derivative values where each entry is similar to that returned by `rationalSurfaceDerivatives` + + public static function rationalSurfaceRegularSampleDerivatives( surface : NurbsSurfaceData, divsU : Int, divsV : Int, numDerivs : Int ) { + + var allders = surfaceRegularSampleDerivatives( surface, divsU, divsV, numDerivs ); + + var allratders = []; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var numDerivs1 = numDerivs + 1; + + for ( i in 0...divsU1 ) { + + var rowders = []; + allratders.push( rowders ); + + for ( j in 0...divsV1 ) { + + var ders = allders[i][j] + , Aders = rational2d( ders ) + , wders = weight2d( ders ) + , SKL = new Array>>() + , dim = Aders[0][0].length; + + for ( k in 0...numDerivs1 ) { + SKL.push( new Array>() ); + + for ( l in 0...numDerivs1 - k ) { + var v = Aders[k][l]; + + for ( j in 1...l + 1 ) { + Vec.subMulMutate( v, Binomial.get( l, j ) * wders[0][j], SKL[k][l - j] ); + } + + for ( i in 1...k + 1 ) { + Vec.subMulMutate( v, Binomial.get( k, i ) * wders[i][0], SKL[k - i][l] ); + + var v2 = Vec.zeros1d( dim ); + + for ( j in 1...l + 1 ) { + Vec.addMulMutate( v2, Binomial.get( l, j ) * wders[i][j], SKL[k - i][l - j] ); + } + + Vec.subMulMutate( v, Binomial.get( k, i ), v2 ); + + } + + Vec.mulMutate( 1 / wders[0][0], v ); + SKL[k].push( v ); //demogenize + } + } + + rowders.push( SKL ); + } + } + + return allratders; + } + + // Compute a regularly spaced grid of derivatives on a non-uniform, non-rational, B spline surface. Generally, this algorithm + // is faster than directly evaluating these as we can pre-compute all of the basis function arrays + // + //**params** + // + //* NurbsSurfaceData object representing the surface + //* number of divisions in the U direction + //* number of divisions in the V direction + // + //**returns** + // + //* a 2d array of dimension (divsU+1, divsV+1) of derivative values where each entry is similar to that returned by surfaceDerivatives + + public static function surfaceRegularSampleDerivatives( surface : NurbsSurfaceData, divsU : Int, divsV : Int, numDerivs : Int ) { + + var degreeU = surface.degreeU + , degreeV = surface.degreeV + , controlPoints = surface.controlPoints + , knotsU = surface.knotsU + , knotsV = surface.knotsV; + + var dim = controlPoints[0][0].length + , spanU = (knotsU.last( ) - knotsU[0]) / divsU + , spanV = (knotsV.last( ) - knotsV[0]) / divsV + , knotSpansBasesU = regularlySpacedDerivativeBasisFunctions( degreeU, knotsU, divsU ) + , knotSpansU = knotSpansBasesU.item0 + , basesU = knotSpansBasesU.item1 + , knotSpansBasesV = regularlySpacedDerivativeBasisFunctions( degreeV, knotsV, divsV ) + , knotSpansV = knotSpansBasesV.item0 + , basesV = knotSpansBasesV.item1 + , pts = [] + , divsU1 = divsU + 1 + , divsV1 = divsV + 1; + + for ( i in 0...divsU1 ) { + var ptsi = []; + pts.push( ptsi ); + + for ( j in 0...divsV1 ) { + ptsi.push( surfaceDerivativesGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim, numDerivs ) ); + } + } + + return pts; + } + + public static function regularlySpacedBasisFunctions( degree : Int, knots : KnotArray, divs : Int ) : Pair, Array>> { + + var n : Int = knots.length - degree - 2; + var span : Float = (knots.last( ) - knots[0]) / divs; + + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = knotSpanGivenN( n, degree, u, knots ); + var div1 = divs + 1; + + // compute all of the basis functions in given dir + for ( i in 0...div1 ) { + while ( u >= knots[knotIndex + 1] ) knotIndex++; + knotspans.push( knotIndex ); + bases.push( basisFunctionsGivenKnotSpanIndex( knotIndex, u, degree, knots ) ); + u += span; + } + + return new Pair, Array>>( knotspans, bases ); + } + + private static function regularlySpacedDerivativeBasisFunctions( degree : Int, knots : KnotArray, divs : Int ) { + + var n : Int = knots.length - degree - 2; + var span : Float = (knots.last( ) - knots[0]) / divs; + + var bases = []; + var knotspans = []; + var u = knots[0]; + var knotIndex = knotSpanGivenN( n, degree, u, knots ); + var div1 = divs + 1; + + // compute all of the basis functions in given dir + for ( i in 0...div1 ) { + while ( u >= knots[knotIndex + 1] ) knotIndex++; + knotspans.push( knotIndex ); + bases.push( derivativeBasisFunctionsGivenNI( knotIndex, u, degree, n, knots ) ); + u += span; + } + + return new Pair, Array>>>( knotspans, bases ); + } + + public static function surfacePointGivenBasesKnotSpans( degreeU : Int, + degreeV : Int, + controlPoints : Array>, + knotSpanU : Int, + knotSpanV : Int, + basesU : Array, + basesV : Array, + dim : Int ) : Point { + + var position = Vec.zeros1d( dim ) + , temp : Array; + + // could be precomputed + var uind = knotSpanU - degreeU; + var vind = knotSpanV - degreeV; + + for ( l in 0...degreeV + 1 ) { + + temp = Vec.zeros1d( dim ); + + for ( k in 0...degreeU + 1 ) { + Vec.addMulMutate( temp, basesU[k], controlPoints[uind + k][vind] ); + } + + vind++; + + Vec.addMulMutate( position, basesV[l], temp ); } return position; } + private static function surfaceDerivativesGivenBasesKnotSpans( degreeU : Int, + degreeV : Int, + controlPoints : Array>, + knotSpanU : Int, + knotSpanV : Int, + basesU : Array>, + basesV : Array>, + dim : Int, + numDerivs : Int ) { + + var dim = controlPoints[0][0].length + , du = numDerivs < degreeU ? numDerivs : degreeU + , dv = numDerivs < degreeV ? numDerivs : degreeV + , SKL = Vec.zeros3d( du + 1, dv + 1, dim ) + , temp = Vec.zeros2d( degreeV + 1, dim ) + , dd = 0; + + for ( k in 0...du + 1 ) { + for ( s in 0...degreeV + 1 ) { + temp[s] = Vec.zeros1d( dim ); + + for ( r in 0...degreeU + 1 ) { + Vec.addMulMutate( temp[s], basesU[k][r], controlPoints[knotSpanU - degreeU + r][knotSpanV - degreeV + s] ); + } + } + + var nk = numDerivs - k; + dd = nk < dv ? nk : dv; + + for ( l in 0...dd + 1 ) { + SKL[k][l] = Vec.zeros1d( dim ); + + for ( s in 0...degreeV + 1 ) { + Vec.addMulMutate( SKL[k][l], basesV[l][s], temp[s] ); + } + } + } + + return SKL; + } //Determine the derivatives of a non-uniform, non-rational B-spline curve at a given parameter // @@ -361,8 +601,7 @@ class Eval { public static function curveDerivatives( crv : NurbsCurveData, u : Float, numDerivs : Int ) : Array { var n = crv.knots.length - crv.degree - 2; - return curveDerivativesGivenN( n, crv, u, numDerivs - ); + return curveDerivativesGivenN( n, crv, u, numDerivs ); } @@ -397,9 +636,9 @@ class Eval { , k = 0 , j = 0; - for (k in 0...du+1) { - for (j in 0...degree+1){ - CK[k] = Vec.add( CK[k], Vec.mul( nders[k][j], controlPoints[ knotSpan_index - degree + j ] ) ); + for ( k in 0...du + 1 ) { + for ( j in 0...degree + 1 ) { + Vec.addMulMutate( CK[k], nders[k][j], controlPoints[ knotSpan_index - degree + j ] ); } } return CK; @@ -416,9 +655,9 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curvePoint( curve : NurbsCurveData, u : Float) { + public static function curvePoint( curve : NurbsCurveData, u : Float ) { var n = curve.knots.length - curve.degree - 2; - return curvePointGivenN( n, curve, u); + return curvePointGivenN( n, curve, u ); } //Confirm the relations between degree (p), number of control points(n+1), and the number of knots (m+1) @@ -451,11 +690,11 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curvePointGivenN( n : Int, curve : NurbsCurveData, u : Float) : Point { + public static function curvePointGivenN( n : Int, curve : NurbsCurveData, u : Float ) : Point { var degree = curve.degree - , controlPoints = curve.controlPoints - , knots = curve.knots; + , controlPoints = curve.controlPoints + , knots = curve.knots; if ( !areValidRelations( degree, controlPoints.length, knots.length ) ) { throw 'Invalid relations between control points, knot Array, and n'; @@ -466,10 +705,8 @@ class Eval { var basis_values = basisFunctionsGivenKnotSpanIndex( knotSpan_index, u, degree, knots ); var position = Vec.zeros1d( controlPoints[0].length ); - for (j in 0...degree+1){ - position = Vec.add( position, - Vec.mul( basis_values[j], - controlPoints[ knotSpan_index - degree + j ] ) ); + for ( j in 0...degree + 1 ) { + Vec.addMulMutate( position, basis_values[j], controlPoints[ knotSpan_index - degree + j ] ); } return position; @@ -515,11 +752,11 @@ class Eval { l : Int, u : Float, v : Float, - w : Float ) : Point { + w : Float ) : Point { - if ( !areValidRelations(volume.degreeU, volume.controlPoints.length, volume.knotsU.length ) || - !areValidRelations(volume.degreeV, volume.controlPoints[0].length, volume.knotsV.length ) || - !areValidRelations(volume.degreeW, volume.controlPoints[0][0].length, volume.knotsW.length ) ) { + if ( !areValidRelations( volume.degreeU, volume.controlPoints.length, volume.knotsU.length ) || + !areValidRelations( volume.degreeV, volume.controlPoints[0].length, volume.knotsV.length ) || + !areValidRelations( volume.degreeW, volume.controlPoints[0][0].length, volume.knotsW.length ) ) { throw 'Invalid relations between control points and knot vector'; } @@ -543,33 +780,32 @@ class Eval { , temp = Vec.zeros1d( dim ) , temp2 = Vec.zeros1d( dim ); - for ( i in 0...degreeW + 1 ){ + for ( i in 0...degreeW + 1 ) { temp2 = Vec.zeros1d( dim ); var wind = knotSpan_index_w - degreeW + i; - for ( j in 0...degreeV + 1 ){ + for ( j in 0...degreeV + 1 ) { temp = Vec.zeros1d( dim ); - var vind = knotSpan_index_v - degreeV + j; + var vind = knotSpan_index_v - degreeV + j; - for ( k in 0...degreeU + 1 ){ - temp = Vec.add( temp, Vec.mul( u_basis_vals[k], controlPoints[uind+k][vind][wind] )); + for ( k in 0...degreeU + 1 ) { + Vec.addMulMutate( temp, u_basis_vals[k], controlPoints[uind + k][vind][wind] ); } - //add weighted contribution of u isoline - temp2 = Vec.add( temp2, Vec.mul( v_basis_vals[j], temp ) ); + //add weighted contribution of u isoline + Vec.addMulMutate( temp2, v_basis_vals[j], temp ); } //add weighted contribution from uv isosurfaces - position = Vec.add( position, Vec.mul( w_basis_vals[i], temp2 ) ); + Vec.addMulMutate( position, w_basis_vals[i], temp2 ); } return position; } - -//Compute the non-vanishing basis functions and their derivatives + //Compute the non-vanishing basis functions and their derivatives // //**params** // @@ -581,8 +817,7 @@ class Eval { // //* 2d array of basis and derivative values of size (n+1, p+1) The nth row is the nth derivative and the first row is made up of the basis function values. - public static function derivativeBasisFunctions( u : Float, degree : Int, knots : KnotArray ): Array> - { + public static function derivativeBasisFunctions( u : Float, degree : Int, knots : KnotArray ) : Array> { var knotSpan_index = knotSpan( degree, u, knots ) , m = knots.length - 1 , n = m - degree - 1; @@ -590,7 +825,7 @@ class Eval { return derivativeBasisFunctionsGivenNI( knotSpan_index, u, degree, n, knots ); } - //Compute the non-vanishing basis functions and their derivatives + // Compute the non-vanishing basis functions and their derivatives // (corresponds to algorithm 2.3 from The NURBS book, Piegl & Tiller 2nd edition) // //**params** @@ -605,10 +840,9 @@ class Eval { // //* 2d array of basis and derivative values of size (n+1, p+1) The nth row is the nth derivative and the first row is made up of the basis function values. - public static function derivativeBasisFunctionsGivenNI( knotSpan_index : Int, u : Float, p : Int, - n : Int, knots : KnotArray ) : Array> - { - var ndu = Vec.zeros2d( p+1, p+1 ) + public static function derivativeBasisFunctionsGivenNI( knotIndex : Int, u : Float, p : Int, + n : Int, knots : KnotArray ) : Array> { + var ndu = Vec.zeros2d( p + 1, p + 1 ) , left = Vec.zeros1d( p + 1 ) , right = Vec.zeros1d( p + 1 ) , saved = 0.0 @@ -616,71 +850,70 @@ class Eval { ndu[0][0] = 1.0; - for(j in 1...p+1){ - left[j] = u - knots[knotSpan_index+1-j]; - right[j] = knots[knotSpan_index+j] - u; + for ( j in 1...p + 1 ) { + left[j] = u - knots[knotIndex + 1 - j]; + right[j] = knots[knotIndex + j] - u; saved = 0.0; - for (r in 0...j){ - ndu[j][r] = right[r+1] + left[j-r]; - temp = ndu[r][j-1] / ndu[j][r]; + for ( r in 0...j ) { + ndu[j][r] = right[r + 1] + left[j - r]; + temp = ndu[r][j - 1] / ndu[j][r]; - ndu[r][j] = saved + right[r+1]*temp; - saved = left[j-r]*temp; + ndu[r][j] = saved + right[r + 1] * temp; + saved = left[j - r] * temp; } ndu[j][j] = saved; } - var ders = Vec.zeros2d(n+1, p+1) - , a = Vec.zeros2d(2, p+1) - , s1 : Int = 0 - , s2 : Int = 1 - , d : Float = 0.0 - , rk : Int = 0 - , pk : Int = 0 - , j1 : Int = 0 - , j2 : Int = 0; - - for (j in 0...p+1){ + var ders = Vec.zeros2d( n + 1, p + 1 ) + , a = Vec.zeros2d( 2, p + 1 ) + , s1 : Int = 0 + , s2 : Int = 1 + , d : Float = 0.0 + , rk : Int = 0 + , pk : Int = 0 + , j1 : Int = 0 + , j2 : Int = 0; + + for ( j in 0...p + 1 ) { ders[0][j] = ndu[j][p]; } - for (r in 0...p+1){ + for ( r in 0...p + 1 ) { s1 = 0; s2 = 1; a[0][0] = 1.0; - for (k in 1...n+1) - { + for ( k in 1...n + 1 ) { d = 0.0; rk = r - k; pk = p - k; - if (r >= k) { - a[s2][0] = a[s1][0] / ndu[pk+1][rk]; + if ( r >= k ) { + a[s2][0] = a[s1][0] / ndu[pk + 1][rk]; d = a[s2][0] * ndu[rk][pk]; } - if (rk >= -1) { + if ( rk >= -1 ) { j1 = 1; } else { j1 = -rk; } - if (r-1 <= pk) { - j2 = k-1; + if ( r - 1 <= pk ) { + j2 = k - 1; } else { j2 = p - r; } - for (j in j1...j2+1) { + for ( j in j1...j2 + 1 ) { a[s2][j] = ( a[s1][j] - a[s1][ j - 1 ] ) / ndu[ pk + 1 ][ rk + j ]; - d += a[s2][j]*ndu[rk+j][pk]; + d += a[s2][j] * ndu[rk + j][pk]; } - if (r <= pk){ - a[s2][k] = -a[s1][k-1]/ndu[pk+1][r]; + if ( r <= pk ) { + a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r]; d += a[s2][k] * ndu[r][pk]; } @@ -693,11 +926,11 @@ class Eval { } var acc = p; - for (k in 1...n+1) { - for (j in 0...p+1){ + for ( k in 1...n + 1 ) { + for ( j in 0...p + 1 ) { ders[k][j] *= acc; } - acc *= (p-k); + acc *= (p - k); } return ders; @@ -717,9 +950,8 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctions( u : Float, degree : Int, knots : KnotArray) - { - var knotSpan_index = knotSpan(degree, u, knots); + public static function basisFunctions( u : Float, degree : Int, knots : KnotArray ) : Array { + var knotSpan_index = knotSpan( degree, u, knots ); return basisFunctionsGivenKnotSpanIndex( knotSpan_index, u, degree, knots ); } @@ -739,10 +971,9 @@ class Eval { // public static function basisFunctionsGivenKnotSpanIndex( knotSpan_index : Int, - u : Float, - degree : Int, - knots : KnotArray ) - { + u : Float, + degree : Int, + knots : KnotArray ) : Array { var basisFunctions = Vec.zeros1d( degree + 1 ); var left = Vec.zeros1d( degree + 1 ); var right = Vec.zeros1d( degree + 1 ); @@ -751,15 +982,15 @@ class Eval { basisFunctions[0] = 1.0; - for( j in 1...degree+1 ){ - left[j] = u - knots[knotSpan_index+1-j]; - right[j] = knots[knotSpan_index+j] - u; + for ( j in 1...degree + 1 ) { + left[j] = u - knots[knotSpan_index + 1 - j]; + right[j] = knots[knotSpan_index + j] - u; saved = 0.0; - for (r in 0...j){ - temp = basisFunctions[r] / ( right[r+1] + left[j-r] ); - basisFunctions[r] = saved + right[r+1]*temp; - saved = left[j-r]*temp; + for ( r in 0...j ) { + temp = basisFunctions[r] / ( right[r + 1] + left[j - r] ); + basisFunctions[r] = saved + right[r + 1] * temp; + saved = left[j - r] * temp; } basisFunctions[j] = saved; @@ -781,9 +1012,8 @@ class Eval { //* the index of the knot span // - public static function knotSpan( degree : Int, u : Float, knots : Array ) : Int - { - return knotSpanGivenN(knots.length - degree - 2, degree, u, knots); + public static function knotSpan( degree : Int, u : Float, knots : Array ) : Int { + return knotSpanGivenN( knots.length - degree - 2, degree, u, knots ); } //Find the span on the knot Array knots of the given parameter @@ -801,30 +1031,24 @@ class Eval { //* the index of the knot span // - public static function knotSpanGivenN( n : Int, degree : Int, u : Float, knots : Array ) : Int - { - if ( u > knots[n+1] - Constants.EPSILON ) - { + public static function knotSpanGivenN( n : Int, degree : Int, u : Float, knots : Array ) : Int { + if ( u > knots[n + 1] - Constants.EPSILON ) { return n; } - if ( u < knots[degree] + Constants.EPSILON ) - { + if ( u < knots[degree] + Constants.EPSILON ) { return degree; } var low = degree - , high = n+1 - , mid = Math.floor( (low + high) / 2 ); + , high = n + 1 + , mid = Math.floor( (low + high) / 2 ); - while( u < knots[ mid ] || u >= knots[ mid + 1 ] ) - { - if ( u < knots[ mid ] ) - { + while ( u < knots[ mid ] || u >= knots[ mid + 1 ] ) { + if ( u < knots[ mid ] ) { high = mid; } - else - { + else { low = mid; } mid = Math.floor( (low + high) / 2 ); @@ -847,10 +1071,10 @@ class Eval { var dim = homoPoint.length , point = [] - , wt = homoPoint[dim-1] + , wt = homoPoint[dim - 1] , l = homoPoint.length - 1; - for (i in 0...l){ + for ( i in 0...l ) { point.push( homoPoint[i] / wt ); } @@ -870,7 +1094,7 @@ class Eval { public static function rational1d( homoPoints : Array ) : Array { var dim = homoPoints[0].length - 1; - return homoPoints.map(function(x : Point){ return x.slice(0,dim); }); + return homoPoints.map( function( x : Point ) { return x.slice( 0, dim ); } ); } //Obtain the weight from a collection of points in homogeneous space, assuming all @@ -885,7 +1109,7 @@ class Eval { //* array of arrays of points, each represented by an array pi with length (dim) public static function rational2d( homoPoints : Array> ) : Array> { - return homoPoints.map(rational1d); + return homoPoints.map( rational1d ); } //Obtain the weight from a collection of points in homogeneous space, assuming all @@ -901,7 +1125,7 @@ class Eval { public static function weight1d( homoPoints : Array ) : Array { var dim = homoPoints[0].length - 1; - return homoPoints.map(function(x){ return x[dim]; }); + return homoPoints.map( function( x ) { return x[dim]; } ); } //Obtain the weight from a collection of points in homogeneous space, assuming all @@ -916,7 +1140,7 @@ class Eval { //* array of arrays of points, each represented by an array pi with length (dim) public static function weight2d( homoPoints : Array> ) : Array> { - return homoPoints.map(weight1d); + return homoPoints.map( weight1d ); } //Dehomogenize an array of points @@ -929,8 +1153,8 @@ class Eval { // //* an array of points, each of length dim - public static function dehomogenize1d( homoPoints : Array ) : Array{ - return homoPoints.map(dehomogenize); + public static function dehomogenize1d( homoPoints : Array ) : Array { + return homoPoints.map( dehomogenize ); } //Dehomogenize a 2d array of pts @@ -944,7 +1168,7 @@ class Eval { //* array of arrays of points, each of length dim public static function dehomogenize2d( homoPoints : Array> ) : Array> { - return homoPoints.map(dehomogenize1d); + return homoPoints.map( dehomogenize1d ); } //Transform a 1d array of points into their homogeneous equivalents @@ -960,7 +1184,7 @@ class Eval { //i the ith control point weight and pi is the ith control point, //hence the dimension of the point is dim + 1 - public static function homogenize1d( controlPoints : Array, weights : Array = null) : Array { + public static function homogenize1d( controlPoints : Array, weights : Array = null ) : Array { var rows = controlPoints.length , dim = controlPoints[0].length @@ -969,20 +1193,20 @@ class Eval { , ref_pt = new Point() , weights = weights != null ? weights : Vec.rep( controlPoints.length, 1.0 ); - for (i in 0...rows) { + for ( i in 0...rows ) { var pt = []; ref_pt = controlPoints[i]; wt = weights[i]; - for (k in 0...dim) { + for ( k in 0...dim ) { pt.push( ref_pt[k] * wt ); } //append the weight - pt.push(wt); + pt.push( wt ); - homo_controlPoints.push(pt); + homo_controlPoints.push( pt ); } return homo_controlPoints; @@ -1001,13 +1225,13 @@ class Eval { // (m x n x dim+1) public static function homogenize2d( controlPoints : Array>, - weights: Array> = null ) : Array> { + weights : Array> = null ) : Array> { var rows = controlPoints.length , homo_controlPoints = new Array>() - , weights = weights != null ? weights : [ for (i in 0...rows ) Vec.rep( controlPoints[0].length, 1.0 ) ]; + , weights = weights != null ? weights : [ for ( i in 0...rows ) Vec.rep( controlPoints[0].length, 1.0 ) ]; - for (i in 0...rows) { - homo_controlPoints.push( homogenize1d(controlPoints[i], weights[i]) ); + for ( i in 0...rows ) { + homo_controlPoints.push( homogenize1d( controlPoints[i], weights[i] ) ); } return homo_controlPoints; diff --git a/src/verb/eval/Intersect.hx b/src/verb/eval/Intersect.hx index 7880a4b4..e2d2f74d 100644 --- a/src/verb/eval/Intersect.hx +++ b/src/verb/eval/Intersect.hx @@ -46,7 +46,7 @@ class Intersect { // //* array of NurbsCurveData objects - public static function surfaces( surface0 : NurbsSurfaceData, surface1 : NurbsSurfaceData, tol : Float) : Array { + public static function surfaces( surface0 : NurbsSurfaceData, surface1 : NurbsSurfaceData, tol : Float ) : Array { // 1) tessellate the two surfaces var tess1 = Tess.rationalSurfaceAdaptive( surface0 ); @@ -56,16 +56,16 @@ class Intersect { var resApprox = Intersect.meshes( tess1, tess2 ); // 3) refine the intersection points so that they lie on both surfaces to tolerance - var exactPls = resApprox.map(function(pl){ - return pl.map( function(inter : MeshIntersectionPoint){ + var exactPls = resApprox.map( function( pl ) { + return pl.map( function( inter : MeshIntersectionPoint ) { return Intersect.surfacesAtPointWithEstimate( surface0, surface1, inter.uv0, inter.uv1, tol ); - }); - }); + } ); + } ); // 4) perform cubic interpolation - return exactPls.map(function(x){ - return Make.rationalInterpCurve( x.map(function(y){ return y.point; }), 3 ); - }); + return exactPls.map( function( x ) { + return Make.rationalInterpCurve( x.map( function( y ) { return y.point; } ), 3 ); + } ); } //Refine a pair of surface points to a point where the two surfaces intersect @@ -82,11 +82,11 @@ class Intersect { // //* a SurfaceSurfaceIntersectionPoint object - public static function surfacesAtPointWithEstimate(surface0 : NurbsSurfaceData, - surface1 : NurbsSurfaceData, - uv1 : UV, - uv2 : UV, - tol : Float ) : SurfaceSurfaceIntersectionPoint { + public static function surfacesAtPointWithEstimate( surface0 : NurbsSurfaceData, + surface1 : NurbsSurfaceData, + uv1 : UV, + uv2 : UV, + tol : Float ) : SurfaceSurfaceIntersectionPoint { var pds, p, pn, pu, pv, pd, qds, q, qn, qu, qv, qd, dist; var maxits = 5; @@ -109,9 +109,9 @@ class Intersect { qd = Vec.dot( qn, q ); //if tolerance is met, exit loop - dist = Vec.distSquared(p, q); + dist = Vec.distSquared( p, q ); - if (dist < tol*tol) { + if ( dist < tol * tol ) { break; } @@ -122,7 +122,7 @@ class Intersect { // 3) x = intersection of all 3 planes var x = Intersect.threePlanes( pn, pd, qn, qd, fn, fd ); - if (x == null) throw "panic!"; + if ( x == null ) throw "panic!"; // 4) represent the difference vectors (pd = x - p, qd = x - q) in the partial // derivative vectors of the respective surfaces (pu, pv, qu, qv) @@ -148,7 +148,7 @@ class Intersect { //repeat its++; - } while( its < maxits ); + } while ( its < maxits ); return new SurfaceSurfaceIntersectionPoint(uv1, uv2, p, dist); } @@ -171,20 +171,20 @@ class Intersect { bbtree0 : IBoundingBoxTree = null, bbtree1 : IBoundingBoxTree = null ) : Array> { - if (bbtree0 == null) bbtree0 = new LazyMeshBoundingBoxTree( mesh0 ); - if (bbtree1 == null) bbtree1 = new LazyMeshBoundingBoxTree( mesh1 ); + if ( bbtree0 == null ) bbtree0 = new LazyMeshBoundingBoxTree( mesh0 ); + if ( bbtree1 == null ) bbtree1 = new LazyMeshBoundingBoxTree( mesh1 ); //bounding box intersection to get all of the face pairs var bbints = Intersect.boundingBoxTrees( bbtree0, bbtree1, 0 ); //get the segments of the intersection crv with uvs - var segments = bbints.map(function(ids : Pair){ + var segments = bbints.map( function( ids : Pair ) { return Intersect.triangles( mesh0, ids.item0, mesh1, ids.item1 ); - }).filter(function(x){ + } ).filter( function( x ) { return x != null; - }).filter(function(x){ + } ).filter( function( x ) { return Vec.distSquared( x.min.point, x.max.point ) > Constants.EPSILON; - }).unique(function(a, b){ + } ).unique( function( a, b ) { //TODO: this is too expensive and this only occurs when the intersection // line is on an edge. we should mark these to avoid doing all of @@ -203,8 +203,8 @@ class Intersect { var d4 = Vec.dot( s4, s4 ); return ( d1 < Constants.EPSILON && d2 < Constants.EPSILON ) || - ( d3 < Constants.EPSILON && d4 < Constants.EPSILON ); - }); + ( d3 < Constants.EPSILON && d4 < Constants.EPSILON ); + } ); return makeMeshIntersectionPolylines( segments ); } @@ -226,7 +226,7 @@ class Intersect { public static function meshSlices( mesh : MeshData, min : Float, max : Float, step : Float ) : Array>> { var bbtree = new MeshBoundingBoxTree( mesh ); - var bb = bbtree.boundingBox(); + var bb = bbtree.boundingBox( ); var x0 = bb.min[0]; var y0 = bb.min[1]; @@ -237,10 +237,10 @@ class Intersect { var span = Vec.span( min, max, step ); var slices = []; - for ( z in span ){ - var pts = [ [x0,y0,z], [x1,y0,z], [x1,y1,z], [x0,y1,z] ]; - var uvs = [ [0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0] ]; - var faces = [ [ 0,1,2 ],[0,2,3] ]; + for ( z in span ) { + var pts = [ [x0, y0, z], [x1, y0, z], [x1, y1, z], [x0, y1, z] ]; + var uvs = [ [0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0] ]; + var faces = [ [ 0, 1, 2 ], [0, 2, 3] ]; var plane = new MeshData( faces, pts, null, uvs ); slices.push( Intersect.meshes( mesh, plane, bbtree ) ); @@ -261,10 +261,10 @@ class Intersect { public static function makeMeshIntersectionPolylines( segments : Array> ) : Array> { - if (segments.length == 0) return []; + if ( segments.length == 0 ) return []; //we need to tag the segment ends - for (s in segments){ + for ( s in segments ) { s.max.opp = s.min; s.min.opp = s.max; } @@ -275,30 +275,30 @@ class Intersect { //flatten everything, we no longer need the segments var ends : Array = []; - for (seg in segments){ - ends.push(seg.min); - ends.push(seg.max); + for ( seg in segments ) { + ends.push( seg.min ); + ends.push( seg.max ); } //step 1: assigning the vertices to the segment ends - for (segEnd in ends){ - if (segEnd.adj != null) continue; + for ( segEnd in ends ) { + if ( segEnd.adj != null ) continue; var adjEnd = lookupAdjacentSegment( segEnd, tree, segments.length ); - if (adjEnd != null && adjEnd.adj == null){ + if ( adjEnd != null && adjEnd.adj == null ) { segEnd.adj = adjEnd; adjEnd.adj = segEnd; } } //step 2: traversing the topology to construct the pls - var freeEnds = ends.filter(function(x){ + var freeEnds = ends.filter( function( x ) { return x.adj == null; - }); + } ); //if you cant find one, youve got a loop (or multiple), we run through all - if (freeEnds.length == 0) { + if ( freeEnds.length == 0 ) { freeEnds = ends; } @@ -306,20 +306,20 @@ class Intersect { var numVisitedEnds = 0; var loopDetected = false; - while (freeEnds.length != 0){ + while ( freeEnds.length != 0 ) { - var end = freeEnds.pop(); + var end = freeEnds.pop( ); - if (!end.visited){ + if ( !end.visited ) { //traverse to end var pl = []; var curEnd = end; - while (curEnd != null) { + while ( curEnd != null ) { //debug - if (curEnd.visited) { + if ( curEnd.visited ) { break; } @@ -327,26 +327,26 @@ class Intersect { curEnd.visited = true; curEnd.opp.visited = true; - pl.push(curEnd); + pl.push( curEnd ); numVisitedEnds += 2; curEnd = curEnd.opp.adj; //loop condition - if (curEnd == end) { + if ( curEnd == end ) { break; } } - if (pl.length > 0) { - pl.push( pl[pl.length-1].opp ); + if ( pl.length > 0 ) { + pl.push( pl[pl.length - 1].opp ); pls.push( pl ); } } - if (freeEnds.length == 0 && ends.length > 0 && ( loopDetected || numVisitedEnds < ends.length )){ + if ( freeEnds.length == 0 && ends.length > 0 && ( loopDetected || numVisitedEnds < ends.length ) ) { loopDetected = true; - var e = ends.pop(); + var e = ends.pop( ); freeEnds.push( e ); } } @@ -364,14 +364,14 @@ class Intersect { // //* array of array of MeshIntersectionPoint - private static function kdTreeFromSegments( segments: Array> ) : KdTree { + private static function kdTreeFromSegments( segments : Array> ) : KdTree { var treePoints = []; //for each segment, transform into two elements, each keyed by pt1 and pt2 - for (seg in segments){ - treePoints.push(new KdPoint(seg.min.point, seg.min )); - treePoints.push(new KdPoint(seg.max.point, seg.max )); + for ( seg in segments ) { + treePoints.push( new KdPoint(seg.min.point, seg.min ) ); + treePoints.push( new KdPoint(seg.max.point, seg.max ) ); } //make our tree @@ -388,15 +388,15 @@ class Intersect { // //* array of array of MeshIntersectionPoint - public static function lookupAdjacentSegment( segEnd: MeshIntersectionPoint, tree : KdTree, numResults : Int ) { + public static function lookupAdjacentSegment( segEnd : MeshIntersectionPoint, tree : KdTree, numResults : Int ) { //we look up 3 elements because we need to find the unique adj ele //we expect one result to be self, one to be neighbor and no more - var adj = tree.nearest(segEnd.point, numResults, Constants.EPSILON) - .filter(function(r){ + var adj = tree.nearest( segEnd.point, numResults, Constants.EPSILON ) + .filter( function( r ) { return segEnd != r.item0.obj; - }) - .map(function(r){ return r.item0.obj; }); + } ) + .map( function( r ) { return r.item0.obj; } ); //if its not unique (i.e. were at a branching point) we dont return it return (adj.length == 1) ? adj[0] : null; @@ -415,42 +415,42 @@ class Intersect { //* array of CurveSurfaceIntersection objects public static function curveAndSurface( curve : NurbsCurveData, - surface : NurbsSurfaceData, - tol : Float = 1e-3, - crvBbTree : IBoundingBoxTree = null, - srfBbTree : IBoundingBoxTree = null ) : Array { + surface : NurbsSurfaceData, + tol : Float = 1e-3, + crvBbTree : IBoundingBoxTree = null, + srfBbTree : IBoundingBoxTree = null ) : Array { crvBbTree = crvBbTree != null ? crvBbTree : new LazyCurveBoundingBoxTree( curve ); srfBbTree = srfBbTree != null ? srfBbTree : new LazySurfaceBoundingBoxTree( surface ); var ints = Intersect.boundingBoxTrees( crvBbTree, srfBbTree, tol ); - return ints.map(function( inter ){ + return ints.map( function( inter ) { var crvSeg = inter.item0; var srfPart = inter.item1; //get the middle param of the curve - var min = crvSeg.knots.first(); - var max = crvSeg.knots.last(); + var min = crvSeg.knots.first( ); + var max = crvSeg.knots.last( ); var u = (min + max) / 2.0; //get the middle param of the surface - var minu = srfPart.knotsU.first(); - var maxu = srfPart.knotsU.last(); + var minu = srfPart.knotsU.first( ); + var maxu = srfPart.knotsU.last( ); - var minv = srfPart.knotsV.first(); - var maxv = srfPart.knotsV.last(); + var minv = srfPart.knotsV.first( ); + var maxv = srfPart.knotsV.last( ); var uv = [ (minu + maxu) / 2.0, (minv + maxv) / 2.0 ]; - return Intersect.curveAndSurfaceWithEstimate( crvSeg, srfPart, [u].concat(uv), tol ); - }).filter(function(x){ + return Intersect.curveAndSurfaceWithEstimate( crvSeg, srfPart, [u].concat( uv ), tol ); + } ).filter( function( x ) { return Vec.distSquared( x.curvePoint, x.surfacePoint ) < tol * tol; - }).unique(function(a,b){ - return Math.abs(a.u - b.u) < 0.5 * tol; - }); + } ).unique( function( a, b ) { + return Math.abs( a.u - b.u ) < 0.5 * tol; + } ); } //Refine an intersection pair for a surface and curve given an initial guess. This is an unconstrained minimization, @@ -466,17 +466,17 @@ class Intersect { // //* a CurveSurfaceIntersection object - public static function curveAndSurfaceWithEstimate( curve : NurbsCurveData, - surface : NurbsSurfaceData, - start_params : Array, - tol : Float = 1e-3 ) : CurveSurfaceIntersection { + public static function curveAndSurfaceWithEstimate( curve : NurbsCurveData, + surface : NurbsSurfaceData, + start_params : Array, + tol : Float = 1e-3 ) : CurveSurfaceIntersection { - var objective = function(x) { - var p1 = Eval.rationalCurvePoint( curve, x[0]) + var objective = function( x ) { + var p1 = Eval.rationalCurvePoint( curve, x[0] ) , p2 = Eval.rationalSurfacePoint( surface, x[1], x[2] ) - , p1_p2 = Vec.sub(p1, p2); + , p1_p2 = Vec.sub( p1, p2 ); - return Vec.dot(p1_p2, p1_p2); + return Vec.dot( p1_p2, p1_p2 ); } // 3 params @@ -498,27 +498,27 @@ class Intersect { //df/du = 2 * dr/du . r(u,v,t) //df/dv = 2 * dr/dv . r(u,v,t) - var grad = function(x){ + var grad = function( x ) { var dc = Eval.rationalCurveDerivatives( curve, x[0], 1 ) - , ds = Eval.rationalSurfaceDerivatives( surface, x[1], x[2], 1 ); + , ds = Eval.rationalSurfaceDerivatives( surface, x[1], x[2], 1 ); - var r = Vec.sub(ds[0][0], dc[0]); + var r = Vec.sub( ds[0][0], dc[0] ); - var drdt = Vec.mul(-1.0, dc[1]); + var drdt = Vec.mul( -1.0, dc[1] ); var drdu = ds[1][0]; var drdv = ds[0][1]; - return [ 2.0 * Vec.dot( drdt, r ), - 2.0 * Vec.dot( drdu, r ), - 2.0 * Vec.dot( drdv, r ) ]; + return [ 2.0 * Vec.dot( drdt, r ), + 2.0 * Vec.dot( drdu, r ), + 2.0 * Vec.dot( drdv, r ) ]; } - var sol_obj = Minimizer.uncmin( objective, start_params, tol*tol, grad ); + var sol_obj = Minimizer.uncmin( objective, start_params, tol * tol, grad ); var final = sol_obj.solution; return new CurveSurfaceIntersection( final[0], [ final[1], final[2] ], - Eval.rationalCurvePoint( curve, final[0] ), Eval.rationalSurfacePoint( surface, final[1], final[2]) ); + Eval.rationalCurvePoint( curve, final[0] ), Eval.rationalSurfacePoint( surface, final[1], final[2] ) ); } //Approximate the intersection of a polyline and mesh while maintaining parameter information @@ -533,8 +533,8 @@ class Intersect { //* an array of PolylineMeshIntersection object public static function polylineAndMesh( polyline : PolylineData, - mesh : MeshData, - tol : Float ) : Array { + mesh : MeshData, + tol : Float ) : Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline ), @@ -542,7 +542,7 @@ class Intersect { var finalResults = []; - for (event in res) { + for ( event in res ) { var polid = event.item0; var faceid = event.item1; @@ -551,10 +551,10 @@ class Intersect { if ( inter == null ) continue; var pt = inter.point; - var u = Vec.lerp(inter.p, [ polyline.params[polid] ], [ polyline.params[polid+1] ] )[0]; - var uv = Mesh.triangleUVFromPoint( mesh, faceid, pt ); + var u = Vec.lerp( inter.p, [ polyline.params[polid] ], [ polyline.params[polid + 1] ] )[0]; + var uv = Mesh.triangleUVFromPoint( mesh, faceid, pt ); - finalResults.push(new PolylineMeshIntersection( pt, u, uv, polid, faceid )); + finalResults.push( new PolylineMeshIntersection( pt, u, uv, polid, faceid ) ); } @@ -575,63 +575,63 @@ class Intersect { //* an array of Pair objects extracted from the yield method of IBoundingBoxTree private static function boundingBoxTrees( ai : IBoundingBoxTree, bi : IBoundingBoxTree, tol : Float = 1e-9 ) - : Array> { + : Array> { var atrees = []; var btrees = []; - - atrees.push(ai); - btrees.push(bi); + + atrees.push( ai ); + btrees.push( bi ); var results = []; - while ( atrees.length > 0 ){ + while ( atrees.length > 0 ) { - var a = atrees.pop(); - var b = btrees.pop(); + var a = atrees.pop( ); + var b = btrees.pop( ); - if (a.empty() || b.empty()) continue; - if ( !a.boundingBox().intersects( b.boundingBox(), tol ) ) continue; + if ( a.empty( ) || b.empty( ) ) continue; + if ( !a.boundingBox( ).intersects( b.boundingBox( ), tol ) ) continue; - var ai = a.indivisible(tol); - var bi = b.indivisible(tol); + var ai = a.indivisible( tol ); + var bi = b.indivisible( tol ); - if (ai && bi) { - results.push( new Pair(a.yield(), b.yield()) ); + if ( ai && bi ) { + results.push( new Pair(a.yield( ), b.yield( )) ); continue; - } else if (ai && !bi) { - var bs = b.split(); - + } else if ( ai && !bi ) { + var bs = b.split( ); + atrees.push( a ); btrees.push( bs.item1 ); - + atrees.push( a ); btrees.push( bs.item0 ); - + continue; - } else if (!ai && bi){ - var as = a.split(); - + } else if ( !ai && bi ) { + var as = a.split( ); + atrees.push( as.item1 ); btrees.push( b ); - + atrees.push( as.item0 ); btrees.push( b ); - + continue; } - var as = a.split(), bs = b.split(); - + var as = a.split( ), bs = b.split( ); + atrees.push( as.item1 ); btrees.push( bs.item1 ); - + atrees.push( as.item1 ); btrees.push( bs.item0 ); - + atrees.push( as.item0 ); btrees.push( bs.item1 ); - + atrees.push( as.item0 ); btrees.push( bs.item0 ); @@ -658,13 +658,13 @@ class Intersect { new LazyCurveBoundingBoxTree( curve1 ), new LazyCurveBoundingBoxTree( curve2 ), 0 ); - return ints.map(function(x : Pair) : CurveCurveIntersection { - return Intersect.curvesWithEstimate( curve1, curve2, x.item0.knots.first(), x.item1.knots.first(), tolerance ); - }).filter(function(x){ + return ints.map( function( x : Pair ) : CurveCurveIntersection { + return Intersect.curvesWithEstimate( curve1, curve2, x.item0.knots.first( ), x.item1.knots.first( ), tolerance ); + } ).filter( function( x ) { return Vec.distSquared( x.point0, x.point1 ) < tolerance; - }).unique(function(a,b){ - return Math.abs(a.u0 - b.u0) < tolerance*5; - }); + } ).unique( function( a, b ) { + return Math.abs( a.u0 - b.u0 ) < tolerance * 5; + } ); } //Refine an intersection pair for two curves given an initial guess. This is an unconstrained minimization, @@ -683,17 +683,16 @@ class Intersect { //* array of CurveCurveIntersection objects private static function curvesWithEstimate( curve0 : NurbsCurveData, - curve1 : NurbsCurveData, - u0 : Float, - u1 : Float, - tolerance : Float ) : CurveCurveIntersection - { + curve1 : NurbsCurveData, + u0 : Float, + u1 : Float, + tolerance : Float ) : CurveCurveIntersection { var objective = function( x : Vector ) : Float { - var p1 = Eval.rationalCurvePoint(curve0, x[0]) - , p2 = Eval.rationalCurvePoint(curve1, x[1]) - , p1_p2 = Vec.sub(p1, p2); + var p1 = Eval.rationalCurvePoint( curve0, x[0] ) + , p2 = Eval.rationalCurvePoint( curve1, x[1] ) + , p1_p2 = Vec.sub( p1, p2 ); - return Vec.dot(p1_p2, p1_p2); + return Vec.dot( p1_p2, p1_p2 ); } // 2 params @@ -709,26 +708,26 @@ class Intersect { //df/du = 2 * dr/du . r(u,t) //df/dt = 2 * dr/dt . r(u,t) - var grad = function(x){ + var grad = function( x ) { var dc0 = Eval.rationalCurveDerivatives( curve0, x[0], 1 ) , dc1 = Eval.rationalCurveDerivatives( curve1, x[1], 1 ); var r = Vec.sub( dc0[0], dc1[0] ); var drdu = dc0[1]; - var drdt = Vec.mul(-1.0, dc1[1]); + var drdt = Vec.mul( -1.0, dc1[1] ); - return [ 2.0 * Vec.dot( drdu, r ), - 2.0 * Vec.dot( drdt, r ) ]; + return [ 2.0 * Vec.dot( drdu, r ), + 2.0 * Vec.dot( drdt, r ) ]; } var sol_obj = Minimizer.uncmin( objective, [u0, u1], tolerance * tolerance, grad ); var u1 = sol_obj.solution[0] - , u2 = sol_obj.solution[1]; + , u2 = sol_obj.solution[1]; - var p1 = Eval.rationalCurvePoint(curve0, u1) - , p2 = Eval.rationalCurvePoint(curve1, u2 ); + var p1 = Eval.rationalCurvePoint( curve0, u1 ) + , p2 = Eval.rationalCurvePoint( curve1, u2 ); return new CurveCurveIntersection(p1, p2, u1, u2); } @@ -746,7 +745,7 @@ class Intersect { // //* a point represented by an array of length (dim) - public static function triangles( mesh0 : MeshData, faceIndex0 : Int, mesh1 : MeshData, faceIndex1 : Int ) : Interval{ + public static function triangles( mesh0 : MeshData, faceIndex0 : Int, mesh1 : MeshData, faceIndex1 : Int ) : Interval { var tri0 = mesh0.faces[faceIndex0]; var tri1 = mesh1.faces[faceIndex1]; @@ -758,34 +757,34 @@ class Intersect { var o1 = mesh1.points[ tri1[0] ]; // 1) intersect with planes to yield ray of intersection - var ray = Intersect.planes(o0, n0, o1, n1); - if (ray == null) return null; + var ray = Intersect.planes( o0, n0, o1, n1 ); + if ( ray == null ) return null; // 2) clip the ray within tri0 var clip1 = clipRayInCoplanarTriangle( ray, mesh0, faceIndex0 ); - if (clip1 == null) return null; + if ( clip1 == null ) return null; // 3) clip the ray within tri1 var clip2 = clipRayInCoplanarTriangle( ray, mesh1, faceIndex1 ); - if (clip2 == null) return null; + if ( clip2 == null ) return null; // 4) find the interval that overlaps - var merged = mergeTriangleClipIntervals(clip1, clip2, mesh0, faceIndex0, mesh1, faceIndex1 ); - if (merged == null) return null; + var merged = mergeTriangleClipIntervals( clip1, clip2, mesh0, faceIndex0, mesh1, faceIndex1 ); + if ( merged == null ) return null; return return new Interval( - new MeshIntersectionPoint(merged.min.uv0, merged.min.uv1, merged.min.point, faceIndex0, faceIndex1 ), - new MeshIntersectionPoint(merged.max.uv0, merged.max.uv1, merged.max.point, faceIndex0, faceIndex1 )); + new MeshIntersectionPoint(merged.min.uv0, merged.min.uv1, merged.min.point, faceIndex0, faceIndex1 ), + new MeshIntersectionPoint(merged.max.uv0, merged.max.uv1, merged.max.point, faceIndex0, faceIndex1 )); } - public static function clipRayInCoplanarTriangle(ray : Ray, mesh : MeshData, faceIndex : Int ) : Interval { + public static function clipRayInCoplanarTriangle( ray : Ray, mesh : MeshData, faceIndex : Int ) : Interval { // 0) construct rays for each edge of the triangle var tri = mesh.faces[faceIndex] , o = [ mesh.points[ tri[0] ], mesh.points[ tri[1] ], mesh.points[ tri[2] ] ] , uvs = [ mesh.uvs[ tri[0] ], mesh.uvs[ tri[1] ], mesh.uvs[ tri[2] ] ] - , uvd = [ Vec.sub(uvs[1], uvs[0]), Vec.sub(uvs[2], uvs[1]), Vec.sub(uvs[0], uvs[2]) ] + , uvd = [ Vec.sub( uvs[1], uvs[0] ), Vec.sub( uvs[2], uvs[1] ), Vec.sub( uvs[0], uvs[2] ) ] , s = [ Vec.sub( o[1], o[0] ), Vec.sub( o[2], o[1] ), Vec.sub( o[0], o[2] ) ] , d = s.map( Vec.normalized ) , l = s.map( Vec.norm ); @@ -795,13 +794,13 @@ class Intersect { var maxU : CurveTriPoint = null; //need to clip in order to maximize the width of the intervals - for (i in 0...3){ + for ( i in 0...3 ) { var o0 = o[i]; var d0 = d[i]; var res = Intersect.rays( o0, d0, ray.origin, ray.dir ); - if (res == null) { + if ( res == null ) { continue; } @@ -809,19 +808,19 @@ class Intersect { var uray = res.u1; //if outside of triangle edge interval, discard - if (useg < -Constants.EPSILON || useg > l[i] + Constants.EPSILON) continue; + if ( useg < -Constants.EPSILON || useg > l[i] + Constants.EPSILON ) continue; //if inside interval - if (minU == null || uray < minU.u){ - minU = new CurveTriPoint( uray, Vec.onRay( ray.origin, ray.dir, uray ), Vec.onRay( uvs[i], uvd[i], useg / l[i])); + if ( minU == null || uray < minU.u ) { + minU = new CurveTriPoint( uray, Vec.onRay( ray.origin, ray.dir, uray ), Vec.onRay( uvs[i], uvd[i], useg / l[i] )); } - if (maxU == null || uray > maxU.u){ - maxU = new CurveTriPoint( uray, Vec.onRay( ray.origin, ray.dir, uray ), Vec.onRay( uvs[i], uvd[i], useg / l[i])); + if ( maxU == null || uray > maxU.u ) { + maxU = new CurveTriPoint( uray, Vec.onRay( ray.origin, ray.dir, uray ), Vec.onRay( uvs[i], uvd[i], useg / l[i] )); } } - if (maxU == null || minU == null) { + if ( maxU == null || minU == null ) { return null; } @@ -830,12 +829,12 @@ class Intersect { } - public static function mergeTriangleClipIntervals(clip1 : Interval, clip2 : Interval, - mesh1 : MeshData, faceIndex1 : Int, mesh2 : MeshData, faceIndex2 : Int ) : Interval { + public static function mergeTriangleClipIntervals( clip1 : Interval, clip2 : Interval, + mesh1 : MeshData, faceIndex1 : Int, mesh2 : MeshData, faceIndex2 : Int ) : Interval { //if the intervals dont overlap, fail if ( clip2.min.u > clip1.max.u + Constants.EPSILON - || clip1.min.u > clip2.max.u + Constants.EPSILON) { + || clip1.min.u > clip2.max.u + Constants.EPSILON ) { return null; } @@ -844,10 +843,10 @@ class Intersect { var max = (clip1.max.u < clip2.max.u) ? new Pair(clip1.max, 0) : new Pair(clip2.max, 1); var res = new Interval( - new MeshIntersectionPoint(null, null, min.item0.point, faceIndex1, faceIndex2), - new MeshIntersectionPoint(null, null, max.item0.point, faceIndex1, faceIndex2)); + new MeshIntersectionPoint(null, null, min.item0.point, faceIndex1, faceIndex2), + new MeshIntersectionPoint(null, null, max.item0.point, faceIndex1, faceIndex2)); - if (min.item1 == 0){ + if ( min.item1 == 0 ) { res.min.uv0 = min.item0.uv; res.min.uv1 = Mesh.triangleUVFromPoint( mesh2, faceIndex2, min.item0.point ); } else { @@ -855,7 +854,7 @@ class Intersect { res.min.uv1 = min.item0.uv; } - if (max.item1 == 0){ + if ( max.item1 == 0 ) { res.max.uv0 = max.item0.uv; res.max.uv1 = Mesh.triangleUVFromPoint( mesh2, faceIndex2, max.item0.point ); } else { @@ -879,11 +878,11 @@ class Intersect { // //* a point represented by an array of length (dim) - public static function planes(origin0 : Point, normal0 : Vector, origin1 : Point, normal1: Vector) : Ray { + public static function planes( origin0 : Point, normal0 : Vector, origin1 : Point, normal1 : Vector ) : Ray { - var d = Vec.cross(normal0, normal1); + var d = Vec.cross( normal0, normal1 ); - if (Vec.dot(d, d) < Constants.EPSILON) return null; + if ( Vec.dot( d, d ) < Constants.EPSILON ) return null; //find the largest index of d var li = 0; @@ -891,24 +890,24 @@ class Intersect { var m1 = Math.abs( d[1] ); var m2 = Math.abs( d[2] ); - if ( m1 > mi ){ + if ( m1 > mi ) { li = 1; mi = m1; } - if ( m2 > mi ){ + if ( m2 > mi ) { li = 2; mi = m2; } var a1, b1, a2, b2; - if ( li == 0 ){ + if ( li == 0 ) { a1 = normal0[1]; b1 = normal0[2]; a2 = normal1[1]; b2 = normal1[2]; - } else if ( li == 1 ){ + } else if ( li == 1 ) { a1 = normal0[0]; b1 = normal0[2]; a2 = normal1[0]; @@ -930,12 +929,12 @@ class Intersect { var y = (d1 * a2 - a1 * d2) / den; var p; - if ( li == 0 ){ - p = [0,x,y]; - } else if ( li == 1 ){ - p = [x,0,y]; + if ( li == 0 ) { + p = [0, x, y]; + } else if ( li == 1 ) { + p = [x, 0, y]; } else { - p = [x,y,0]; + p = [x, y, 0]; } return new Ray( p, Vec.normalized( d ) ); @@ -957,15 +956,15 @@ class Intersect { // //* the point representing the intersection - public static function threePlanes(n0 : Point, d0 : Float, n1 : Point, d1 : Float, n2 : Point, d2 : Float) : Point { + public static function threePlanes( n0 : Point, d0 : Float, n1 : Point, d1 : Float, n2 : Point, d2 : Float ) : Point { var u = Vec.cross( n1, n2 ); var den = Vec.dot( n0, u ); - if (Math.abs(den) < Constants.EPSILON) return null; + if ( Math.abs( den ) < Constants.EPSILON ) return null; var diff = Vec.sub( Vec.mul( d2, n1 ), Vec.mul( d1, n2 ) ); - var num = Vec.add( Vec.mul( d0, u ), Vec.cross( n0, diff)); + var num = Vec.add( Vec.mul( d0, u ), Vec.cross( n0, diff ) ); return Vec.mul( 1 / den, num ); @@ -984,7 +983,7 @@ class Intersect { //* array of parameter pairs representing the intersection of the two parameteric polylines public static function polylines( polyline0 : PolylineData, polyline1 : PolylineData, tol : Float ) - : Array { + : Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline0 ), @@ -992,20 +991,20 @@ class Intersect { var finalResults = []; - for (event in res) { + for ( event in res ) { var polid0 = event.item0; var polid1 = event.item1; - var inter = Intersect.segments(polyline0.points[polid0],polyline0.points[polid0+1], - polyline1.points[polid1],polyline1.points[polid1+1], tol); + var inter = Intersect.segments( polyline0.points[polid0], polyline0.points[polid0 + 1], + polyline1.points[polid1], polyline1.points[polid1 + 1], tol ); if ( inter == null ) continue; //remap to full parametric domain of polyline - inter.u0 = Vec.lerp(inter.u0, [ polyline0.params[polid0] ], [ polyline0.params[polid0+1] ] )[0]; - inter.u1 = Vec.lerp(inter.u1, [ polyline1.params[polid1] ], [ polyline1.params[polid1+1] ] )[0]; + inter.u0 = Vec.lerp( inter.u0, [ polyline0.params[polid0] ], [ polyline0.params[polid0 + 1] ] )[0]; + inter.u1 = Vec.lerp( inter.u1, [ polyline1.params[polid1] ], [ polyline1.params[polid1 + 1] ] )[0]; - finalResults.push(inter); + finalResults.push( inter ); } return finalResults; @@ -1027,23 +1026,23 @@ class Intersect { public static function segments( a0 : Point, a1 : Point, b0 : Point, b1 : Point, tol : Float ) : CurveCurveIntersection { - var a1ma0 = Vec.sub(a1, a0), - aN = Math.sqrt( Vec.dot(a1ma0, a1ma0) ), - a = Vec.mul( 1/ aN, a1ma0 ), - b1mb0 = Vec.sub(b1, b0), - bN = Math.sqrt( Vec.dot(b1mb0, b1mb0) ), - b = Vec.mul( 1 / bN, b1mb0 ), - int_params = Intersect.rays(a0, a, b0, b); + var a1ma0 = Vec.sub( a1, a0 ), + aN = Math.sqrt( Vec.dot( a1ma0, a1ma0 ) ), + a = Vec.mul( 1 / aN, a1ma0 ), + b1mb0 = Vec.sub( b1, b0 ), + bN = Math.sqrt( Vec.dot( b1mb0, b1mb0 ) ), + b = Vec.mul( 1 / bN, b1mb0 ), + int_params = Intersect.rays( a0, a, b0, b ); if ( int_params != null ) { - var u0 = Math.min( Math.max( 0, int_params.u0 / aN ), 1.0), - u1 = Math.min( Math.max( 0, int_params.u1 / bN ), 1.0), - point0 = Vec.onRay( a0, a1ma0, u0 ), - point1 = Vec.onRay( b0, b1mb0, u1 ), - dist = Vec.distSquared(point0, point1); + var u0 = Math.min( Math.max( 0, int_params.u0 / aN ), 1.0 ), + u1 = Math.min( Math.max( 0, int_params.u1 / bN ), 1.0 ), + point0 = Vec.onRay( a0, a1ma0, u0 ), + point1 = Vec.onRay( b0, b1mb0, u1 ), + dist = Vec.distSquared( point0, point1 ); - if ( dist < tol*tol ) { + if ( dist < tol * tol ) { return new CurveCurveIntersection( point0, point1, u0, u1 ); } } @@ -1073,16 +1072,16 @@ class Intersect { dba0 = Vec.dot( b, a0 ), daa = Vec.dot( a, a ), dbb = Vec.dot( b, b ), - div = daa*dbb - dab*dab; + div = daa * dbb - dab * dab; //parallel case if ( Math.abs( div ) < Constants.EPSILON ) { return null; } - var num = dab * (dab0-daa0) - daa * (dbb0-dba0), + var num = dab * (dab0 - daa0) - daa * (dbb0 - dba0), w = num / div, - t = (dab0 - daa0 + w * dab)/daa; + t = (dab0 - daa0 + w * dab) / daa; var p0 = Vec.onRay( a0, a, t ); var p1 = Vec.onRay( b0, b, w ); @@ -1118,14 +1117,14 @@ class Intersect { , b = Vec.dot( n, dir ); //is ray is parallel to triangle plane? - if ( Math.abs( b ) < Constants.EPSILON ){ + if ( Math.abs( b ) < Constants.EPSILON ) { return null; } var r = a / b; //segment goes away from triangle or is beyond segment - if ( r < 0 || r > 1 ){ + if ( r < 0 || r > 1 ) { return null; } @@ -1133,22 +1132,22 @@ class Intersect { var pt = Vec.add( p0, Vec.mul( r, dir ) ); //is I inside T? - var uv = Vec.dot(u,v) - , uu = Vec.dot(u,u) - , vv = Vec.dot(v,v) + var uv = Vec.dot( u, v ) + , uu = Vec.dot( u, u ) + , vv = Vec.dot( v, v ) , w = Vec.sub( pt, v0 ) , wu = Vec.dot( w, u ) , wv = Vec.dot( w, v ) , denom = uv * uv - uu * vv; - if (Math.abs(denom) < Constants.EPSILON){ + if ( Math.abs( denom ) < Constants.EPSILON ) { return null; } var s = ( uv * wv - vv * wu ) / denom , t = ( uv * wu - uu * wv ) / denom; - if (s > 1.0 + Constants.EPSILON || t > 1.0 + Constants.EPSILON || t < -Constants.EPSILON || s < -Constants.EPSILON || s + t > 1.0 + Constants.EPSILON){ + if ( s > 1.0 + Constants.EPSILON || t > 1.0 + Constants.EPSILON || t < -Constants.EPSILON || s < -Constants.EPSILON || s + t > 1.0 + Constants.EPSILON ) { return null; } @@ -1174,18 +1173,18 @@ class Intersect { public static function segmentAndPlane( p0 : Point, p1 : Point, v0 : Point, n : Point ) { //the length of the segment - var denom = Vec.dot( n, Vec.sub(p1,p0) ); + var denom = Vec.dot( n, Vec.sub( p1, p0 ) ); //parallel case if ( Math.abs( denom ) < Constants.EPSILON ) { return null; } - var numer = Vec.dot( n, Vec.sub(v0, p0) ); + var numer = Vec.dot( n, Vec.sub( v0, p0 ) ); var p = numer / denom; - if (p > 1.0 + Constants.EPSILON || p < -Constants.EPSILON ) return null; + if ( p > 1.0 + Constants.EPSILON || p < -Constants.EPSILON ) return null; return { p: p }; @@ -1194,9 +1193,9 @@ class Intersect { } interface IBoundingBoxTree { - public function boundingBox() : BoundingBox; - public function split() : Pair, IBoundingBoxTree>; - public function yield() : T; + public function boundingBox( ) : BoundingBox; + public function split( ) : Pair, IBoundingBoxTree>; + public function yield( ) : T; public function indivisible( tolerance : Float ) : Bool; - public function empty() : Bool; + public function empty( ) : Bool; } diff --git a/src/verb/eval/Make.hx b/src/verb/eval/Make.hx index 5aefcd44..66e94624 100644 --- a/src/verb/eval/Make.hx +++ b/src/verb/eval/Make.hx @@ -42,19 +42,19 @@ class Make { public static function rationalTranslationalSurface( profile : NurbsCurveData, rail : NurbsCurveData ) : NurbsSurfaceData { - var pt0 = Eval.rationalCurvePoint( rail, rail.knots.first() ) - , startu = rail.knots.first() - , endu = rail.knots.last() - , numSamples = 2 * rail.controlPoints.length - , span = ( endu - startu ) / (numSamples-1); + var pt0 = Eval.rationalCurvePoint( rail, rail.knots.first( ) ) + , startu = rail.knots.first( ) + , endu = rail.knots.last( ) + , numSamples = 2 * rail.controlPoints.length + , span = ( endu - startu ) / (numSamples - 1); var crvs = []; - for ( i in 0...numSamples ){ + for ( i in 0...numSamples ) { var pt = Vec.sub( Eval.rationalCurvePoint( rail, startu + i * span ), pt0 ); - var crv = Modify.rationalCurveTransform(profile, [[1,0,0,pt[0]], [0,1,0,pt[1]], [0,0,1,pt[2]], [0,0,0,1]]); + var crv = Modify.rationalCurveTransform( profile, [[1, 0, 0, pt[0]], [0, 1, 0, pt[1]], [0, 0, 1, pt[2]], [0, 0, 0, 1]] ); crvs.push( crv ); } @@ -68,13 +68,13 @@ class Make { // //* an array containing 4 elements, first 2 curves in the V direction, then 2 curves in the U direction - public static function surfaceBoundaryCurves(surface : NurbsSurfaceData) : Array { + public static function surfaceBoundaryCurves( surface : NurbsSurfaceData ) : Array { var crvs = []; - var c0 = Make.surfaceIsocurve( surface, surface.knotsU.first(), false ); - var c1 = Make.surfaceIsocurve( surface, surface.knotsU.last(), false ); - var c2 = Make.surfaceIsocurve( surface, surface.knotsV.first(), true ); - var c3 = Make.surfaceIsocurve( surface, surface.knotsV.last(), true ); + var c0 = Make.surfaceIsocurve( surface, surface.knotsU.first( ), false ); + var c1 = Make.surfaceIsocurve( surface, surface.knotsU.last( ), false ); + var c2 = Make.surfaceIsocurve( surface, surface.knotsV.first( ), true ); + var c3 = Make.surfaceIsocurve( surface, surface.knotsV.last( ), true ); return [c0, c1, c2, c3]; } @@ -89,32 +89,32 @@ class Make { //if the knot already exists in the array, don't make duplicates var reqKnotIndex : Int = -1; - for ( i in 0...knotMults.length ){ - if ( Math.abs( u - knotMults[i].knot ) < Constants.EPSILON ){ + for ( i in 0...knotMults.length ) { + if ( Math.abs( u - knotMults[i].knot ) < Constants.EPSILON ) { reqKnotIndex = i; break; } } var numKnotsToInsert = degree + 1; - if (reqKnotIndex >= 0){ + if ( reqKnotIndex >= 0 ) { numKnotsToInsert = numKnotsToInsert - knotMults[reqKnotIndex].mult; } //insert the knots - var newSrf = numKnotsToInsert > 0 ? Modify.surfaceKnotRefine( surface, Vec.rep(numKnotsToInsert, u), useV ) : surface; + var newSrf = numKnotsToInsert > 0 ? Modify.surfaceKnotRefine( surface, Vec.rep( numKnotsToInsert, u ), useV ) : surface; //obtain the correct index of control points to extract var span = Eval.knotSpan( degree, u, knots ); - if ( Math.abs( u - knots.first() ) < Constants.EPSILON ){ + if ( Math.abs( u - knots.first( ) ) < Constants.EPSILON ) { span = 0; - } else if ( Math.abs( u - knots.last() ) < Constants.EPSILON ) { - span = ( if (useV) newSrf.controlPoints[0].length else newSrf.controlPoints.length ) - 1; + } else if ( Math.abs( u - knots.last( ) ) < Constants.EPSILON ) { + span = ( if ( useV ) newSrf.controlPoints[0].length else newSrf.controlPoints.length ) - 1; } - if (useV){ - return new NurbsCurveData( newSrf.degreeU, newSrf.knotsU, [ for (row in newSrf.controlPoints) row[span] ]); + if ( useV ) { + return new NurbsCurveData( newSrf.degreeU, newSrf.knotsU, [ for ( row in newSrf.controlPoints ) row[span] ]); } return new NurbsCurveData( newSrf.degreeV, newSrf.knotsV, newSrf.controlPoints[span] ); @@ -126,8 +126,8 @@ class Make { //degree var degreeU = curves[0].degree; - if (degreeV == null) degreeV = 3; - if (degreeV > curves.length - 1){ + if ( degreeV == null ) degreeV = 3; + if ( degreeV > curves.length - 1 ) { degreeV = curves.length - 1; } @@ -136,14 +136,14 @@ class Make { var knotsV = []; var controlPoints = []; - for ( i in 0...curves[0].controlPoints.length ){ + for ( i in 0...curves[0].controlPoints.length ) { //extract the ith control pt of each curve - var points = curves.map(function(x){ + var points = curves.map( function( x ) { return x.controlPoints[i]; - }); + } ); - //construct an interpolating curve using this list + //construct an interpolating curve using this list` var c = Make.rationalInterpCurve( points, degreeV, true ); controlPoints.push( c.controlPoints ); knotsV = c.knots; //redundant computation @@ -153,9 +153,26 @@ class Make { } public static function clonedCurve( curve : NurbsCurveData ) : NurbsCurveData { - return new NurbsCurveData( curve.degree, curve.knots.copy(), curve.controlPoints.map(function(x){ return x.copy(); }) ); + return new NurbsCurveData( curve.degree, curve.knots.copy( ), curve.controlPoints.map( function( x ) { return x.copy( ); } ) ); } + public static function clonedSurface( surface : NurbsSurfaceData ) : NurbsSurfaceData { + + var newpts = new Array>(); + var newrow; + for (row in surface.controlPoints){ + newrow = []; + newpts.push( newrow ); + + for (pt in row){ + newrow.push(pt.copy()); + } + } + + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), surface.knotsV.copy( ), newpts ); + } + + //Generate the control points, weights, and knots for a bezier curve of any degree // //**params** @@ -174,11 +191,11 @@ class Make { var degree = controlPoints.length - 1; var knots = []; - for (i in 0...degree+1) { knots.push(0.0); } - for (i in 0...degree+1) { knots.push(1.0); } + for ( i in 0...degree + 1 ) { knots.push( 0.0 ); } + for ( i in 0...degree + 1 ) { knots.push( 1.0 ); } //if weights aren't provided, build uniform weights - if (weights == null) weights = Vec.rep( controlPoints.length, 1.0 ); + if ( weights == null ) weights = Vec.rep( controlPoints.length, 1.0 ); return new NurbsCurveData( degree, knots, Eval.homogenize1d( controlPoints, weights )); } @@ -196,33 +213,33 @@ class Make { // //* NurbsSurfaceData object - public static function fourPointSurface( p1 : Point, p2 : Point, p3 : Point, p4 : Point, degree : Int = 3 ) : NurbsSurfaceData { + public static function fourPointSurface( p1 : Point, p2 : Point, p3 : Point, p4 : Point, degree : Int = 3 ) : NurbsSurfaceData { var degreeFloat : Float = degree; var pts = []; - for (i in 0...degree+1){ + for ( i in 0...degree + 1 ) { var row = []; - for (j in 0...degree+1){ + for ( j in 0...degree + 1 ) { var l = 1.0 - i / degreeFloat; var p1p2 = Vec.lerp( l, p1, p2 ); var p4p3 = Vec.lerp( l, p4, p3 ); var res = Vec.lerp( 1.0 - j / degreeFloat, p1p2, p4p3 ); - res.push(1.0); //add the weight + res.push( 1.0 ); //add the weight - row.push(res); + row.push( res ); } pts.push( row ); } - var zeros = Vec.rep(degree+1, 0.0); - var ones = Vec.rep(degree+1, 1.0); + var zeros = Vec.rep( degree + 1, 0.0 ); + var ones = Vec.rep( degree + 1, 1.0 ); - return new NurbsSurfaceData( degree, degree, zeros.concat(ones), zeros.concat(ones), pts ); + return new NurbsSurfaceData( degree, degree, zeros.concat( ones ), zeros.concat( ones ), pts ); } @@ -249,18 +266,18 @@ class Make { yaxis = Vec.normalized( yaxis ); //if the end angle is less than the start angle, do a circle - if (endAngle < startAngle) endAngle = 2.0 * Math.PI + startAngle; + if ( endAngle < startAngle ) endAngle = 2.0 * Math.PI + startAngle; var theta = endAngle - startAngle , numArcs = 0; //how many arcs? - if (theta <= Math.PI / 2) { + if ( theta <= Math.PI / 2 ) { numArcs = 1; } else { - if (theta <= Math.PI){ + if ( theta <= Math.PI ) { numArcs = 2; - } else if (theta <= 3 * Math.PI / 2){ + } else if ( theta <= 3 * Math.PI / 2 ) { numArcs = 3; } else { numArcs = 4; @@ -269,11 +286,11 @@ class Make { var dtheta = theta / numArcs , n = 2 * numArcs - , w1 = Math.cos( dtheta / 2) - , P0 = Vec.add( center, Vec.add( Vec.mul( xradius * Math.cos(startAngle), xaxis), Vec.mul( yradius * Math.sin(startAngle), yaxis ) ) ) - , T0 = Vec.sub( Vec.mul( Math.cos(startAngle), yaxis ), Vec.mul( Math.sin(startAngle), xaxis) ) + , w1 = Math.cos( dtheta / 2 ) + , P0 = Vec.add( center, Vec.add( Vec.mul( xradius * Math.cos( startAngle ), xaxis ), Vec.mul( yradius * Math.sin( startAngle ), yaxis ) ) ) + , T0 = Vec.sub( Vec.mul( Math.cos( startAngle ), yaxis ), Vec.mul( Math.sin( startAngle ), xaxis ) ) , controlPoints = [] - , knots = Vec.zeros1d( 2 *numArcs + 3 ) + , knots = Vec.zeros1d( 2 * numArcs + 3 ) , index = 0 , angle = startAngle , weights = Vec.zeros1d( numArcs * 2 ); @@ -281,26 +298,26 @@ class Make { controlPoints[0] = P0; weights[0] = 1.0; - for (i in 1...numArcs+1){ + for ( i in 1...numArcs + 1 ) { angle += dtheta; var P2 = Vec.add( center, - Vec.add( Vec.mul( xradius * Math.cos(angle), xaxis), Vec.mul( yradius * Math.sin(angle), yaxis ) ) ); + Vec.add( Vec.mul( xradius * Math.cos( angle ), xaxis ), Vec.mul( yradius * Math.sin( angle ), yaxis ) ) ); - weights[index+2] = 1; - controlPoints[index+2] = P2; + weights[index + 2] = 1; + controlPoints[index + 2] = P2; - var T2 = Vec.sub( Vec.mul( Math.cos(angle), yaxis ), Vec.mul( Math.sin(angle), xaxis) ); + var T2 = Vec.sub( Vec.mul( Math.cos( angle ), yaxis ), Vec.mul( Math.sin( angle ), xaxis ) ); - var inters = Intersect.rays(P0, Vec.mul( 1 / Vec.norm(T0), T0), P2, Vec.mul( 1 / Vec.norm(T2), T2)); - var P1 = Vec.add( P0, Vec.mul(inters.u0, T0)); + var inters = Intersect.rays( P0, Vec.mul( 1 / Vec.norm( T0 ), T0 ), P2, Vec.mul( 1 / Vec.norm( T2 ), T2 ) ); + var P1 = Vec.add( P0, Vec.mul( inters.u0, T0 ) ); - weights[index+1] = w1; - controlPoints[index+1] = P1; + weights[index + 1] = w1; + controlPoints[index + 1] = P1; index += 2; - if (i < numArcs){ + if ( i < numArcs ) { P0 = P2; T0 = T2; } @@ -308,17 +325,17 @@ class Make { var j = 2 * numArcs + 1; - for (i in 0...3){ + for ( i in 0...3 ) { knots[i] = 0.0; - knots[i+j] = 1.0; + knots[i + j] = 1.0; } switch (numArcs){ case 2: knots[3] = knots[4] = 0.5; case 3: - knots[3] = knots[4] = 1/3; - knots[5] = knots[6] = 2/3; + knots[3] = knots[4] = 1 / 3; + knots[5] = knots[6] = 2 / 3; case 4: knots[3] = knots[4] = 0.25; knots[5] = knots[6] = 0.5; @@ -347,7 +364,7 @@ class Make { public static function arc( center : Point, xaxis : Vector, yaxis : Vector, radius : Float, startAngle : Float, endAngle : Float ) : NurbsCurveData { - return ellipseArc( center, Vec.mul( radius, Vec.normalized( xaxis ) ), Vec.mul( radius, Vec.normalized( yaxis ) ), startAngle, endAngle ); + return ellipseArc( center, Vec.mul( radius, Vec.normalized( xaxis ) ), Vec.mul( radius, Vec.normalized( yaxis ) ), startAngle, endAngle ); } //Generate the control points, weights, and knots of a polyline curve @@ -360,13 +377,13 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - public static function polyline( pts : Array) : NurbsCurveData { + public static function polyline( pts : Array ) : NurbsCurveData { - var knots = [0.0,0.0]; + var knots = [0.0, 0.0]; var lsum = 0.0; - for (i in 0...pts.length-1) { - lsum += Vec.dist( pts[i], pts[i+1] ); + for ( i in 0...pts.length - 1 ) { + lsum += Vec.dist( pts[i], pts[i + 1] ); knots.push( lsum ); } knots.push( lsum ); @@ -374,9 +391,9 @@ class Make { //normalize the knot array knots = Vec.mul( 1 / lsum, knots ); - var weights = [ for (i in 0...pts.length) 1.0 ]; + var weights = [ for ( i in 0...pts.length ) 1.0 ]; - return new NurbsCurveData( 1, knots, Eval.homogenize1d(pts.slice(0), weights )); + return new NurbsCurveData( 1, knots, Eval.homogenize1d( pts.slice( 0 ), weights )); } @@ -394,8 +411,8 @@ class Make { public static function extrudedSurface( axis : Point, length : Float, profile : NurbsCurveData ) : NurbsSurfaceData { - var controlPoints = [[],[],[]] - , weights = [[],[],[]]; + var controlPoints = [[], [], []] + , weights = [[], [], []]; var prof_controlPoints = Eval.dehomogenize1d( profile.controlPoints ); var prof_weights = Eval.weight1d( profile.controlPoints ); @@ -404,7 +421,7 @@ class Make { var halfTranslation = Vec.mul( 0.5 * length, axis ); //original control points - for (j in 0...prof_controlPoints.length){ + for ( j in 0...prof_controlPoints.length ) { controlPoints[2][j] = prof_controlPoints[j]; controlPoints[1][j] = Vec.add( halfTranslation, prof_controlPoints[j] ); @@ -415,7 +432,7 @@ class Make { weights[2][j] = prof_weights[j]; } - return new NurbsSurfaceData( 2, profile.degree, [0,0,0,1,1,1], profile.knots, Eval.homogenize2d( controlPoints, weights) ); + return new NurbsSurfaceData( 2, profile.degree, [0, 0, 0, 1, 1, 1], profile.knots, Eval.homogenize2d( controlPoints, weights ) ); } //Generate the control points, weights, and knots of a cylinder @@ -461,74 +478,74 @@ class Make { public static function revolvedSurface( profile : NurbsCurveData, center : Point, axis : Point, theta : Float ) : NurbsSurfaceData { var prof_controlPoints = Eval.dehomogenize1d( profile.controlPoints ) - , prof_weights = Eval.weight1d( profile.controlPoints ); + , prof_weights = Eval.weight1d( profile.controlPoints ); var narcs, knotsU, controlPoints, weights; - if (theta <= Math.PI / 2) { //less than 90 + if ( theta <= Math.PI / 2 ) { //less than 90 narcs = 1; - knotsU = Vec.zeros1d( 6 + 2 * (narcs-1) ); + knotsU = Vec.zeros1d( 6 + 2 * (narcs - 1) ); } else { - if (theta <= Math.PI){ //between 90 and 180 + if ( theta <= Math.PI ) { //between 90 and 180 narcs = 2; - knotsU = Vec.zeros1d( 6 + 2 * (narcs-1) ); - knotsU[3]= knotsU[4] = 0.5; - } else if (theta <= 3 * Math.PI / 2){ //between 180 and 270 + knotsU = Vec.zeros1d( 6 + 2 * (narcs - 1) ); + knotsU[3] = knotsU[4] = 0.5; + } else if ( theta <= 3 * Math.PI / 2 ) { //between 180 and 270 narcs = 3; - knotsU = Vec.zeros1d( 6 + 2 * (narcs-1) ); - knotsU[3]= knotsU[4] = 1/3; - knotsU[5]= knotsU[6] = 2/3; + knotsU = Vec.zeros1d( 6 + 2 * (narcs - 1) ); + knotsU[3] = knotsU[4] = 1 / 3; + knotsU[5] = knotsU[6] = 2 / 3; } else { //between 270 and 360 narcs = 4; - knotsU = Vec.zeros1d( 6 + 2 * (narcs-1) ); - knotsU[3]= knotsU[4] = 1/4; - knotsU[5]= knotsU[6] = 1/2; - knotsU[7]= knotsU[8] = 3/4; + knotsU = Vec.zeros1d( 6 + 2 * (narcs - 1) ); + knotsU[3] = knotsU[4] = 1 / 4; + knotsU[5] = knotsU[6] = 1 / 2; + knotsU[7] = knotsU[8] = 3 / 4; } } var dtheta = theta / narcs //divide the interval into several points - , j = 3 + 2 * (narcs-1); + , j = 3 + 2 * (narcs - 1); //initialize the start and end knots //keep in mind that we only return the knot vector for thes - for (i in 0...3){ + for ( i in 0...3 ) { knotsU[i] = 0.0; - knotsU[j+i] = 1.0; + knotsU[j + i] = 1.0; } //do some initialization var n = 2 * narcs - , wm = Math.cos( dtheta/2.0 ) + , wm = Math.cos( dtheta / 2.0 ) , angle = 0.0 - , sines = Vec.zeros1d( narcs + 1) - , cosines = Vec.zeros1d( narcs + 1) - , controlPoints = Vec.zeros3d( 2*narcs + 1, prof_controlPoints.length, 3 ) - , weights = Vec.zeros2d( 2*narcs + 1, prof_controlPoints.length ); + , sines = Vec.zeros1d( narcs + 1 ) + , cosines = Vec.zeros1d( narcs + 1 ) + , controlPoints = Vec.zeros3d( 2 * narcs + 1, prof_controlPoints.length, 3 ) + , weights = Vec.zeros2d( 2 * narcs + 1, prof_controlPoints.length ); //initialize the sines and cosines - for (i in 1...narcs+1){ + for ( i in 1...narcs + 1 ) { angle += dtheta; - cosines[i] = Math.cos(angle); - sines[i] = Math.sin(angle); + cosines[i] = Math.cos( angle ); + sines[i] = Math.sin( angle ); } //for each pt in the generatrix //i.e. for each row of the 2d knot vectors - for (j in 0...prof_controlPoints.length){ + for ( j in 0...prof_controlPoints.length ) { //get the closest point of the generatrix point on the axis - var O = Trig.rayClosestPoint(prof_controlPoints[j], center, axis) - //X is the vector from the axis to generatrix control pt + var O = Trig.rayClosestPoint( prof_controlPoints[j], center, axis ) + //X is the vector from the axis to generatrix control pt , X = Vec.sub( prof_controlPoints[j], O ) - //radius at that height - , r = Vec.norm(X) - //Y is perpendicular to X and axis, and complete the coordinate system - , Y = Vec.cross(axis,X); - - if ( r > Constants.EPSILON ){ - X = Vec.mul( 1 / r, X); - Y = Vec.mul( 1 / r, Y); + //radius at that height + , r = Vec.norm( X ) + //Y is perpendicular to X and axis, and complete the coordinate system + , Y = Vec.cross( axis, X ); + + if ( r > Constants.EPSILON ) { + X = Vec.mul( 1 / r, X ); + Y = Vec.mul( 1 / r, Y ); } //the first row of controlPoints and weights is just the generatrix @@ -542,34 +559,34 @@ class Make { , angle = 0.0; //proceed around the circle - for (i in 1...narcs+1){ + for ( i in 1...narcs + 1 ) { //O + r * cos(theta) * X + r * sin(theta) * Y //rotated generatrix pt - var P2 = r == 0 ? O : Vec.add( O, Vec.add( Vec.mul( r * cosines[i], X), Vec.mul( r * sines[i], Y) ) ); + var P2 = r == 0 ? O : Vec.add( O, Vec.add( Vec.mul( r * cosines[i], X ), Vec.mul( r * sines[i], Y ) ) ); - controlPoints[index+2][j] = P2; - weights[index+2][j] = prof_weights[j]; + controlPoints[index + 2][j] = P2; + weights[index + 2][j] = prof_weights[j]; //construct the vector tangent to the rotation - var T2 = Vec.sub( Vec.mul( cosines[i], Y), Vec.mul(sines[i], X)); + var T2 = Vec.sub( Vec.mul( cosines[i], Y ), Vec.mul( sines[i], X ) ); - //construct the next control pt - if (r == 0){ - controlPoints[index+1][j] = O; + //construct the next control pt + if ( r == 0 ) { + controlPoints[index + 1][j] = O; } else { - var inters = Intersect.rays(P0, Vec.mul( 1 / Vec.norm(T0), T0), P2, Vec.mul( 1 / Vec.norm(T2), T2)); - var P1 = Vec.add( P0, Vec.mul(inters.u0, T0)); + var inters = Intersect.rays( P0, Vec.mul( 1 / Vec.norm( T0 ), T0 ), P2, Vec.mul( 1 / Vec.norm( T2 ), T2 ) ); + var P1 = Vec.add( P0, Vec.mul( inters.u0, T0 ) ); - controlPoints[index+1][j] = P1; + controlPoints[index + 1][j] = P1; } - weights[index+1][j] = wm * prof_weights[j]; + weights[index + 1][j] = wm * prof_weights[j]; index += 2; - if (i < narcs) { + if ( i < narcs ) { P0 = P2; T0 = T2; } @@ -594,9 +611,9 @@ class Make { //* an object with the following properties: controlPoints, weights, knotsU, knotsV, degreeU, degreeV // - public static function sphericalSurface( center : Point, axis : Point, xaxis : Point, radius : Float ){ + public static function sphericalSurface( center : Point, axis : Point, xaxis : Point, radius : Float ) { - var arc = arc(center, Vec.mul( -1.0, axis ), xaxis, radius, 0.0, Math.PI ); + var arc = arc( center, Vec.mul( -1.0, axis ), xaxis, radius, 0.0, Math.PI ); return revolvedSurface( arc, center, axis, 2 * Math.PI ); } @@ -620,11 +637,11 @@ class Make { var angle = 2 * Math.PI , prof_degree = 1 , prof_ctrl_pts = [ Vec.add( base, Vec.mul( height, axis ) ), Vec.add( base, Vec.mul( radius, xaxis ) )] - , prof_knots = [0.0,0.0,1.0,1.0] - , prof_weights = [1.0,1.0] + , prof_knots = [0.0, 0.0, 1.0, 1.0] + , prof_weights = [1.0, 1.0] , prof = new NurbsCurveData( prof_degree, prof_knots, Eval.homogenize1d( prof_ctrl_pts, prof_weights ) ); - return revolvedSurface(prof, base, axis, angle ); + return revolvedSurface( prof, base, axis, angle ); } @@ -643,20 +660,20 @@ class Make { // 4) solve for c in all 3 dimensions - if (points.length < degree + 1){ + if ( points.length < degree + 1 ) { throw "You need to supply at least degree + 1 points! You only supplied " + points.length + " points."; } var us = [ 0.0 ]; - for (i in 1...points.length){ - var chord = Vec.norm( Vec.sub( points[i], points[i-1] ) ); + for ( i in 1...points.length ) { + var chord = Vec.norm( Vec.sub( points[i], points[i - 1] ) ); var last = us[us.length - 1]; us.push( last + chord ); } //normalize - var max = us[us.length-1]; - for (i in 0...us.length){ + var max = us[us.length - 1]; + for ( i in 0...us.length ) { us[i] = us[i] / max; } @@ -668,9 +685,9 @@ class Make { var start = hasTangents ? 0 : 1; var end = hasTangents ? us.length - degree + 1 : us.length - degree; - for (i in start...end){ + for ( i in start...end ) { var weightSums = 0.0; - for (j in 0...degree){ + for ( j in 0...degree ) { weightSums += us[i + j]; } @@ -686,7 +703,7 @@ class Make { var lst = hasTangents ? 1 : 0; var ld = hasTangents ? points.length - (degree - 1) : points.length - (degree + 1); - for (u in us){ + for ( u in us ) { var span = Eval.knotSpanGivenN( n, degree, u, knots ); var basisFuncs = Eval.basisFunctionsGivenKnotSpanIndex( span, u, degree, knots ); @@ -695,17 +712,17 @@ class Make { var rowstart = Vec.zeros1d( ls ); var rowend = Vec.zeros1d( ld - ls ); - A.push( rowstart.concat(basisFuncs).concat(rowend) ); + A.push( rowstart.concat( basisFuncs ).concat( rowend ) ); } - if (hasTangents){ + if ( hasTangents ) { var ln = A[0].length - 2; - var tanRow0 = [-1.0,1.0].concat( Vec.zeros1d( ln ) ); - var tanRow1 = Vec.zeros1d( ln ).concat( [-1.0,1.0] ); + var tanRow0 = [-1.0, 1.0].concat( Vec.zeros1d( ln ) ); + var tanRow1 = Vec.zeros1d( ln ).concat( [-1.0, 1.0] ); A.spliceAndInsert( 1, 0, tanRow0 ); - A.spliceAndInsert( A.length-1, 0, tanRow1 ); + A.spliceAndInsert( A.length - 1, 0, tanRow1 ); } //for each dimension, solve @@ -715,31 +732,31 @@ class Make { var mult1 = (1 - knots[knots.length - degree - 2] ) / degree; var mult0 = knots[degree + 1] / degree; - for (i in 0...dim){ + for ( i in 0...dim ) { var b : Array; - if (!hasTangents){ - b = points.map(function(x){ return x[i]; }); + if ( !hasTangents ) { + b = points.map( function( x ) { return x[i]; } ); } else { //insert the tangents at the second and second to last index b = [ points[0][i] ]; - b.push( mult0 * start_tangent[i]); - for (j in 1...points.length-1) b.push( points[j][i] ); + b.push( mult0 * start_tangent[i] ); + for ( j in 1...points.length - 1 ) b.push( points[j][i] ); b.push( mult1 * end_tangent[i] ); - b.push( points.last()[i] ); + b.push( points.last( )[i] ); } var x = Mat.solve( A, b ); - xs.push(x); + xs.push( x ); } - var controlPts = Mat.transpose(xs); + var controlPts = Mat.transpose( xs ); - if (!homogeneousPoints){ - var weights = Vec.rep(controlPts.length, 1.0); - controlPts = Eval.homogenize1d(controlPts, weights); + if ( !homogeneousPoints ) { + var weights = Vec.rep( controlPts.length, 1.0 ); + controlPts = Eval.homogenize1d( controlPts, weights ); } return new NurbsCurveData( degree, knots, controlPts ); diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index cd1ab1a5..774e78cd 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -36,7 +36,7 @@ class Modify { //* A new NURBS curve with a reversed parameterization public static function curveReverse( curve : NurbsCurveData ) : NurbsCurveData { - return new NurbsCurveData( curve.degree, knotsReverse( curve.knots ), curve.controlPoints.reversed() ); + return new NurbsCurveData( curve.degree, knotsReverse( curve.knots ), curve.controlPoints.reversed( ) ); } //Reverse the parameterization of a NURBS surface in the specified direction. The domain is unaffected. @@ -51,14 +51,14 @@ class Modify { //* A new NURBS surface with a reversed parameterization in the given direction public static function surfaceReverse( surface : NurbsSurfaceData, useV : Bool = false ) : NurbsSurfaceData { - if (useV){ - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU, knotsReverse(surface.knotsV), - [for (row in surface.controlPoints) row.reversed() ]); + if ( useV ) { + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU, knotsReverse( surface.knotsV ), + [for ( row in surface.controlPoints ) row.reversed( ) ]); } - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, knotsReverse(surface.knotsU), surface.knotsV, - surface.controlPoints.reversed()); + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, knotsReverse( surface.knotsU ), surface.knotsV, + surface.controlPoints.reversed( )); } //Reverse a knot vector @@ -72,13 +72,13 @@ class Modify { //* The reversed array of knots public static function knotsReverse( knots : KnotArray ) : KnotArray { - var min = knots.first(); - var max = knots.last(); + var min = knots.first( ); + var max = knots.last( ); var l = [ min ]; var len = knots.length; - for (i in 1...len){ - l.push( l[i-1] + ( knots[len-i] - knots[len-i-1] ) ); + for ( i in 1...len ) { + l.push( l[i - 1] + ( knots[len - i] - knots[len - i - 1] ) ); } return l; @@ -95,45 +95,45 @@ class Modify { //* A collection of NURBS curves, all with the same knot vector public static function unifyCurveKnotVectors( curves : Array ) : Array { - curves = curves.map(Make.clonedCurve); + curves = curves.map( Make.clonedCurve ); - var maxDegree = curves.fold(function(x,a){ return Modify.imax(x.degree, a); }, 0 ); + var maxDegree = curves.fold( function( x, a ) { return Modify.imax( x.degree, a ); }, 0 ); //elevate all curves to the same degree - for (i in 0...curves.length){ - if (curves[i].degree < maxDegree){ + for ( i in 0...curves.length ) { + if ( curves[i].degree < maxDegree ) { curves[i] = Modify.curveElevateDegree( curves[i], maxDegree ); } } - var knotIntervals = [ for (c in curves) new Interval( c.knots.first(), c.knots.last() ) ]; + var knotIntervals = [ for ( c in curves ) new Interval( c.knots.first( ), c.knots.last( ) ) ]; //shift all knot vectors to start at 0.0 - for (i in 0...curves.length){ + for ( i in 0...curves.length ) { var min = knotIntervals[i].min; - curves[i].knots = curves[i].knots.map(function(x){ return x - min; }); + curves[i].knots = curves[i].knots.map( function( x ) { return x - min; } ); } //find the max knot span - var knotSpans = knotIntervals.map(function(x){ return x.max - x.min; }); - var maxKnotSpan = knotSpans.fold(function(x,a){ return Math.max(x, a); }, 0.0 ); + var knotSpans = knotIntervals.map( function( x ) { return x.max - x.min; } ); + var maxKnotSpan = knotSpans.fold( function( x, a ) { return Math.max( x, a ); }, 0.0 ); //scale all of the knot vectors to match - for (i in 0...curves.length){ + for ( i in 0...curves.length ) { var scale = maxKnotSpan / knotSpans[i]; - curves[i].knots = curves[i].knots.map(function(x){ return x * scale; }); + curves[i].knots = curves[i].knots.map( function( x ) { return x * scale; } ); } //merge all of the knot vectors - var mergedKnots = curves.fold(function(x,a){ return Vec.sortedSetUnion(x.knots,a); }, []); + var mergedKnots = curves.fold( function( x, a ) { return Vec.sortedSetUnion( x.knots, a ); }, [] ); //knot refinement on each curve - for (i in 0...curves.length){ + for ( i in 0...curves.length ) { var rem = Vec.sortedSetSub( mergedKnots, curves[i].knots ); - if (rem.length == 0) { + if ( rem.length == 0 ) { curves[i] = curves[i]; } - curves[i] = Modify.curveKnotRefine( curves[i], rem ); + curves[i] = Modify.curveKnotRefine( curves[i], rem ); } return curves; @@ -160,7 +160,7 @@ class Modify { public static function curveElevateDegree( curve : NurbsCurveData, finalDegree : Int ) : NurbsCurveData { - if (finalDegree <= curve.degree) return curve; + if ( finalDegree <= curve.degree ) return curve; //args var n = curve.knots.length - curve.degree - 2; @@ -172,7 +172,7 @@ class Modify { var dim = curve.controlPoints[0].length; //intermediate values - var bezalfs = Vec.zeros2d( newDegree + degreeInc + 1, newDegree + 1); + var bezalfs = Vec.zeros2d( newDegree + degreeInc + 1, newDegree + 1 ); var bpts = []; var ebpts = []; var Nextbpts = []; @@ -180,7 +180,7 @@ class Modify { var m = n + newDegree + 1; var ph = finalDegree; - var ph2 = Math.floor(ph / 2); + var ph2 = Math.floor( ph / 2 ); //return values var Qw = []; @@ -190,135 +190,135 @@ class Modify { bezalfs[0][0] = 1.0; bezalfs[ph][newDegree] = 1.0; - for (i in 1...ph2+1){ + for ( i in 1...ph2 + 1 ) { var inv = 1.0 / Binomial.get( ph, i ); - var mpi = imin(newDegree,i); - for (j in imax(0,i-degreeInc)...mpi+1){ - bezalfs[i][j] = inv * Binomial.get(newDegree,j) * Binomial.get(degreeInc,i-j); + var mpi = imin( newDegree, i ); + for ( j in imax( 0, i - degreeInc )...mpi + 1 ) { + bezalfs[i][j] = inv * Binomial.get( newDegree, j ) * Binomial.get( degreeInc, i - j ); } } - for (i in ph2+1...ph){ - var mpi = imin(newDegree,i); - for (j in imax(0,i-degreeInc)...mpi+1){ - bezalfs[i][j] = bezalfs[ph-i][newDegree-j]; + for ( i in ph2 + 1...ph ) { + var mpi = imin( newDegree, i ); + for ( j in imax( 0, i - degreeInc )...mpi + 1 ) { + bezalfs[i][j] = bezalfs[ph - i][newDegree - j]; } } var mh = ph; - var kind = ph+1; + var kind = ph + 1; var r = -1; var a = newDegree; - var b = newDegree+1; + var b = newDegree + 1; var cind = 1; var ua = knots[0]; Qw[0] = controlPoints[0]; - for (i in 0...ph+1){ + for ( i in 0...ph + 1 ) { Uh[i] = ua; } - for (i in 0...newDegree+1){ + for ( i in 0...newDegree + 1 ) { bpts[i] = controlPoints[i]; } - while (b < m){ + while ( b < m ) { var i = b; - while( b < m && knots[b] == knots[b+1]){ - b = b+1; + while ( b < m && knots[b] == knots[b + 1] ) { + b = b + 1; } - var mul = b-i+1; - var mh = mh+mul+degreeInc; + var mul = b - i + 1; + var mh = mh + mul + degreeInc; var ub = knots[b]; var oldr = r; - r = newDegree-mul; + r = newDegree - mul; //check for integer arithmetic - var lbz = oldr > 0 ? Math.floor((oldr+2)/2) : 1; - var rbz = r > 0 ? Math.floor(ph-(r+1)/2) : ph; - if (r > 0){ - var numer = ub-ua; + var lbz = oldr > 0 ? Math.floor( (oldr + 2) / 2 ) : 1; + var rbz = r > 0 ? Math.floor( ph - (r + 1) / 2 ) : ph; + if ( r > 0 ) { + var numer = ub - ua; var alfs = []; var k = newDegree; - while (k > mul){ - alfs[k-mul-1] = numer/(knots[a+k]-ua); //integer arithmetic? + while ( k > mul ) { + alfs[k - mul - 1] = numer / (knots[a + k] - ua); //integer arithmetic? k--; } - for( j in 1...r+1){ - var save = r-j; - var s = mul+j; + for ( j in 1...r + 1 ) { + var save = r - j; + var s = mul + j; var k = newDegree; - while ( k >= s ){ - bpts[k] = Vec.add( Vec.mul(alfs[k-s],bpts[k]), Vec.mul(1.0-alfs[k-s], bpts[k-1])); + while ( k >= s ) { + bpts[k] = Vec.add( Vec.mul( alfs[k - s], bpts[k] ), Vec.mul( 1.0 - alfs[k - s], bpts[k - 1] ) ); k--; } Nextbpts[save] = bpts[newDegree]; } } - for( i in lbz...ph+1){ + for ( i in lbz...ph + 1 ) { ebpts[i] = Vec.zeros1d( dim ); - var mpi = imin(newDegree,i); - for (j in imax(0,i-degreeInc)...mpi+1){ - ebpts[i] = Vec.add( ebpts[i], Vec.mul( bezalfs[i][j], bpts[j])); + var mpi = imin( newDegree, i ); + for ( j in imax( 0, i - degreeInc )...mpi + 1 ) { + ebpts[i] = Vec.add( ebpts[i], Vec.mul( bezalfs[i][j], bpts[j] ) ); } } - if (oldr > 1){ - var first = kind-2; + if ( oldr > 1 ) { + var first = kind - 2; var last = kind; - var den = ub-ua; - var bet = (ub-Uh[kind-1])/den; //integer arithmetic? - for (tr in 1...oldr){ + var den = ub - ua; + var bet = (ub - Uh[kind - 1]) / den; //integer arithmetic? + for ( tr in 1...oldr ) { var i = first; var j = last; - var kj = j-kind+1; - while (j-i > tr){ - if (i < cind){ - var alf = (ub-Uh[i])/(ua-Uh[i]); //integer arithmetic? - Qw[i] = Vec.lerp(alf, Qw[i], Qw[i-1]); + var kj = j - kind + 1; + while ( j - i > tr ) { + if ( i < cind ) { + var alf = (ub - Uh[i]) / (ua - Uh[i]); //integer arithmetic? + Qw[i] = Vec.lerp( alf, Qw[i], Qw[i - 1] ); } - if ( j >= lbz ){ - if ( j-tr <= kind-ph+oldr ){ - var gam = (ub-Uh[j-tr])/den; - ebpts[kj] = Vec.lerp(gam, ebpts[kj], ebpts[kj+1]); + if ( j >= lbz ) { + if ( j - tr <= kind - ph + oldr ) { + var gam = (ub - Uh[j - tr]) / den; + ebpts[kj] = Vec.lerp( gam, ebpts[kj], ebpts[kj + 1] ); } } else { - ebpts[kj] = Vec.lerp(bet, ebpts[kj], ebpts[kj+1]); + ebpts[kj] = Vec.lerp( bet, ebpts[kj], ebpts[kj + 1] ); } - i = i+1; - j = j-1; - kj = kj-1; + i = i + 1; + j = j - 1; + kj = kj - 1; } - first = first-1; - last = last+1; + first = first - 1; + last = last + 1; } } - if (a != newDegree){ - for (i in 0...ph-oldr){ + if ( a != newDegree ) { + for ( i in 0...ph - oldr ) { Uh[kind] = ua; - kind = kind+1; + kind = kind + 1; } } - for (j in lbz...rbz+1){ + for ( j in lbz...rbz + 1 ) { Qw[cind] = ebpts[j]; cind = cind + 1; } - if (b < m){ - for (j in 0...r){ + if ( b < m ) { + for ( j in 0...r ) { bpts[j] = Nextbpts[j]; } - for (j in r...newDegree+1){ - bpts[j] = controlPoints[b-newDegree+j]; + for ( j in r...newDegree + 1 ) { + bpts[j] = controlPoints[b - newDegree + j]; } a = b; - b = b+1; + b = b + 1; ua = ub; } else { - for (i in 0...ph+1){ - Uh[kind+i] = ub; + for ( i in 0...ph + 1 ) { + Uh[kind + i] = ub; } } } - nh = mh-ph-1; + nh = mh - ph - 1; return new NurbsCurveData( finalDegree, Uh, Qw ); } @@ -338,16 +338,16 @@ class Modify { var pts = Eval.dehomogenize2d( surface.controlPoints ); - for (i in 0...pts.length){ - for (j in 0...pts[i].length){ + for ( i in 0...pts.length ) { + for ( j in 0...pts[i].length ) { var homoPt = pts[i][j]; - homoPt.push(1.0); + homoPt.push( 1.0 ); pts[i][j] = Mat.dot( mat, homoPt ).slice( 0, homoPt.length - 1 ); } } - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy(), surface.knotsV.copy(), Eval.homogenize2d(pts, Eval.weight2d( surface.controlPoints)) ); + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), surface.knotsV.copy( ), Eval.homogenize2d( pts, Eval.weight2d( surface.controlPoints ) ) ); } //Transform a NURBS curve using a matrix @@ -365,15 +365,15 @@ class Modify { var pts = Eval.dehomogenize1d( curve.controlPoints ); - for (i in 0...pts.length){ + for ( i in 0...pts.length ) { var homoPt = pts[i]; - homoPt.push(1.0); + homoPt.push( 1.0 ); pts[i] = Mat.dot( mat, homoPt ).slice( 0, homoPt.length - 1 ); } - return new NurbsCurveData( curve.degree, curve.knots.copy(), Eval.homogenize1d( pts, Eval.weight1d( curve.controlPoints) ) ); + return new NurbsCurveData( curve.degree, curve.knots.copy( ), Eval.homogenize1d( pts, Eval.weight1d( curve.controlPoints ) ) ); } @@ -391,45 +391,223 @@ class Modify { public static function surfaceKnotRefine( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { - //TODO: make this faster by taking advantage of repeat computations in every row - // i.e. no reason to recompute the knot vectors on every row + if ( knotsToInsert.length == 0 ) return Make.clonedSurface( surface ); - var newPts = [] - , knots - , degree - , ctrlPts; + var degree, controlPoints = surface.controlPoints, knots; - //u dir - if (!useV){ - ctrlPts = Mat.transpose( surface.controlPoints ); - knots = surface.knotsU; + if (useV){ + degree = surface.degreeV; + knots = surface.knotsV; + } else { degree = surface.degreeU; - //v dir + knots = surface.knotsU; + } + + var n = useV ? controlPoints[0].length - 1 : controlPoints.length - 1 + , m = n + degree + 1 + , r = knotsToInsert.length - 1 + , a = Eval.knotSpan( degree, knotsToInsert[0], knots ) + , b = Eval.knotSpan( degree, knotsToInsert[r], knots ) + , controlPoints_post = new Array>() + , knots_post = new KnotArray(); + + //new control pts + + if (useV){ + + // count unique elements in knot collection + + var km = Analyze.knotMultiplicities( knotsToInsert ); + + for (i in 0...controlPoints.length + km.length - 1 ){ + controlPoints_post.push([]); + } + + for ( i in 0...a - degree + 1 ) { + for ( j in 0...controlPoints.length){ + controlPoints_post[j][i] = controlPoints[j][i]; + } + } + + for ( i in b - 1...n + 1 ) { + var l = i + r + 1; + for ( j in 0...controlPoints.length){ + controlPoints_post[j][l] = controlPoints[j][i]; + } + } } else { - ctrlPts = surface.controlPoints; - knots = surface.knotsV; - degree = surface.degreeV; + for ( i in 0...a - degree + 1 ) { + controlPoints_post[i] = controlPoints[i].slice(0); + } + + for ( i in b - 1...n + 1 ) { + controlPoints_post[i + r + 1] = controlPoints[i].slice(0); + } + } + + //new knot vector + + for ( i in 0...a + 1 ) { + knots_post[i] = knots[i]; } - //do knot refinement on every row - var c : NurbsCurveData = null; - for (cptrow in ctrlPts){ - c = curveKnotRefine( new NurbsCurveData(degree, knots, cptrow), knotsToInsert ); - newPts.push( c.controlPoints ); + for ( i in b + degree...m + 1 ) { + knots_post[i + r + 1] = knots[i]; } - var newknots = c.knots; + var i = b + degree - 1; + var k = b + degree + r; + var j = r; + var ci; + + while ( j >= 0 ) { + + while ( knotsToInsert[j] <= knots[i] && i > a ) { + var wi = k - degree - 1; + var xi = i - degree - 1; + + if (useV){ + for (ci in 0...controlPoints_post.length){ + controlPoints_post[ci][wi] = controlPoints[ci][xi].slice(0); + } + } else { + controlPoints_post[wi] = controlPoints[xi].slice(0); + } + + knots_post[k] = knots[i]; + k = k - 1; + i = i - 1; + } + + if (useV){ + for (ci in 0...controlPoints_post.length){ + controlPoints_post[ci][k - degree - 1] = controlPoints_post[ci][k - degree].slice(0); + } + } else { + controlPoints_post[k - degree - 1] = controlPoints_post[k - degree].slice(0); + } + + for ( l in 1...degree + 1 ) { + + var ind = k - degree + l; + var alfa = knots_post[k + l] - knotsToInsert[j]; + + if ( Math.abs( alfa ) < Constants.EPSILON ) { - //u dir - if (!useV){ - newPts = Mat.transpose( newPts ); - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy(), newPts ); - //v dir + if (useV){ + for (ci in 0...controlPoints_post.length){ + controlPoints_post[ci][ind - 1] = controlPoints_post[ci][ind]; + } + } else { + controlPoints_post[ind - 1] = controlPoints_post[ind].slice(0); + } + } else { + alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); + + if (useV){ + for (wi in 0...controlPoints_post.length){ + controlPoints_post[wi][ind - 1] = + Vec.lerp( alfa, controlPoints_post[wi][ind - 1], controlPoints_post[wi][ind] ); + } + } else { + for (wi in 0...controlPoints_post[ind].length){ + controlPoints_post[ind - 1][wi] = Vec.lerp( alfa, controlPoints_post[ind - 1][wi], controlPoints_post[ind][wi] ); + } + } + } + } + + knots_post[k] = knotsToInsert[j]; + k = k - 1; + + j--; + } + + if ( useV ) { + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy(), knots_post, controlPoints_post ); } else { - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy(), newknots, newPts ); + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, knots_post, surface.knotsV.copy(), controlPoints_post ); } } + public static function decomposeSurfaceIntoBeziers( surface : NurbsSurfaceData ) : Array> { + + //find all of the unique knot values and their multiplicity + //for each, increase their multiplicity to degree + 1 + + var knotmultsU = Analyze.knotMultiplicities( surface.knotsU ); + var reqMultU = surface.degreeU + 1; + + //insert the knots + + for ( knotmult in knotmultsU ) { + if ( knotmult.mult < reqMultU ) { + var knotsInsert = Vec.rep( reqMultU - knotmult.mult, knotmult.knot ); + if (knotsInsert.length == 0) continue; + surface = surfaceKnotRefine( surface, knotsInsert, false ); + } + } + + var knotmultsV = Analyze.knotMultiplicities( surface.knotsV ); + var reqMultV = surface.degreeV + 1; + + for ( knotmult in knotmultsV ) { + if ( knotmult.mult < reqMultV ) { + var knotsInsert = Vec.rep( reqMultV - knotmult.mult, knotmult.knot ); + if (knotsInsert.length == 0) continue; + surface = surfaceKnotRefine( surface, knotsInsert, true ); + } + } + + // extract sub control point matrices + + var numU = surface.knotsU.length / reqMultU - 1; + var numV = surface.knotsV.length / reqMultV - 1; + + var knotLengthU = reqMultU * 2; + var knotLengthV = reqMultV * 2; + + var subSurfaces : Array> = []; + + var i = 0; + while ( i < surface.controlPoints.length ) { + + var row = []; + subSurfaces.push( row ); + + var ktsU = surface.knotsU.slice( i, i + knotLengthU ); + + var j = 0; + while ( j < surface.controlPoints[i].length ) { + + var ktsV = surface.knotsV.slice( j, j + knotLengthV ); + var pts = submatrix( surface.controlPoints, i, j, reqMultV, reqMultU ); + + row.push( new NurbsSurfaceData( surface.degreeU, surface.degreeV, ktsU, ktsV, pts ) ); + + j += reqMultV; + } + + i += reqMultU; + } + + return subSurfaces; + } + + + private static function submatrix( mat : Array>, startRow : Int, startCol : Int, rows : Int, cols : Int ) : Array> { + + var newmat = []; + + for ( i in startRow...startRow+rows ){ + newmat.push( mat[i].slice(startCol, startCol+cols )); + } + + return newmat; + + } + + //Decompose a NURBS curve into a collection of bezier's. Useful //as each bezier fits into it's convex hull. This is a useful starting //point for intersection, closest point, divide & conquer algorithms @@ -455,10 +633,12 @@ class Modify { var reqMult = degree + 1; //insert the knots - for (knotmult in knotmults) { // (var i = 0; i < mults.length; i++){ - if ( knotmult.mult < reqMult ){ + for ( knotmult in knotmults ) { + if ( knotmult.mult < reqMult ) { var knotsInsert = Vec.rep( reqMult - knotmult.mult, knotmult.knot ); + if (knotsInsert.length == 0) continue; + var res = curveKnotRefine( new NurbsCurveData(degree, knots, controlPoints), knotsInsert ); knots = res.knots; @@ -472,7 +652,7 @@ class Modify { var crvs = []; var i = 0; - while ( i < controlPoints.length){ + while ( i < controlPoints.length ) { var kts = knots.slice( i, i + crvKnotLength ); var pts = controlPoints.slice( i, i + reqMult ); @@ -501,7 +681,7 @@ class Modify { public static function curveKnotRefine( curve : NurbsCurveData, knotsToInsert : Array ) : NurbsCurveData { - if ( knotsToInsert.length == 0 ) return Make.clonedCurve(curve); + if ( knotsToInsert.length == 0 ) return Make.clonedCurve( curve ); var degree = curve.degree , controlPoints = curve.controlPoints @@ -516,21 +696,21 @@ class Modify { , knots_post = new KnotArray(); //new control pts - for (i in 0...a-degree+1){ + for ( i in 0...a - degree + 1 ) { controlPoints_post[i] = controlPoints[i]; } - for (i in b-1...n+1){ - controlPoints_post[i+r+1] = controlPoints[i]; + for ( i in b - 1...n + 1 ) { + controlPoints_post[i + r + 1] = controlPoints[i]; } //new knot vector - for (i in 0...a+1){ + for ( i in 0...a + 1 ) { knots_post[i] = knots[i]; } - for (i in b+degree...m+1){ - knots_post[i+r+1] = knots[i]; + for ( i in b + degree...m + 1 ) { + knots_post[i + r + 1] = knots[i]; } var i = b + degree - 1; @@ -539,28 +719,26 @@ class Modify { while ( j >= 0 ) { - while (knotsToInsert[j] <= knots[i] && i > a){ - controlPoints_post[k-degree-1] = controlPoints[i-degree-1]; + while ( knotsToInsert[j] <= knots[i] && i > a ) { + controlPoints_post[k - degree - 1] = controlPoints[i - degree - 1]; knots_post[k] = knots[i]; - k = k-1; - i = i-1; + k = k - 1; + i = i - 1; } - controlPoints_post[k-degree-1] = controlPoints_post[k-degree]; + controlPoints_post[k - degree - 1] = controlPoints_post[k - degree]; - for ( l in 1...degree+1){ + for ( l in 1...degree + 1 ) { - var ind = k-degree+l; - var alfa = knots_post[k+l] - knotsToInsert[j]; + var ind = k - degree + l; + var alfa = knots_post[k + l] - knotsToInsert[j]; - if (Math.abs(alfa) < Constants.EPSILON){ - controlPoints_post[ind-1] = controlPoints_post[ind]; + if ( Math.abs( alfa ) < Constants.EPSILON ) { + controlPoints_post[ind - 1] = controlPoints_post[ind]; } else { - alfa = alfa / (knots_post[k+l] - knots[i-degree+l]); + alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); - controlPoints_post[ind-1] = Vec.add( - Vec.mul( alfa, controlPoints_post[ind-1] ), - Vec.mul( (1.0 - alfa), controlPoints_post[ind]) ); + controlPoints_post[ind - 1] = Vec.lerp( alfa, controlPoints_post[ind - 1], controlPoints_post[ind] ); } } @@ -620,62 +798,62 @@ class Modify { //new knot vector //insert the k knots that will not be affected - for (i in 1...k+1){ + for ( i in 1...k + 1 ) { knots_post[i] = knots[i]; } //insert the new repeat knots - for (i in 1...r+1){ - knots_post[k+i] = u; + for ( i in 1...r + 1 ) { + knots_post[k + i] = u; } //insert the rest of the knots - for (i in k+1...knots.length){ - knots_post[i+r] = knots[i]; + for ( i in k + 1...knots.length ) { + knots_post[i + r] = knots[i]; } //control point generation //copy the original control points before the insertion span - for (i in 0...k - degree + 1){ + for ( i in 0...k - degree + 1 ) { controlPoints_post[i] = controlPoints[i]; } //copy the original controls after the insertion span - for (i in k-s...num_pts){ - controlPoints_post[i+r] = controlPoints[i]; + for ( i in k - s...num_pts ) { + controlPoints_post[i + r] = controlPoints[i]; } //collect the affected control points in this temporary array - for (i in 0...degree-s+1){ - controlPoints_temp[i] = controlPoints[k-degree+i]; + for ( i in 0...degree - s + 1 ) { + controlPoints_temp[i] = controlPoints[k - degree + i]; } var L : Int = 0 , alpha : Float = 0; //insert knot r times - for (j in 1...r+1){ + for ( j in 1...r + 1 ) { - L = k-degree+j; + L = k - degree + j; - for (i in 0...degree-j-s+1){ + for ( i in 0...degree - j - s + 1 ) { - alpha = ( u - knots[L+i] ) / ( knots[i+k+1] - knots[L+i] ); + alpha = ( u - knots[L + i] ) / ( knots[i + k + 1] - knots[L + i] ); controlPoints_temp[i] = Vec.add( - Vec.mul( alpha, controlPoints_temp[i+1] ), - Vec.mul( (1.0 - alpha), controlPoints_temp[i]) - ); + Vec.mul( (1.0 - alpha), controlPoints_temp[i] ), + Vec.mul( alpha, controlPoints_temp[i + 1] ) + ); } controlPoints_post[ L ] = controlPoints_temp[0]; - controlPoints_post[k+r-j-s] = controlPoints_temp[degree-j-s]; + controlPoints_post[k + r - j - s] = controlPoints_temp[degree - j - s]; } //not so confident about this part - for (i in L+1...k-s){ + for ( i in L + 1...k - s ) { controlPoints_post[i] = controlPoints_temp[ i - L ]; } diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index f60ed18f..00ca8279 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -3,6 +3,11 @@ package verb.eval; import verb.core.ArrayExtensions; using verb.core.ArrayExtensions; +import verb.eval.Eval; + +import verb.core.Constants; +import verb.core.Mat; +import verb.core.BoundingBox; import verb.core.Intersections; import verb.core.Data; import verb.core.Vec; @@ -17,341 +22,1044 @@ import verb.core.Trig; // increased computational cost. For example, it is sometimes necessarily to compute higher order derivatives in order to // obtain these more economical results. Your usage of these algorithms should consider these tradeoffs. +// TODO +class NewMeshData { + var points : Array; + var faces : Array; + var uvs : Array; +} + +class BezierEdgeIndices { + public var n : Pair; + public var s : Pair; + public var e : Pair; + public var w : Pair; + public function new(){} +} + +enum EdgeSide { + North; South; East; West; +} + @:expose("eval.Tess") class Tess { - //Sample a NURBS curve at equally spaced parametric intervals - // - //**params** - // - //* NurbsCurveData object - //* integer number of samples - //* whether to prefix the point with the parameter - // - //**returns** - // - //* an array of points, prepended by the point param if required + public static function rationalBezierSurfaceRegularSample( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array { - public static function rationalCurveRegularSample( curve : NurbsCurveData, numSamples : Int, includeU : Bool ) : Array { - return rationalCurveRegularSampleRange( curve, curve.knots[0], curve.knots.last(), numSamples, includeU); - } + var pts = []; - //Sample a range of a NURBS curve at equally spaced parametric intervals - // - //**params** - // - //* NurbsCurveData object - //* start parameter for sampling - //* end parameter for sampling - //* integer number of samples - //* whether to prefix the point with the parameter - // - //**returns** - // - //* an dictionary of parameter - point pairs + // TODO dir is prob wrong + var u = surface.knotsU[0]; + var t = (surface.knotsU.last( ) - surface.knotsU[0]) / divsU; - public static function rationalCurveRegularSampleRange( curve : NurbsCurveData, start : Float, end : Float, - numSamples : Int, includeU : Bool) : Array { + for ( i in 0...divsU ) { + var iso = Make.surfaceIsocurve( surface, u, true ); + var v = (iso.knots.last( ) - iso.knots[0]) / divsV; + rationalBezierCurveRegularSamplePointsMutate( iso, pts, iso.knots[0], t, divsV, false ); + u += t; + } - if (numSamples < 1){ - numSamples = 2; - } + return pts; + } + + private static function northIndex( i, j, divs : Array> ) { + if ( i <= 0 ) return null; + return divs[ i - 1 ][ j ]; + } - var p = []; - var span : Float = (end - start) / (numSamples - 1); - var u : Float = 0; + private static function southIndex( i, j, divs : Array> ) { + if ( i >= divs.length - 1 ) return null; + return divs[ i + 1 ][j]; + } + + private static function eastIndex( i, j, divs : Array> ) { + if ( j >= divs[i].length - 1 ) return null; + return divs[ i ][j + 1]; + } - for (i in 0...numSamples){ + private static function westIndex( i, j, divs : Array> ) { + if ( j <= 0 ) return null; + return divs[ i ][j - 1]; + } - u = start + span * i; + public static function rationalSurfaceAdaptiveSample( surface : NurbsSurfaceData, tol : Float ) : MeshData { - if ( includeU ){ - p.push( [u].concat( Eval.rationalCurvePoint(curve, u) ) ); - } else { - p.push( Eval.rationalCurvePoint(curve, u) ); - } + // TODO check for planarity + // TODO cache bezier decomposition - } + // split into bezier patches + var beziers = Modify.decomposeSurfaceIntoBeziers( surface ); + + // get step lengths for patches + var stepLengths : Array>> = [] + , stepLengthRow; + + for ( bezierrow in beziers ) { + stepLengthRow = []; + stepLengths.push( stepLengthRow ); + + for ( bezier in bezierrow ) { + var ls = rationalBezierSurfaceStepLength( bezier, tol ); + + ls.item0 = Math.min(ls.item0, (bezier.knotsU.last() - bezier.knotsU.first()) / 2); + ls.item1 = Math.min(ls.item1, (bezier.knotsV.last() - bezier.knotsV.first()) / 2); + + stepLengthRow.push( ls ); + } + } + + var pts = [], + uvs = [], + edgeRow, n, s, e, w, + empty = new Pair(Math.POSITIVE_INFINITY, Math.POSITIVE_INFINITY), + beis : Array> = [], + beir : Array, + bei : BezierEdgeIndices, + e0 : Int, + e1 : Int, + srf; + + // tessellate the edges of the bezier patches + for (i in 0...beziers.length){ + + beir = []; + beis.push( beir ); + + for (j in 0...beziers[i].length){ + + srf = beziers[i][j]; + + // store the indices of the edge vertices in the pt array + + bei = new BezierEdgeIndices(); + beir.push(bei); + + // obtain the step lengths used to tessellate the south and east edge of the bezier + + s = southIndex( i, j, stepLengths ); + if (s == null) s = empty; + + e = eastIndex( i, j, stepLengths ); + if (e == null) e = empty; + + // if i = 0, tessellate the north edge using the stepLengths for this bezier + + if (i == 0){ + + var ne = Make.surfaceIsocurve( srf, srf.knotsU.first( ), false ); // uconstant + + e0 = pts.length; + + rationalBezierCurveRegularSamplePointsMutate2( ne, pts, stepLengths[i][j].item1 ); + + e1 = pts.length; + + regularUvsMutate( e1-e0, ne.knots.first(), stepLengths[i][j].item1, uvs, srf.knotsU.first( ), true ); + + bei.n = new Pair(e0, e1); + + } else { + bei.n = beis[i - 1][j].s; + } + + // if j = 0, tessellate the west edge using the stepLengths for this bezier + + if (j == 0) { + + e0 = pts.length; + + var we = Make.surfaceIsocurve( srf, srf.knotsV.first( ), true ); + rationalBezierCurveRegularSamplePointsMutate2( we, pts, stepLengths[i][j].item0 ); + + e1 = pts.length; + + regularUvsMutate( e1-e0, we.knots.first(), stepLengths[i][j].item0, uvs, srf.knotsV.first( ), false ); + + bei.w = new Pair(e0, e1); + + } else { + bei.w = beis[i][j-1].e; + } + + // tessellate the south edge and record vertex positions + + e0 = pts.length; + + var se = Make.surfaceIsocurve( srf, srf.knotsU.last( ), false ); + rationalBezierCurveRegularSamplePointsMutate2( se, pts, Math.min( s.item1, stepLengths[i][j].item1) ); + + e1 = pts.length; + + regularUvsMutate( e1-e0, se.knots.first(), Math.min( s.item1, stepLengths[i][j].item1), uvs, srf.knotsU.last( ), true ); + + bei.s = new Pair(e0, e1); + + // tessellate the east edge and record vertex positions + + e0 = pts.length; + + var ee = Make.surfaceIsocurve( srf, srf.knotsV.last( ), true ); + rationalBezierCurveRegularSamplePointsMutate2( ee, pts, Math.min( e.item0, stepLengths[i][j].item0) ); + + e1 = pts.length; + + regularUvsMutate( e1-e0, ee.knots.first(), Math.min( e.item0, stepLengths[i][j].item0), uvs, srf.knotsV.last( ), false ); + + bei.e = new Pair(e0, e1); + } + } + + // tessellate the patch interior and join to the polyline interiors together + var faces = [], p0; + + for ( i in 0...beziers.length ) { + for ( j in 0...beziers[i].length ) { + + // tessellate just the interior of the surface + + // keep track of the position in the pts array + + p0 = pts.length; + + var bezier = beziers[i][j]; + + var divsU = Math.ceil( 1.0 / stepLengths[i][j].item0 ); + + var domainV = bezier.knotsV.last( ) - bezier.knotsV[0]; + var domainU = bezier.knotsU.last( ) - bezier.knotsU[0]; + + var divsV = Math.ceil( 1.0 / stepLengths[i][j].item1 ); + + var tessStepV = domainV / divsV; + var tessStepU = domainU / divsU; + + var u = bezier.knotsU[0] + tessStepU; + + // evaluate all points on the interior of the face - return p; + for ( k in 0...divsU-1 ) { + var iso = Make.surfaceIsocurve( bezier, u, false ); + rationalBezierCurveRegularSamplePointsMutate( iso, pts, iso.knots[0] + tessStepV, tessStepV, divsV - 1, false ); + + regularUvsMutate( divsV - 1, iso.knots[0] + tessStepV, tessStepV, uvs, u, true ); + + u += tessStepU; + } + + // we don't include the start and end points of every row, so we must adjust these values here + + divsU = divsU - 2; + divsV = divsV - 2; + + // triangulate the interior of the face after having computed the points + + for ( k in 0...divsU ) { + for ( l in 0...divsV ) { + var a_k = p0 + k * (divsV + 1) + l, + b_k = p0 + (k + 1) * (divsV + 1) + l, + c_k = b_k + 1, + d_k = a_k + 1, + abc = [a_k, b_k, c_k], + acd = [a_k, c_k, d_k]; + + faces.push( abc ); + faces.push( acd ); + } + } + + // triangulate the edges, joining the interior pts with the edge pts + + bei = beis[i][j]; // we'll need the edge indices for completing this + + stitchMesh( bezier, faces, bei, divsU, divsV, domainV, p0, tessStepV, EdgeSide.North ); + stitchMesh( bezier, faces, bei, divsU, divsV, domainV, p0, tessStepV, EdgeSide.South ); + stitchMesh( bezier, faces, bei, divsU, divsV, domainU, p0, tessStepU, EdgeSide.East ); + stitchMesh( bezier, faces, bei, divsU, divsV, domainU, p0, tessStepU, EdgeSide.West ); + } + } + + return new MeshData( faces, pts, null, uvs ); + } + + private static function regularUvsMutate( count : Int, start : Float, step : Float, uvs : Array, constant : Float, uConstant : Bool ){ + var i = 0; + var u = start; + if (uConstant){ + while ( i < count ){ + uvs.push([constant, u]); + u += step; + i++; + } + } else { + while ( i < count ){ + uvs.push([u, constant]); + u += step; + i++; + } + } } + private static function stitchMesh( bezier : NurbsSurfaceData, faces : Array, bei : BezierEdgeIndices, + divsU : Int, divsV : Int, domain : Float, p0 : Int, tessStep : Float, edgeSide : EdgeSide ){ + + var edgeIndices; + var knots; + var reverseFace = false; + var tessIStep = 1; + var tessDivCount = 1; + + switch (edgeSide) { + case EdgeSide.North: + edgeIndices = bei.n; + knots = bezier.knotsV; + tessDivCount = divsV; + case EdgeSide.South: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV+1); + reverseFace = true; + tessDivCount = divsV; + case EdgeSide.East: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV+1; + p0 += divsV; + tessDivCount = divsU; + case EdgeSide.West: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV+1; + reverseFace = true; + tessDivCount = divsU; + } + + // how many indices in the north edge? + + var edgeCount = edgeIndices.item1 - edgeIndices.item0 - 1; + + // what is the north edge's step length + + var edgeStep = domain / edgeCount; + + var edgeU = knots.first(); + var tessU = knots.first() + (3/2) * tessStep; + + var edgeI = 0; + var tessI = 0; + + var tessDivI = 1; // number of division steps - not indexs into the mesh + + // triangulate the northwest corner + + while ( edgeI < edgeCount ){ + while ( edgeU < tessU && edgeI < edgeCount || (edgeI < edgeCount && tessDivI > tessDivCount) ){ + var ei = edgeIndices.item0 + edgeI, + ei2 = ei + 1; + + if (reverseFace){ + faces.push( [ ei, ei2, p0 + tessI ] ); + } else { + faces.push( [ ei, p0 + tessI, ei2 ] ); + } + + edgeI++; + edgeU += edgeStep; + } + + if (edgeI < edgeCount){ + var ei = edgeIndices.item0 + edgeI; + + if (reverseFace){ + faces.push( [ p0 + tessI, ei, p0 + tessI + tessIStep ] ); + } else { + faces.push( [ p0 + tessI, p0 + tessI + tessIStep, ei ] ); + } + } + + tessDivI++; + tessI += tessIStep; + tessU += tessStep; + } + } + + private static function rationalBezierCurveRegularSamplePointsMutate2( crv : NurbsCurveData, + pts : Array, + step : Float, + includeU : Bool = false ) : Void { + + var domain = crv.knots.last( ) - crv.knots[0]; + var steps = Math.ceil( 1.0 / step ); + var len = domain / steps; + + rationalBezierCurveRegularSamplePointsMutate( crv, pts, crv.knots[0], len, steps + 1, false ); + + } + + + + public static function rationalBezierSurfaceStepLength( surface : NurbsSurfaceData, tol : Float ) : Pair { + + // center the control pts at the origin + + var dehomo = Eval.dehomogenize2d( surface.controlPoints ); + + var bb = new BoundingBox(); + for ( row in dehomo ) { + bb.addRange( row ); + } + var avgPt = Vec.mul( 0.5, Vec.add( bb.min, bb.max ) ); + + // clone and translate all control pts + + var m = Mat.identity( 4 ); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; + + var ts = Modify.rationalSurfaceTransform( surface, m ); // todo util methods for translation + dehomo = Eval.dehomogenize2d( ts.controlPoints ); + + // compute r = max( || Pi || ) + + var r = 0.0, n; + for ( i in 0...dehomo.length ) { + for ( j in 0...dehomo[i].length ) { + n = Vec.norm( dehomo[i][j] ); + if ( n > r ) r = n; + } + } + + // compute Duu + + var duu = Math.NEGATIVE_INFINITY, iduu; + + for ( i in 0...surface.controlPoints.length - 2 ) { + for ( j in 0...surface.controlPoints[i].length ) { + + iduu = + Vec.norm( Vec.add( dehomo[i + 2][j], Vec.add( Vec.mul( -2.0, dehomo[i + 1][j] ), dehomo[i][j] ) ) ) - + (r - tol) * ( ts.controlPoints[i + 2][j].last( ) - 2 * ts.controlPoints[i + 1][j].last( ) + ts.controlPoints[i][j].last( )); + + if ( iduu > duu ) duu = iduu; + + } + } + + // compute Dvv + + var dvv = Math.NEGATIVE_INFINITY, idvv; + + for ( i in 0...surface.controlPoints.length ) { + for ( j in 0...surface.controlPoints[i].length - 2 ) { + + idvv = + Vec.norm( Vec.add( dehomo[i][j + 2], Vec.add( Vec.mul( -2.0, dehomo[i][j + 1] ), dehomo[i][j] ) ) ) - + (r - tol) * ( ts.controlPoints[i][j + 2].last( ) - 2 * ts.controlPoints[i][j + 1].last( ) + ts.controlPoints[i][j].last( )); + + if ( idvv > dvv ) dvv = idvv; + } + } + + // compute Duv + + var duv = Math.NEGATIVE_INFINITY, iduv; + + for ( i in 0...surface.controlPoints.length - 1 ) { + for ( j in 0...surface.controlPoints[i].length - 1 ) { + iduv = + Vec.norm( Vec.addAll( [ dehomo[i + 1][j + 1], + Vec.mul( -1.0, dehomo[i][j + 1] ), + Vec.mul( -1.0, dehomo[i + 1][j] ), + dehomo[i][j] ] ) ) - + (r - tol) * ( ts.controlPoints[i + 1][j + 1].last( ) - ts.controlPoints[i][j + 1].last( ) - ts.controlPoints[i + 1][j].last( ) + ts.controlPoints[i][j].last( )); + + if ( iduv > duv ) duv = iduv; + } + } + + duu *= surface.degreeU * (surface.degreeU - 1); + dvv *= surface.degreeV * (surface.degreeV - 1); + duv *= surface.degreeU * surface.degreeV; + + var minw = Math.POSITIVE_INFINITY; + var w; + + for ( i in 0...surface.controlPoints.length ) { + for ( j in 0...surface.controlPoints[i].length ) { + w = surface.controlPoints[i][j].last( ); + if ( w < minw ) minw = w; + } + } + + var stepu, stepv; + + if ( Math.abs( duu ) < Constants.TOLERANCE ) { + + stepu = 1.0; + + if ( Math.abs( dvv ) < Constants.TOLERANCE ) { + stepv = 1.0; + return new Pair( stepu, stepv ); + } + + stepv = ( Math.sqrt( duv * duv + 8 * dvv * tol * minw ) - duv ) / dvv; + } + + if ( Math.abs( dvv ) < Constants.TOLERANCE ) { + + stepv = 1.0; + stepu = ( Math.sqrt( duv * duv + 8 * duu * tol * minw ) - duv ) / duu; + + return new Pair( stepu, stepv ); + } + + var unum, vnum, denom; + + unum = 4 * dvv * tol * minw; + denom = duu * dvv + duv * Math.sqrt( duu * dvv ); + stepu = Math.sqrt( unum / denom ); + + vnum = 4 * duu * tol * minw; + stepv = Math.sqrt( vnum / denom ); + + return new Pair( stepu, stepv ); + } - //Sample a NURBS curve over its entire domain, corresponds to [this algorithm](http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf) - // + // Compute a regularly spaced sequence of points on a non-uniform, rational spline curve. Generally, this algorithm + // is much faster than computing these points directly. This algorithm is based on the forward difference algorithm + // presented in chapter 4 of + // [T. W. Sederberg, BYU, Computer Aided Geometric Design Course Notes](http://cagd.cs.byu.edu/~557/text/cagd.pdf) + // //**params** // - //* NurbsCurveData object - //* tol for the adaptive scheme - //* whether to prefix the point with the parameter - // + //* NurbsCurveData object representing the curve + //* number of divisions + // //**returns** // - //* an array of dim + 1 length where the first element is the param where it was sampled and the remaining the pt - - public static function rationalCurveAdaptiveSample( curve : NurbsCurveData, tol : Float = 1e-6, includeU : Bool = false ) : Array { - - //if degree is 1, just return the dehomogenized control points - if (curve.degree == 1){ - if ( !includeU ) { - return curve.controlPoints.map( Eval.dehomogenize ); - } else { - //the first element of each array is the parameter - return [ for (i in 0...curve.controlPoints.length) - [ curve.knots[i+1] ].concat( Eval.dehomogenize( curve.controlPoints[i] ) ) ]; - } - } + //* an array of (divs+1) points - return rationalCurveAdaptiveSampleRange( curve, curve.knots[0], curve.knots.last(), tol, includeU ); - } + public static function rationalCurveRegularSample( crv : NurbsCurveData, divs : Int, includeU : Bool = false ) : Array { + + //if degree is 1, just return the dehomogenized control points + if ( crv.degree == 1 ) { + var pts = []; + for ( i in 0...crv.controlPoints.length ) { + pts.push( Eval.dehomogenize( crv.controlPoints[i] ) ); + } + if ( includeU ) { + for ( i in 0...crv.controlPoints.length ) { + pts[i].push( crv.knots[i + 1] ); + } + } + return pts; + } + + var range = crv.knots.last( ) - crv.knots[0]; + var beziers = crv.knots.length == (crv.degree + 1) * 2 ? [ crv ] : Modify.decomposeCurveIntoBeziers( crv ); + var pts = []; + var brange, fraction; + + var currentU = crv.knots[0]; + var step = range / divs; + var brange, bsteps, nextU; + + for ( i in 0...beziers.length ) { + + brange = beziers[i].knots.last( ) - currentU; + bsteps = Math.ceil( brange / step ); + nextU = currentU + bsteps * step; + + if ( nextU > beziers[i].knots.last( ) + Constants.TOLERANCE ) { + nextU -= step; + bsteps--; + } + + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, currentU, step, bsteps + 1, includeU ); + + currentU = nextU + step; + } + + return pts; + } + + public static function rationalCurveAdaptiveSample( crv : NurbsCurveData, tol : Float, includeU : Bool = false ) : Array { + //if degree is 1, just return the dehomogenized control points + if ( crv.degree == 1 ) { + var pts = []; + for ( i in 0...crv.controlPoints.length ) { + pts.push( Eval.dehomogenize( crv.controlPoints[i] ) ); + } + if ( includeU ) { + for ( i in 0...crv.controlPoints.length ) { + pts[i].push( crv.knots[i + 1] ); + } + } + return pts; + } + + var beziers = crv.knots.length == (crv.degree + 1) * 2 ? [ crv ] : Modify.decomposeCurveIntoBeziers( crv ); + var pts = [], steps, domain, len; + + for ( i in 0...beziers.length ) { + + domain = beziers[i].knots.last( ) - beziers[i].knots[0]; + len = rationalBezierCurveStepLength( beziers[i], tol ); + steps = Math.ceil( domain / len ); + len = domain / steps; + + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, beziers[i].knots[0], len, steps + 1, includeU ); + + if ( i == beziers.length - 1 ) break; + pts.pop( ); + } + + return pts; + } + + private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, + pts : Array, + startU : Float, + step : Float, + numSteps : Int, + includeU : Bool = false ) : Void { - //Sample a NURBS curve at 3 points, facilitating adaptive sampling - // + var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; + + if ( numSteps <= crv.degree + 1 ) { + for ( i in 0...numSteps ) { + pts.push( Eval.rationalCurvePoint( crv, u ) ); + u += step; + } + return; + } + + // initialize forward differencing + + for ( i in 0...degree1 ) { + its.push( Eval.curvePoint( crv, u ) ); + u += step; + } + + // compute the differences + + var prev; + + for ( i in 1...degree1 ) { + its = []; + ts.push( its ); + prev = ts[i - 1]; + + for ( j in 1...prev.length ) { + its.push( Vec.sub( prev[j], prev[j - 1] ) ); + } + } + + // evaluate the intial points + + for ( pt in ts[0] ) { + pts.push( Eval.dehomogenize( pt ) ); + } + + // evaluate the rest of the points + + var front = [ for ( r in ts ) r.last( ) ], k; + var frlen2 = front.length - 2; + + for ( i in 0...numSteps - degree1 ) { + + // Rright = R + Rdown + + // compute the new forward difference front + + for ( j in 0...front.length - 1 ) { + k = frlen2 - j; // invert + Vec.addMutate( front[k], front[k + 1] ); + } + + // add the new pt + pts.push( Eval.dehomogenize( front[0] ) ); + } + + // add the parameters if required + + u = startU; + if ( includeU ) { + for ( pt in pts ) { + pt.push( u ); + u += step; + } + } + } + + //Compute the regular tessellation step length necessary to approximate a rational Bezier curve to the specified tolerance. + // //**params** // - //* NurbsCurveData object - //* start parameter for sampling - //* end parameter for sampling - //* whether to prefix the point with the parameter - // + //* NurbsCurveData object representing the curve + //* The desired tolerance - the resultant + // //**returns** // - //* an array of dim + 1 length where the first element is the param where it was sampled and the remaining the pt + //* The step length - domain / step length yields the number of steps to take within the curve - public static function rationalCurveAdaptiveSampleRange( curve : NurbsCurveData, start, end, tol, includeU ) : Array{ + public static function rationalBezierCurveStepLength( curve : NurbsCurveData, tol : Float ) : Float { - //sample curve at three pts - var p1 = Eval.rationalCurvePoint(curve, start), - p3 = Eval.rationalCurvePoint(curve, end), - t = 0.5 + 0.2 * Math.random(), - mid = start + (end - start) * t, - p2 = Eval.rationalCurvePoint(curve, mid); + // get average pt - //if the two end control points are coincident, the three point test will always return 0, let's split the curve - var diff = Vec.sub( p1, p3); - var diff2 = Vec.sub( p1, p2); + var dehomo = Eval.dehomogenize1d( curve.controlPoints ); - //the first condition checks if the curve makes up a loop, if so, we will need to continue evaluation - if ( ( Vec.dot( diff, diff ) < tol && Vec.dot( diff2, diff2 ) > tol ) || !Trig.threePointsAreFlat( p1, p2, p3, tol ) ) { + var bb = new BoundingBox( dehomo ); + var avgPt = Vec.mul( 0.5, Vec.add( bb.min, bb.max ) ); - //get the exact middle - var exact_mid = start + (end - start) * 0.5; + // clone and translate all control pts + var m = Mat.identity( 4 ); + m[0][3] = -avgPt[0]; + m[1][3] = -avgPt[1]; + m[2][3] = -avgPt[2]; - //recurse on the two halves - var left_pts = rationalCurveAdaptiveSampleRange( curve, start, exact_mid, tol, includeU ) - , right_pts = rationalCurveAdaptiveSampleRange( curve, exact_mid, end, tol, includeU ); + var tc = Modify.rationalCurveTransform( curve, m ); // todo util methods for translation + dehomo = Eval.dehomogenize1d( tc.controlPoints ); - //concatenate the two - return left_pts.slice(0, -1).concat(right_pts); + // compute r = max( || Pi || ) - } else { - if (includeU){ - return [ [ start ].concat(p1) , [end].concat(p3) ]; - } else { - return [ p1, p3 ]; - } - } - } + var r = 0.0, n; + for ( i in 0...dehomo.length ) { + n = Vec.norm( dehomo[i] ); + if ( n > r ) r = n; + } + + // compute w = min( wi ) + + var wts = Eval.weight1d( curve.controlPoints ); + var w = Vec.min( wts ); + var domain = curve.knots.last( ) - curve.knots[0]; + + if ( tol < r ) { + + var numer = 8 * w * tol; + + var ws = secondForwardDiff( wts ); + var pts = secondForwardDiff2( dehomo ); + var fs = [ for ( i in 0...pts.length ) Vec.norm( pts[i] ) + (r - tol) * ws[i]]; + var f = Vec.max( fs ); + var denom = curve.degree * (curve.degree - 1.0) * f; + + return domain * Math.sqrt( numer / denom ); + + } else if ( r >= tol && tol < 2.0 * r ) { - //Tessellate a NURBS surface on equal spaced intervals in the parametric domain - // + var numer = 8 * w * tol; + var pts = secondForwardDiff2( dehomo ); + var fs = [ for ( i in 0...pts.length ) Vec.norm( pts[i] )]; + var f = Vec.max( fs ); + var denom = curve.degree * (curve.degree - 1.0) * f; + + return domain * Math.sqrt( numer / denom ); + + } else { + return domain; + } + } + + private static function secondForwardDiff( array : Array ) { + var i = 0, res = []; + while ( i < array.length - 2 ) { + res.push( array[i + 2] - 2.0 * array[i + 1] + array[i] ); + i++; + } + + return res; + } + + private static function secondForwardDiff2( array : Array ) { + var i = 0, res = []; + while ( i < array.length - 2 ) { + res.push( Vec.add( array[i + 2], Vec.add( Vec.mul( -2.0, array[i + 1] ), array[i] ) ) ); + i++; + } + + return res; + } + + //Tessellate a NURBS surface on equal spaced intervals in the parametric domain + // //**params** // //* NurbsSurfaceData object - //* number of divisions in the u direction - //* number of divisions in the v direction - // + //* number of divisions in the u direction + //* number of divisions in the v direction + // //**returns** // //* MeshData object - public static function rationalSurfaceNaive( surface : NurbsSurfaceData, divs_u : Int, divs_v : Int ) : MeshData { + public static function rationalSurfaceNaive( surface : NurbsSurfaceData, divs_u : Int, divs_v : Int ) : MeshData { - if ( divs_u < 1 ) { divs_u = 1; } - if ( divs_v < 1 ) { divs_v = 1; } + if ( divs_u < 1 ) { divs_u = 1; } + if ( divs_v < 1 ) { divs_v = 1; } - var degreeU = surface.degreeU - , degreeV = surface.degreeV - , controlPoints = surface.controlPoints - , knotsU = surface.knotsU - , knotsV = surface.knotsV; + var degreeU = surface.degreeU + , degreeV = surface.degreeV + , controlPoints = surface.controlPoints + , knotsU = surface.knotsU + , knotsV = surface.knotsV; - var u_span = knotsU.last() - knotsU[0]; - var v_span = knotsV.last() - knotsV[0]; + var u_span = knotsU.last( ) - knotsU[0]; + var v_span = knotsV.last( ) - knotsV[0]; - var span_u = u_span / divs_u, - span_v = v_span / divs_v; + var span_u = u_span / divs_u, + span_v = v_span / divs_v; - var points = []; - var uvs = []; - var normals = []; + var points = []; + var uvs = []; + var normals = []; - for (i in 0...divs_u+1){ - for (j in 0...divs_v+1){ + for ( i in 0...divs_u + 1 ) { + for ( j in 0...divs_v + 1 ) { - var pt_u = i * span_u, - pt_v = j * span_v; + var pt_u = knotsU[0] + i * span_u, + pt_v = knotsV[0] + j * span_v; - uvs.push( [pt_u, pt_v] ); + uvs.push( [pt_u, pt_v] ); - var derivs = Eval.rationalSurfaceDerivatives( surface, pt_u, pt_v, 1 ); - var pt = derivs[0][0]; + var derivs = Eval.rationalSurfaceDerivatives( surface, pt_u, pt_v, 1 ); + var pt = derivs[0][0]; - points.push( pt ); + points.push( pt ); - var normal = Vec.normalized( Vec.cross( derivs[1][0], derivs[0][1] ) ); - normals.push( normal ); - } - } + var normal = Vec.normalized( Vec.cross( derivs[1][0], derivs[0][1] ) ); + normals.push( normal ); + } + } - var faces = []; + var faces = []; - for (i in 0...divs_u){ - for (j in 0...divs_v){ - var a_i = i * (divs_v + 1) + j, - b_i = (i + 1) * (divs_v + 1) + j, - c_i = b_i + 1, - d_i = a_i + 1, - abc = [a_i, b_i, c_i], - acd = [a_i, c_i, d_i]; + for ( i in 0...divs_u ) { + for ( j in 0...divs_v ) { + var a_i = i * (divs_v + 1) + j, + b_i = (i + 1) * (divs_v + 1) + j, + c_i = b_i + 1, + d_i = a_i + 1, + abc = [a_i, b_i, c_i], + acd = [a_i, c_i, d_i]; - faces.push(abc); - faces.push(acd); - } - } + faces.push( abc ); + faces.push( acd ); + } + } - return new MeshData( faces, points, normals, uvs ); + return new MeshData( faces, points, normals, uvs ); - } + } - //Divide a NURBS surface int equal spaced intervals in the parametric domain as AdaptiveRefinementNodes - // + //Divide a NURBS surface int equal spaced intervals in the parametric domain as AdaptiveRefinementNodes + // //**params** // //* NurbsSurfaceData object - //* SurfaceDivideOptions object - // + //* SurfaceDivideOptions object + // //**returns** // //* MeshData object - public static function divideRationalSurfaceAdaptive( surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null ): Array { + public static function divideRationalSurfaceAdaptive( surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null ) : Array { - if (options == null) options = new AdaptiveRefinementOptions(); + if ( options == null ) options = new AdaptiveRefinementOptions(); - #if (!cs && !cpp && !java) - options.minDivsU = options.minDivsU != null ? options.minDivsU : 1; - options.minDivsU = options.minDivsV != null ? options.minDivsV : 1; - options.refine = options.refine != null ? options.refine : true; + #if (!cs && !cpp && !java) + options.minDivsU = options.minDivsU != null ? options.minDivsU : 1; + options.minDivsU = options.minDivsV != null ? options.minDivsV : 1; + options.refine = options.refine != null ? options.refine : true; #end - var minU = (surface.controlPoints.length - 1) * 2; - var minV = (surface.controlPoints[0].length - 1) * 2; + var minU = (surface.controlPoints.length - 1) * 2; + var minV = (surface.controlPoints[0].length - 1) * 2; - var divsU = options.minDivsU = options.minDivsU > minU ? options.minDivsU : minU; - var divsV = options.minDivsV = options.minDivsV > minV ? options.minDivsV : minV; + var divsU = options.minDivsU = options.minDivsU > minU ? options.minDivsU : minU; + var divsV = options.minDivsV = options.minDivsV > minV ? options.minDivsV : minV; - //get necessary intervals - var umax = surface.knotsU.last(); - var umin = surface.knotsU[0]; - var vmax = surface.knotsV.last(); - var vmin = surface.knotsV[0]; + //get necessary intervals + var umax = surface.knotsU.last( ); + var umin = surface.knotsU[0]; + var vmax = surface.knotsV.last( ); + var vmin = surface.knotsV[0]; - var du = (umax - umin) / divsU - , dv = (vmax - vmin) / divsV; + var du = (umax - umin) / divsU + , dv = (vmax - vmin) / divsV; - var divs = []; - var pts = []; + var divs = []; + var pts = []; - // 1) evaluate all of the corners - for( i in 0...divsV + 1){ - var ptrow = []; - for (j in 0...divsU + 1){ + // 1) evaluate all of the corners + for ( i in 0...divsV + 1 ) { + var ptrow = []; + for ( j in 0...divsU + 1 ) { - var u = umin + du * j - , v = vmin + dv * i; + var u = umin + du * j + , v = vmin + dv * i; - //todo: make this faster by specifying n,m - var ds = Eval.rationalSurfaceDerivatives( surface, u, v, 1 ); + //todo: make this faster by specifying n,m + var ds = Eval.rationalSurfaceDerivatives( surface, u, v, 1 ); - var norm = Vec.normalized( Vec.cross( ds[0][1], ds[1][0] ) ); - ptrow.push( new SurfacePoint( ds[0][0], norm, [u,v], -1, Vec.isZero( norm ) ) ); - } - pts.push( ptrow ); - } + var norm = Vec.normalized( Vec.cross( ds[0][1], ds[1][0] ) ); + ptrow.push( new SurfacePoint( ds[0][0], norm, [u, v], -1, Vec.isZero( norm ) ) ); + } + pts.push( ptrow ); + } - // 2) make all of the nodes - for (i in 0...divsV){ - for (j in 0...divsU){ - var corners = [ pts[divsV - i - 1][j], - pts[divsV - i - 1][j+1], - pts[divsV - i][j+1], - pts[divsV - i][j] ]; + // 2) make all of the nodes + for ( i in 0...divsV ) { + for ( j in 0...divsU ) { + var corners = [ pts[divsV - i - 1][j], + pts[divsV - i - 1][j + 1], + pts[divsV - i][j + 1], + pts[divsV - i][j] ]; - divs.push( new AdaptiveRefinementNode( surface, corners ) ); - } - } + divs.push( new AdaptiveRefinementNode( surface, corners ) ); + } + } - if (!options.refine) return divs; + if ( !options.refine ) return divs; - // 3) assign all of the neighbors and divide - for (i in 0...divsV){ - for (j in 0...divsU){ + // 3) assign all of the neighbors and divide + for ( i in 0...divsV ) { + for ( j in 0...divsU ) { - var ci = i * divsU + j - , n = north( ci, i, j, divsU, divsV, divs ) - , e = east( ci, i, j, divsU, divsV, divs ) - , s = south( ci, i, j, divsU, divsV, divs ) - , w = west( ci, i, j, divsU, divsV, divs ); + var ci = i * divsU + j + , n = north( ci, i, j, divsU, divsV, divs ) + , e = east( ci, i, j, divsU, divsV, divs ) + , s = south( ci, i, j, divsU, divsV, divs ) + , w = west( ci, i, j, divsU, divsV, divs ); - divs[ci].neighbors = [ s, e, n, w ]; - divs[ci].divide( options ); - } - } + divs[ci].neighbors = [ s, e, n, w ]; + divs[ci].divide( options ); + } + } - return divs; - } + return divs; + } - private static function north(index, i, j, divsU, divsV, divs){ - if (i == 0) return null; - return divs[ index - divsU ]; - } - - private static function south(index, i, j, divsU, divsV, divs){ - if (i == divsV - 1) return null; - return divs[ index + divsU ]; - } - - private static function east(index, i, j, divsU, divsV, divs){ - if (j == divsU - 1) return null; - return divs[ index + 1 ]; - } - - private static function west(index, i, j, divsU, divsV, divs){ - if (j == 0) return null; - return divs[ index - 1 ]; - } + private static function north( index, i, j, divsU, divsV, divs ) { + if ( i == 0 ) return null; + return divs[ index - divsU ]; + } - private static function triangulateAdaptiveRefinementNodeTree( arrTree : Array ) : MeshData { + private static function south( index, i, j, divsU, divsV, divs ) { + if ( i == divsV - 1 ) return null; + return divs[ index + divsU ]; + } - //triangulate all of the nodes of the tree - var mesh = MeshData.empty(); - for (x in arrTree) x.triangulate( mesh ); - return mesh; + private static function east( index, i, j, divsU, divsV, divs ) { + if ( j == divsU - 1 ) return null; + return divs[ index + 1 ]; + } - } + private static function west( index, i, j, divsU, divsV, divs ) { + if ( j == 0 ) return null; + return divs[ index - 1 ]; + } - public static function rationalSurfaceAdaptive( surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null ) : MeshData { + private static function triangulateAdaptiveRefinementNodeTree( arrTree : Array ) : MeshData { - options = options != null ? options : new AdaptiveRefinementOptions(); + //triangulate all of the nodes of the tree + var mesh = MeshData.empty( ); + for ( x in arrTree ) x.triangulate( mesh ); + return mesh; - //adaptive divide - var arrTrees = divideRationalSurfaceAdaptive( surface, options ); + } - //triangulation - return triangulateAdaptiveRefinementNodeTree( arrTrees ); - } + public static function rationalSurfaceAdaptive( surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null ) : MeshData { + + options = options != null ? options : new AdaptiveRefinementOptions(); + + //adaptive divide + var arrTrees = divideRationalSurfaceAdaptive( surface, options ); + + //triangulation + return triangulateAdaptiveRefinementNodeTree( arrTrees ); + } + + // Compute a regularly spaced grid of points on a non-uniform, rational, B spline surface. Generally, this algorithm + // is faster than directly evaluating these as we can pre-compute all of the basis function arrays + // + //**params** + // + //* NurbsSurfaceData object representing the surface + //* number of divisions in the U direction + //* number of divisions in the V direction + // + //**returns** + // + //* a 2d array of dimension (divsU+1, divsV+1) of points + + public static function rationalSurfaceRegularSample( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + return Eval.dehomogenize2d( surfaceRegularSample( surface, divsU, divsV ) ); + } + + // Compute a regularly spaced grid of points on a non-uniform, non-rational, B spline surface. Generally, this algorithm + // is faster than directly evaluating these as we can pre-compute all of the basis function arrays + // + //**params** + // + //* NurbsSurfaceData object representing the surface + //* number of divisions in the U direction + //* number of divisions in the V direction + // + //**returns** + // + //* a 2d array of dimension (divsU+1, divsV+1) of points + + public static function surfaceRegularSample( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + + var degreeU = surface.degreeU + , degreeV = surface.degreeV + , controlPoints = surface.controlPoints + , knotsU = surface.knotsU + , knotsV = surface.knotsV; + + var dim = controlPoints[0][0].length + , spanU = (knotsU.last( ) - knotsU[0]) / divsU + , spanV = (knotsV.last( ) - knotsV[0]) / divsV + , knotSpansBasesU = Eval.regularlySpacedBasisFunctions( degreeU, knotsU, divsU ) + , knotSpansU = knotSpansBasesU.item0 + , basesU = knotSpansBasesU.item1 + , knotSpansBasesV = Eval.regularlySpacedBasisFunctions( degreeV, knotsV, divsV ) + , knotSpansV = knotSpansBasesV.item0 + , basesV = knotSpansBasesV.item1 + , pts = [] + , divsU1 = divsU + 1 + , divsV1 = divsV + 1; + + for ( i in 0...divsU1 ) { + var ptsi = []; + pts.push( ptsi ); + + for ( j in 0...divsV1 ) { + ptsi.push( Eval.surfacePointGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim ) ); + } + } + + return pts; + } + + public static function surfaceRegularSample2( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + + var pts = []; + + // TODO dir is prob wrong + var u = surface.knotsU[0]; + var t = (surface.knotsU.last( ) - surface.knotsU[0]) / divsU; + + for ( i in 0...divsU ) { + var iso = Make.surfaceIsocurve( surface, u, true ); + pts.push( rationalCurveRegularSample( iso, divsV ) ); + u += t; + } + return pts; + } } @:expose("core.AdaptiveRefinementOptions") @@ -363,7 +1071,7 @@ class AdaptiveRefinementOptions { public var minDivsU : Int = 1; public var minDivsV : Int = 1; - public function new(){} + public function new( ) {} } @@ -415,40 +1123,40 @@ class AdaptiveRefinementNode { this.corners = corners; //if no corners, we need to construct initial corners from the surface - if (this.corners == null){ + if ( this.corners == null ) { var u0 : Float = srf.knotsU[0]; - var u1 : Float = srf.knotsU.last(); + var u1 : Float = srf.knotsU.last( ); var v0 : Float = srf.knotsV[0]; - var v1 : Float = srf.knotsV.last(); + var v1 : Float = srf.knotsV.last( ); this.corners = [ - SurfacePoint.fromUv( u0, v0 ), - SurfacePoint.fromUv( u1, v0 ), - SurfacePoint.fromUv( u1, v1 ), - SurfacePoint.fromUv( u0, v1 ) ]; + SurfacePoint.fromUv( u0, v0 ), + SurfacePoint.fromUv( u1, v0 ), + SurfacePoint.fromUv( u1, v1 ), + SurfacePoint.fromUv( u0, v1 ) ]; } } - public function isLeaf(){ + public function isLeaf( ) { return this.children == null; } - public function center(){ + public function center( ) { return this.centerPoint != null ? this.centerPoint : this.evalSrf( this.u05, this.v05 ); } - public function evalCorners(){ + public function evalCorners( ) { -//eval the center + //eval the center this.u05 = (this.corners[0].uv[0] + this.corners[2].uv[0]) / 2; this.v05 = (this.corners[0].uv[1] + this.corners[2].uv[1]) / 2; -//eval all of the corners - for (i in 0...4) { -//if it's not already evaluated - if ( this.corners[i].point == null ){ -//evaluate it + //eval all of the corners + for ( i in 0...4 ) { + //if it's not already evaluated + if ( this.corners[i].point == null ) { + //evaluate it var c = this.corners[i]; this.evalSrf( c.uv[0], c.uv[1], c ); } @@ -459,27 +1167,27 @@ class AdaptiveRefinementNode { var derivs = Eval.rationalSurfaceDerivatives( this.srf, u, v, 1 ); var pt = derivs[0][0]; - var norm = Vec.cross( derivs[0][1], derivs[1][0] ); + var norm = Vec.cross( derivs[0][1], derivs[1][0] ); var degen = Vec.isZero( norm ); - if (!degen) norm = Vec.normalized( norm ); + if ( !degen ) norm = Vec.normalized( norm ); - if (srfPt != null){ + if ( srfPt != null ) { srfPt.degen = degen; srfPt.point = pt; srfPt.normal = norm; return srfPt; } else { - return new SurfacePoint( pt, norm, [u,v], -1, degen ); + return new SurfacePoint( pt, norm, [u, v], -1, degen ); } } public function getEdgeCorners( edgeIndex : Int ) : Array { -//if its a leaf, there are no children to obtain uvs from - if ( this.isLeaf() ) return [ this.corners[ edgeIndex ] ]; + //if its a leaf, there are no children to obtain uvs from + if ( this.isLeaf( ) ) return [ this.corners[ edgeIndex ] ]; - if ( this.horizontal ){ + if ( this.horizontal ) { switch (edgeIndex){ case 0: @@ -494,7 +1202,7 @@ class AdaptiveRefinementNode { } -//vertical case + //vertical case switch (edgeIndex) { case 0: return this.children[0].getEdgeCorners( 0 ).concat( this.children[1].getEdgeCorners( 0 ) ); @@ -517,7 +1225,7 @@ class AdaptiveRefinementNode { return baseArr; } -//get opposite edges uvs + //get opposite edges uvs var corners = this.neighbors[edgeIndex].getEdgeCorners( ( edgeIndex + 2 ) % 4 ); var funcIndex = edgeIndex % 2; @@ -525,23 +1233,23 @@ class AdaptiveRefinementNode { var e = verb.core.Constants.EPSILON; var that = this; -//range clipping functions + //range clipping functions var rangeFuncMap = [ - function(c){ return c.uv[0] > that.corners[0].uv[0] + e && c.uv[0] < that.corners[2].uv[0] - e; }, - function(c){ return c.uv[1] > that.corners[0].uv[1] + e && c.uv[1] < that.corners[2].uv[1] - e; } + function( c ) { return c.uv[0] > that.corners[0].uv[0] + e && c.uv[0] < that.corners[2].uv[0] - e; }, + function( c ) { return c.uv[1] > that.corners[0].uv[1] + e && c.uv[1] < that.corners[2].uv[1] - e; } ]; -//clip the range of uvs to match this one + //clip the range of uvs to match this one var cornercopy = corners.filter( rangeFuncMap[ funcIndex ] ); - cornercopy.reverse(); + cornercopy.reverse( ); return baseArr.concat( cornercopy ); } - public function midpoint( index ){ + public function midpoint( index ) { - if (this.midPoints == null) this.midPoints = [null, null, null, null]; - if (!(this.midPoints[index] == null)) return this.midPoints[index]; + if ( this.midPoints == null ) this.midPoints = [null, null, null, null]; + if ( !(this.midPoints[index] == null) ) return this.midPoints[index]; switch (index){ case 0: @@ -558,35 +1266,35 @@ class AdaptiveRefinementNode { } - public function hasBadNormals() : Bool { + public function hasBadNormals( ) : Bool { return this.corners[0].degen || this.corners[1].degen || this.corners[2].degen || this.corners[3].degen; } - public function fixNormals() : Void { + public function fixNormals( ) : Void { var l = this.corners.length; - for (i in 0...l){ + for ( i in 0...l ) { var corn = this.corners[i]; - if (this.corners[i].degen) { -//get neighbors + if ( this.corners[i].degen ) { + //get neighbors var v1 = this.corners[(i + 1) % l]; var v2 = this.corners[(i + 3) % l]; -//correct the normal + //correct the normal this.corners[i].normal = v1.degen ? v2.normal : v1.normal; } } } - public function shouldDivide( options : AdaptiveRefinementOptions, currentDepth : Int ){ + public function shouldDivide( options : AdaptiveRefinementOptions, currentDepth : Int ) { if ( currentDepth < options.minDepth ) return true; if ( currentDepth >= options.maxDepth ) return false; - if ( this.hasBadNormals() ) { - this.fixNormals(); -//don't divide any further when encountering a degenerate normal + if ( this.hasBadNormals( ) ) { + this.fixNormals( ); + //don't divide any further when encountering a degenerate normal return false; } @@ -598,7 +1306,7 @@ class AdaptiveRefinementNode { if ( this.splitVert || this.splitHoriz ) return true; - var center = this.center(); + var center = this.center( ); return Vec.normSquared( Vec.sub( center.normal, this.corners[0].normal ) ) > options.normTol || Vec.normSquared( Vec.sub( center.normal, this.corners[1].normal ) ) > options.normTol || @@ -607,60 +1315,60 @@ class AdaptiveRefinementNode { } public function divide( options : AdaptiveRefinementOptions = null ) : Void { - if (options == null) options = new AdaptiveRefinementOptions(); -#if (!cpp && !cs && !java) - if (options.normTol == null) options.normTol = 8.5e-2; - if (options.minDepth == null) options.minDepth = 0; - if (options.maxDepth == null) options.maxDepth = 10; -#end + if ( options == null ) options = new AdaptiveRefinementOptions(); + #if (!cpp && !cs && !java) + if ( options.normTol == null ) options.normTol = 8.5e-2; + if ( options.minDepth == null ) options.minDepth = 0; + if ( options.maxDepth == null ) options.maxDepth = 10; + #end this._divide( options, 0, true ); } private function _divide( options : AdaptiveRefinementOptions, currentDepth : Int, horiz : Bool ) : Void { - this.evalCorners(); + this.evalCorners( ); - if ( !this.shouldDivide( options, currentDepth ) ) return; + if ( !this.shouldDivide( options, currentDepth ) ) return; currentDepth++; -//is the quad flat in one dir and curved in the other? - if (this.splitVert && !this.splitHoriz) { + //is the quad flat in one dir and curved in the other? + if ( this.splitVert && !this.splitHoriz ) { horiz = false; - } else if (!this.splitVert && this.splitHoriz){ + } else if ( !this.splitVert && this.splitHoriz ) { horiz = true; } this.horizontal = horiz; - if (this.horizontal){ + if ( this.horizontal ) { - var bott = [ this.corners[0], this.corners[1], this.midpoint(1), this.midpoint(3) ]; - var top = [ this.midpoint(3), this.midpoint(1), this.corners[2], this.corners[3] ]; + var bott = [ this.corners[0], this.corners[1], this.midpoint( 1 ), this.midpoint( 3 ) ]; + var top = [ this.midpoint( 3 ), this.midpoint( 1 ), this.corners[2], this.corners[3] ]; this.children = [ new AdaptiveRefinementNode( this.srf, bott ), new AdaptiveRefinementNode( this.srf, top ) ]; -//assign neighbors to bottom node + //assign neighbors to bottom node this.children[0].neighbors = [ this.neighbors[0], this.neighbors[1], this.children[1], this.neighbors[3] ]; -//assign neighbors to top node + //assign neighbors to top node this.children[1].neighbors = [ this.children[0], this.neighbors[1], this.neighbors[2], this.neighbors[3] ]; } else { - var left = [ this.corners[0], this.midpoint(0), this.midpoint(2), this.corners[3] ]; - var right = [ this.midpoint(0), this.corners[1], this.corners[2], this.midpoint(2) ]; + var left = [ this.corners[0], this.midpoint( 0 ), this.midpoint( 2 ), this.corners[3] ]; + var right = [ this.midpoint( 0 ), this.corners[1], this.corners[2], this.midpoint( 2 ) ]; - this.children = [ new AdaptiveRefinementNode( this.srf, left ), new AdaptiveRefinementNode( this.srf, right ) ]; + this.children = [ new AdaptiveRefinementNode( this.srf, left ), new AdaptiveRefinementNode( this.srf, right ) ]; this.children[0].neighbors = [ this.neighbors[0], this.children[1], this.neighbors[2], this.neighbors[3] ]; this.children[1].neighbors = [ this.neighbors[0], this.neighbors[1], this.neighbors[2], this.children[0] ]; } -//divide all children recursively - for (child in this.children){ + //divide all children recursively + for ( child in this.children ) { child._divide( options, currentDepth, !horiz ); } @@ -668,44 +1376,44 @@ class AdaptiveRefinementNode { public function triangulate( mesh : MeshData = null ) : MeshData { - if (mesh == null) mesh = MeshData.empty(); + if ( mesh == null ) mesh = MeshData.empty( ); - if ( this.isLeaf() ) return this.triangulateLeaf( mesh ); + if ( this.isLeaf( ) ) return this.triangulateLeaf( mesh ); -//recurse on the children - for (x in this.children){ - if (x == null) break; + //recurse on the children + for ( x in this.children ) { + if ( x == null ) break; x.triangulate( mesh ); } return mesh; } - public function triangulateLeaf( mesh : MeshData ) : MeshData{ + public function triangulateLeaf( mesh : MeshData ) : MeshData { var baseIndex = mesh.points.length , uvs = [] , ids = [] , splitid = 0; -//enumerate all uvs in counter clockwise direction - for (i in 0...4){ + //enumerate all uvs in counter clockwise direction + for ( i in 0...4 ) { - var edgeCorners = this.getAllCorners(i); + var edgeCorners = this.getAllCorners( i ); -//this is the vertex that is split - if (edgeCorners.length == 2 ) splitid = i + 1; + //this is the vertex that is split + if ( edgeCorners.length == 2 ) splitid = i + 1; - for (j in 0...edgeCorners.length) { - uvs.push(edgeCorners[j]); + for ( j in 0...edgeCorners.length ) { + uvs.push( edgeCorners[j] ); } } - for (corner in uvs){ + for ( corner in uvs ) { -//if the id is defined, we can just push it and continue - if (corner.id != -1){ - ids.push(corner.id); + //if the id is defined, we can just push it and continue + if ( corner.id != -1 ) { + ids.push( corner.id ); continue; } @@ -719,45 +1427,45 @@ class AdaptiveRefinementNode { baseIndex++; } - if (uvs.length == 4){ + if ( uvs.length == 4 ) { -//if the number of points is 4, we're just doing a -//rectangle - just build the basic triangulated square + //if the number of points is 4, we're just doing a + //rectangle - just build the basic triangulated square mesh.faces.push( [ ids[0], ids[3], ids[1] ] ); mesh.faces.push( [ ids[3], ids[2], ids[1] ] ); -//all done + //all done return mesh; - } else if (uvs.length == 5){ + } else if ( uvs.length == 5 ) { -//use the splitcorner to triangulate + //use the splitcorner to triangulate var il = ids.length; -//there will be 3 triangles + //there will be 3 triangles mesh.faces.push( [ ids[ splitid ], ids[ (splitid + 2) % il ], ids[ (splitid + 1) % il ] ] ); - mesh.faces.push( [ ids[ (splitid + 4) % il ], ids[ (splitid + 3) % il ], ids[ splitid ] ] ); - mesh.faces.push( [ ids[ splitid ], ids[ (splitid + 3) % il ],ids[ (splitid + 2) % il ] ]); + mesh.faces.push( [ ids[ (splitid + 4) % il ], ids[ (splitid + 3) % il ], ids[ splitid ] ] ); + mesh.faces.push( [ ids[ splitid ], ids[ (splitid + 3) % il ], ids[ (splitid + 2) % il ] ] ); return mesh; } -//make point at center of face - var center = this.center(); + //make point at center of face + var center = this.center( ); mesh.uvs.push( center.uv ); mesh.points.push( center.point ); mesh.normals.push( center.normal ); -//get index + //get index var centerIndex = mesh.points.length - 1; -//build triangle fan from center + //build triangle fan from center var i = 0; var j = uvs.length - 1; - while (i < uvs.length){ - mesh.faces.push( [ centerIndex, ids[i], ids[j] ]); + while ( i < uvs.length ) { + mesh.faces.push( [ centerIndex, ids[i], ids[j] ] ); j = i++; } @@ -765,3 +1473,5 @@ class AdaptiveRefinementNode { } } + + diff --git a/src/verb/exe/Dispatcher.hx b/src/verb/exe/Dispatcher.hx index 8ae053c7..3cd19d79 100644 --- a/src/verb/exe/Dispatcher.hx +++ b/src/verb/exe/Dispatcher.hx @@ -1,9 +1,9 @@ package verb.exe; #if js - import verb.exe.WorkerPool; +import verb.exe.WorkerPool; #else - import verb.exe.ThreadPool; +import verb.exe.ThreadPool; #end import promhx.Deferred; @@ -15,21 +15,21 @@ class Dispatcher { public static var THREADS : Int = 1; #if js - private static var _workerPool : WorkerPool; + private static var _workerPool : WorkerPool; #else - private static var _threadPool : ThreadPool; + private static var _threadPool : ThreadPool; #end private static var _init : Bool = false; - private static function init() : Void { + private static function init( ) : Void { - if (_init) return; + if ( _init ) return; #if js - _workerPool = new WorkerPool( THREADS ); + _workerPool = new WorkerPool( THREADS ); #else - _threadPool = new ThreadPool( THREADS ); + _threadPool = new ThreadPool( THREADS ); #end _init = true; @@ -37,18 +37,18 @@ class Dispatcher { public static function dispatchMethod( classType : Class, methodName : String, args : Array ) : Promise { - init(); + init( ); var def = new Deferred(); - var callback = function(x){ + var callback = function( x ) { def.resolve( x ); }; #if js - _workerPool.addWork( Type.getClassName( classType ), methodName, args, callback ); + _workerPool.addWork( Type.getClassName( classType ), methodName, args, callback ); #else - _threadPool.addTask(function(_ : Dynamic){ var r : Dynamic = Reflect.callMethod(classType, Reflect.field(classType, methodName), args ); return r; }, null, callback); + _threadPool.addTask( function( _ : Dynamic ) { var r : Dynamic = Reflect.callMethod( classType, Reflect.field( classType, methodName ), args ); return r; }, null, callback ); #end return new Promise( def ); diff --git a/src/verb/exe/ThreadPool.hx b/src/verb/exe/ThreadPool.hx index 69f78e85..5a8093d5 100644 --- a/src/verb/exe/ThreadPool.hx +++ b/src/verb/exe/ThreadPool.hx @@ -1,179 +1,171 @@ package verb.exe; #if neko - import neko.vm.Thread; - import neko.vm.Mutex; +import neko.vm.Thread; +import neko.vm.Mutex; #elseif cpp - import cpp.vm.Thread; - import cpp.vm.Mutex; +import cpp.vm.Thread; +import cpp.vm.Mutex; #end #if (neko || cpp) - private class PoolThread - { - private var thread:Thread; - private var task:Dynamic->Dynamic; - private var mutex:Mutex; - public var started:Bool; - private var _done:Bool; - public var done(get, never):Bool; - private function get_done():Bool - { - mutex.acquire(); - var d:Bool = _done; - mutex.release(); - return d; - } - private var _result:Dynamic; - public var result(get, never):Dynamic; - private function get_result():Dynamic - { - mutex.acquire(); - var r:Dynamic = _result; - mutex.release(); - return r; - } - - public function new() - { - mutex = new Mutex(); - } - - public function start(task:Dynamic->Dynamic, arg:Dynamic):Void - { - this.task = task; - started = true; - _done = false; - thread = Thread.create(doWork); - thread.sendMessage(arg); - } - - private function doWork():Void - { - var arg:Dynamic = Thread.readMessage(true); - var ret:Dynamic = task(arg); - mutex.acquire(); - _result = ret; - _done = true; - mutex.release(); - } - } +private class PoolThread { + private var thread : Thread; + private var task : Dynamic -> Dynamic; + private var mutex : Mutex; + public var started : Bool; + private var _done : Bool; + public var done(get, never) : Bool; + + private function get_done( ) : Bool { + mutex.acquire( ); + var d : Bool = _done; + mutex.release( ); + return d; + } + private var _result : Dynamic; + public var result(get, never) : Dynamic; + + private function get_result( ) : Dynamic { + mutex.acquire( ); + var r : Dynamic = _result; + mutex.release( ); + return r; + } + + public function new( ) { + mutex = new Mutex(); + } + + public function start( task : Dynamic -> Dynamic, arg : Dynamic ) : Void { + this.task = task; + started = true; + _done = false; + thread = Thread.create( doWork ); + thread.sendMessage( arg ); + } + + private function doWork( ) : Void { + var arg : Dynamic = Thread.readMessage( true ); + var ret : Dynamic = task( arg ); + mutex.acquire( ); + _result = ret; + _done = true; + mutex.release( ); + } +} #end private typedef Task = { - var id:Int; - var task:Dynamic->Dynamic; - var done:Bool; - var arg:Dynamic; + var id : Int; + var task : Dynamic -> Dynamic; + var done : Bool; + var arg : Dynamic; #if (neko || cpp) - var thread:PoolThread; - #end - var onFinish:Dynamic->Void; + var thread : PoolThread; + #end + var onFinish : Dynamic -> Void; } /** * ... * @author Kenton Hamaluik */ -class ThreadPool -{ +class ThreadPool { #if (neko || cpp) - private var numThreads:Int = 1; - private var threads:Array; - #end - private var tasks:Array; - private var nextID:Int = 0; - - public function new(numThreads:Int) - { + private var numThreads : Int = 1; + private var threads : Array; + #end + private var tasks : Array; + private var nextID : Int = 0; + + public function new( numThreads : Int ) { tasks = new Array (); #if (neko || cpp) - this.numThreads = numThreads; - threads = new Array(); - for (i in 0...this.numThreads) - { - threads.push(new PoolThread()); - } - #end + this.numThreads = numThreads; + threads = new Array(); + for ( i in 0...this.numThreads ) { + threads.push( new PoolThread() ); + } + #end } - public function addTask(task:Dynamic->Dynamic, arg:Dynamic, onFinish:Dynamic->Void):Void - { + public function addTask( task : Dynamic -> Dynamic, arg : Dynamic, onFinish : Dynamic -> Void ) : Void { tasks.push( { id: nextID, task: task, done: false, arg: arg, #if (neko || cpp) thread: null, #end onFinish: onFinish } ); - nextID++; - } + nextID++; + } - #if (neko || cpp) - private function allTasksAreDone():Bool - { - for (task in tasks) - if (!task.done) - return false; - return true; - } - - private function getNextFreeThread():PoolThread - { - for (thread in threads) - if (!thread.started) - return thread; - return null; - } - #end - - public function blockRunAllTasks():Void - { - #if (neko || cpp) - while (!allTasksAreDone()) - { - //get a free thread - var thread:PoolThread = getNextFreeThread(); - //but if it doesn't exist, try again - if (thread == null) - continue; - - for (task in tasks) - { - //skip any tasks that are done - if (task.done) - continue; - - //if this task is currently being run, see if it's done yet - if (task.thread != null && task.thread.started) - { - if (task.thread.done) - { - //yay, it finished! - task.done = true; - //reset the thread - task.thread.started = false; - //call the on finish function - if (task.onFinish != null) - task.onFinish(task.thread.result); - } - continue; - } - - //ok, we have a task that needs running - //and a thread to run it - //combine forces! - task.thread = thread; - thread.start(task.task, task.arg); - - //break to try to assign the next thread - break; - } - } - #else + #if (neko || cpp) + private function allTasksAreDone( ):Bool + { for (task in tasks) + if (!task.done) + return false; + return true; + } + + private function getNextFreeThread():PoolThread { - if (task.onFinish != null) - task.onFinish(task.task(task.arg)); + for (thread in threads) + if (!thread.started) + return thread; + return null; } - #end + #end - //clear the old tasks + public function blockRunAllTasks():Void + { + #if (neko || cpp) + while (!allTasksAreDone()) + { + //get a free thread + var thread:PoolThread = getNextFreeThread(); + //but if it doesn't exist, try again + if (thread == null) + continue; + + for (task in tasks) + { + //skip any tasks that are done + if (task.done) + continue; + + //if this task is currently being run, see if it's done yet + if (task.thread != null && task.thread.started) + { + if (task.thread.done) + { + //yay, it finished! + task.done = true; + //reset the thread + task.thread.started = false; + //call the on finish function + if (task.onFinish != null) + task.onFinish(task.thread.result); + } + continue; + } + + //ok, we have a task that needs running + //and a thread to run it + //combine forces! + task.thread = thread; + thread.start(task.task, task.arg); + + //break to try to assign the next thread + break; + } + } + #else + for (task in tasks) + { + if (task.onFinish != null) + task.onFinish(task.task(task.arg)); + } + #end + + //clear the old tasks tasks = new Array(); + } } -} diff --git a/src/verb/exe/WorkerPool.hx b/src/verb/exe/WorkerPool.hx index 3e3eaefe..3a89c1a0 100644 --- a/src/verb/exe/WorkerPool.hx +++ b/src/verb/exe/WorkerPool.hx @@ -25,21 +25,21 @@ class WorkerPool { public function new( numThreads : Int = 1, fileName : String = "verb.js" ) { - for (i in 0...numThreads){ + for ( i in 0...numThreads ) { var w : Worker; try { w = new Worker( basePath + fileName ); - } catch (e : Dynamic ) { - w = new Worker( basePath + fileName.substring(0,-3) + ".min.js" ); + } catch ( e : Dynamic ) { + w = new Worker( basePath + fileName.substring( 0, -3 ) + ".min.js" ); } - _pool.push( w ); + _pool.push( w ); } } // The base path to look for verb's source code - public static var basePath = ""; + public static var basePath = ""; // Add work to perform to the queue @@ -49,40 +49,39 @@ class WorkerPool { callback : Dynamic ) : Void { var work = new Work( className, methodName, args ); - _callbacks.set(work.id, callback); + _callbacks.set( work.id, callback ); _queue.push( work ); - processQueue(); + processQueue( ); } - private function processQueue() { + private function processQueue( ) { - while (_queue.length > 0 && _pool.length > 0) { + while ( _queue.length > 0 && _pool.length > 0 ) { - var work = _queue.shift(); + var work = _queue.shift( ); var workId = work.id; - var worker = _pool.shift(); + var worker = _pool.shift( ); - _working.set(workId, worker); + _working.set( workId, worker ); //upon completing your task... - worker.onmessage = function( e ){ + worker.onmessage = function( e ) { _working.remove( workId ); _pool.push( worker ); try { - if ( _callbacks.exists( workId ) ) - { + if ( _callbacks.exists( workId ) ) { _callbacks.get( workId )( e.data.result ); _callbacks.remove( workId ); } - } catch(error : Dynamic) { + } catch ( error : Dynamic ) { trace( error ); } - processQueue(); + processQueue( ); }; worker.postMessage( work ); @@ -100,7 +99,7 @@ private class Work { public var args : Array; public var id : Int; - public function new(className, methodName, args){ + public function new( className, methodName, args ) { this.className = className; this.methodName = methodName; this.args = args; diff --git a/src/verb/geom/Arc.hx b/src/verb/geom/Arc.hx index 40a61591..3f511ab1 100644 --- a/src/verb/geom/Arc.hx +++ b/src/verb/geom/Arc.hx @@ -24,13 +24,13 @@ class Arc extends NurbsCurve { //* Start angle in radians //* End angle in radians - public function new( center : Point, - xaxis : Vector, - yaxis : Vector, - radius : Float, - minAngle : Float, - maxAngle : Float ) { - super( Make.arc(center, xaxis, yaxis, radius, minAngle, maxAngle ) ); + public function new( center : Point, + xaxis : Vector, + yaxis : Vector, + radius : Float, + minAngle : Float, + maxAngle : Float ) { + super( Make.arc( center, xaxis, yaxis, radius, minAngle, maxAngle ) ); _center = center; _xaxis = xaxis; @@ -48,21 +48,27 @@ class Arc extends NurbsCurve { private var _maxAngle : Float; //Length 3 array representing the center of the arc - public function center() : Point { return _center; } + + public function center( ) : Point { return _center; } //Length 3 array representing the xaxis - public function xaxis() : Vector { return _xaxis; } + + public function xaxis( ) : Vector { return _xaxis; } //Length 3 array representing the perpendicular yaxis - public function yaxis() : Vector { return _yaxis; } + + public function yaxis( ) : Vector { return _yaxis; } //Radius of the arc - public function radius() : Float { return _radius; } + + public function radius( ) : Float { return _radius; } //Start angle in radians - public function minAngle() : Float { return _minAngle; } + + public function minAngle( ) : Float { return _minAngle; } //End angle in radians - public function maxAngle() : Float { return _maxAngle; } + + public function maxAngle( ) : Float { return _maxAngle; } } \ No newline at end of file diff --git a/src/verb/geom/Circle.hx b/src/verb/geom/Circle.hx index 351b47cd..410b62a0 100644 --- a/src/verb/geom/Circle.hx +++ b/src/verb/geom/Circle.hx @@ -19,10 +19,10 @@ class Circle extends Arc { //* Length 3 array representing the perpendicular yaxis //* Radius of the circle - public function new( center : Point, - xaxis : Vector, - yaxis : Vector, - radius : Float ) { + public function new( center : Point, + xaxis : Vector, + yaxis : Vector, + radius : Float ) { super( center, xaxis, yaxis, radius, 0, Math.PI * 2 ); } } diff --git a/src/verb/geom/ConicalSurface.hx b/src/verb/geom/ConicalSurface.hx index e8770df0..1cf3da86 100644 --- a/src/verb/geom/ConicalSurface.hx +++ b/src/verb/geom/ConicalSurface.hx @@ -19,8 +19,8 @@ class ConicalSurface extends NurbsSurface { //* Height of the cone //* Radius of the cone - public function new(axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float ) { - super( Make.conicalSurface(axis, xaxis, base, height, radius )); + public function new( axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float ) { + super( Make.conicalSurface( axis, xaxis, base, height, radius ) ); _axis = axis; _xaxis = xaxis; @@ -36,18 +36,23 @@ class ConicalSurface extends NurbsSurface { private var _radius : Float; //Length 3 array representing the axis of the cone - public function axis(){ return _axis; } + + public function axis( ) { return _axis; } //Length 3 array representing the x axis, perpendicular to the axis - public function xaxis(){ return _xaxis; } + + public function xaxis( ) { return _xaxis; } //Length 3 array representing the base of the cone - public function base(){ return _base; } + + public function base( ) { return _base; } //Height of the cone - public function height(){ return _height; } + + public function height( ) { return _height; } //Radius of the cone - public function radius(){ return _radius; } + + public function radius( ) { return _radius; } } diff --git a/src/verb/geom/CylindricalSurface.hx b/src/verb/geom/CylindricalSurface.hx index e134032d..c82b58a2 100644 --- a/src/verb/geom/CylindricalSurface.hx +++ b/src/verb/geom/CylindricalSurface.hx @@ -21,8 +21,8 @@ class CylindricalSurface extends NurbsSurface { //* Height of the cylinder //* Radius of the cylinder - public function new(axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float) { - super(Make.cylindricalSurface(axis, xaxis, base, height, radius)); + public function new( axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float ) { + super( Make.cylindricalSurface( axis, xaxis, base, height, radius ) ); _axis = axis; _xaxis = xaxis; @@ -38,17 +38,22 @@ class CylindricalSurface extends NurbsSurface { private var _radius : Float; //Length 3 array representing the axis of the cylinder - public function axis(){ return _axis; } + + public function axis( ) { return _axis; } //Length 3 array representing the x axis, perpendicular to the axis - public function xaxis(){ return _xaxis; } + + public function xaxis( ) { return _xaxis; } //Length 3 array representing the base of the cylinder - public function base(){ return _base; } + + public function base( ) { return _base; } //Height of the cylinder - public function height(){ return _height; } + + public function height( ) { return _height; } //Radius of the cylinder - public function radius(){ return _radius; } + + public function radius( ) { return _radius; } } diff --git a/src/verb/geom/Ellipse.hx b/src/verb/geom/Ellipse.hx index dafdeff0..d5ef6488 100644 --- a/src/verb/geom/Ellipse.hx +++ b/src/verb/geom/Ellipse.hx @@ -17,9 +17,9 @@ class Ellipse extends EllipseArc { //* Length 3 array representing the xaxis //* Length 3 array representing the perpendicular yaxis - public function new( center : Point, - xaxis : Vector, - yaxis : Vector ) { + public function new( center : Point, + xaxis : Vector, + yaxis : Vector ) { super( center, xaxis, yaxis, 0, Math.PI * 2 ); } } diff --git a/src/verb/geom/EllipseArc.hx b/src/verb/geom/EllipseArc.hx index f5ee774a..951ca194 100644 --- a/src/verb/geom/EllipseArc.hx +++ b/src/verb/geom/EllipseArc.hx @@ -20,12 +20,12 @@ class EllipseArc extends NurbsCurve { //* Minimum angle of the EllipseArc //* Maximum angle of the EllipseArc - public function new( center : Point, - xaxis : Vector, - yaxis : Vector, - minAngle : Float, - maxAngle : Float ) { - super( Make.ellipseArc(center, xaxis, yaxis, minAngle, maxAngle) ); + public function new( center : Point, + xaxis : Vector, + yaxis : Vector, + minAngle : Float, + maxAngle : Float ) { + super( Make.ellipseArc( center, xaxis, yaxis, minAngle, maxAngle ) ); _center = center; _xaxis = xaxis; @@ -41,19 +41,24 @@ class EllipseArc extends NurbsCurve { private var _maxAngle : Float; //Length 3 array representing the center of the arc - public function center(){ return _center; } + + public function center( ) { return _center; } //Length 3 array representing the xaxis - public function xaxis(){ return _xaxis; } + + public function xaxis( ) { return _xaxis; } //Length 3 array representing the perpendicular yaxis - public function yaxis(){ return _yaxis; } + + public function yaxis( ) { return _yaxis; } //Minimum angle of the EllipseArc - public function minAngle(){ return _minAngle; } + + public function minAngle( ) { return _minAngle; } //Maximum angle of the EllipseArc - public function maxAngle(){ return _maxAngle; } + + public function maxAngle( ) { return _maxAngle; } } \ No newline at end of file diff --git a/src/verb/geom/ExtrudedSurface.hx b/src/verb/geom/ExtrudedSurface.hx index cedd9728..b98815f4 100644 --- a/src/verb/geom/ExtrudedSurface.hx +++ b/src/verb/geom/ExtrudedSurface.hx @@ -16,7 +16,7 @@ class ExtrudedSurface extends NurbsSurface { //* The direction and magnitude of the extrusion public function new( profile : ICurve, direction : Vector ) { - super( Make.extrudedSurface( Vec.normalized( direction ), Vec.norm( direction ), profile.asNurbs() )); + super( Make.extrudedSurface( Vec.normalized( direction ), Vec.norm( direction ), profile.asNurbs( ) ) ); _profile = profile; _direction = direction; @@ -27,10 +27,10 @@ class ExtrudedSurface extends NurbsSurface { //The profile curve - public function profile() : ICurve { return _profile; } + public function profile( ) : ICurve { return _profile; } //The direction and magnitude of the extrusion - public function direction() : Vector { return _direction; } + public function direction( ) : Vector { return _direction; } } diff --git a/src/verb/geom/ICurve.hx b/src/verb/geom/ICurve.hx index 22967dcd..c487ce74 100644 --- a/src/verb/geom/ICurve.hx +++ b/src/verb/geom/ICurve.hx @@ -15,7 +15,7 @@ interface ICurve extends ISerializable { // //* A NurbsCurveData object representing the curve - function asNurbs() : NurbsCurveData; + function asNurbs( ) : NurbsCurveData; //Obtain the parametric domain of the curve // @@ -23,7 +23,7 @@ interface ICurve extends ISerializable { // //* An Interval object containing the min and max of the domain - function domain() : Interval; + function domain( ) : Interval; //Evaluate a point on the curve // @@ -35,7 +35,7 @@ interface ICurve extends ISerializable { // //* The evaluated point - function point(u : Float) : Point; + function point( u : Float ) : Point; //Evaluate the derivatives at a point on a curve // @@ -48,5 +48,5 @@ interface ICurve extends ISerializable { // //* An array of derivative vectors - function derivatives(u : Float, numDerivs : Int = 1) : Array; + function derivatives( u : Float, numDerivs : Int = 1 ) : Array; } diff --git a/src/verb/geom/ISurface.hx b/src/verb/geom/ISurface.hx index ced0f206..e3f48627 100644 --- a/src/verb/geom/ISurface.hx +++ b/src/verb/geom/ISurface.hx @@ -16,7 +16,7 @@ interface ISurface extends ISerializable { // //* A NurbsCurveData object representing the curve - function asNurbs() : NurbsSurfaceData; + function asNurbs( ) : NurbsSurfaceData; //Provide the domain of the surface in the U direction // @@ -24,7 +24,7 @@ interface ISurface extends ISerializable { // //* An interval object with min and max properties - function domainU() : Interval; + function domainU( ) : Interval; //Provide the domain of the surface in the V direction // @@ -32,7 +32,7 @@ interface ISurface extends ISerializable { // //* An interval object with min and max properties - function domainV() : Interval; + function domainV( ) : Interval; //Obtain a point on the surface at the given parameter // @@ -45,7 +45,7 @@ interface ISurface extends ISerializable { // //* A point on the surface - function point(u : Float, v : Float) : Point; + function point( u : Float, v : Float ) : Point; //Obtain the derivatives of the NurbsSurface. Returns a two dimensional array //containing the derivative vectors. Increasing U partial derivatives are increasing @@ -63,6 +63,6 @@ interface ISurface extends ISerializable { // //* A two dimensional array of vectors - function derivatives(u : Float, v : Float, numDerivs : Int = 1) : Array>; + function derivatives( u : Float, v : Float, numDerivs : Int = 1 ) : Array>; } diff --git a/src/verb/geom/Intersect.hx b/src/verb/geom/Intersect.hx index 7a9756c2..8bad1745 100644 --- a/src/verb/geom/Intersect.hx +++ b/src/verb/geom/Intersect.hx @@ -28,14 +28,14 @@ class Intersect { // //* a possibly empty array of CurveCurveIntersection objects - public static function curves( first : ICurve, second : ICurve, tol : Float = 1e-3 ) : Array { - return verb.eval.Intersect.curves( first.asNurbs(), second.asNurbs(), tol ); + public static function curves( first : ICurve, second : ICurve, tol : Float = 1e-3 ) : Array { + return verb.eval.Intersect.curves( first.asNurbs( ), second.asNurbs( ), tol ); } // The async version of `curves` public static function curvesAsync( first : ICurve, second : ICurve, tol : Float = 1e-3 ) : Promise> { - return Dispatcher.dispatchMethod( verb.eval.Intersect, "curves", [first.asNurbs(), second.asNurbs(), tol ]); + return Dispatcher.dispatchMethod( verb.eval.Intersect, "curves", [first.asNurbs( ), second.asNurbs( ), tol ] ); } //Determine the intersection of a curve and a surface @@ -51,13 +51,13 @@ class Intersect { //* array of CurveSurfaceIntersection objects public static function curveAndSurface( curve : ICurve, surface : ISurface, tol : Float = 1e-3 ) : Array { - return verb.eval.Intersect.curveAndSurface( curve.asNurbs(), surface.asNurbs(), tol); + return verb.eval.Intersect.curveAndSurface( curve.asNurbs( ), surface.asNurbs( ), tol ); } // The async version of `curveAndSurface` public static function curveAndSurfaceAsync( curve : ICurve, surface : ISurface, tol : Float = 1e-3 ) : Promise> { - return Dispatcher.dispatchMethod( verb.eval.Intersect, "curveAndSurface", [curve.asNurbs(), surface.asNurbs(), tol ]); + return Dispatcher.dispatchMethod( verb.eval.Intersect, "curveAndSurface", [curve.asNurbs( ), surface.asNurbs( ), tol ] ); } //Determine the intersection of two surfaces @@ -71,17 +71,17 @@ class Intersect { // //* array of NurbsCurveData objects - public static function surfaces( first : ISurface, second : ISurface, tol : Float = 1e-3 ) : Array { - return verb.eval.Intersect.surfaces( first.asNurbs(), second.asNurbs(), tol ) - .map(function(cd){ return new NurbsCurve(cd); }); + public static function surfaces( first : ISurface, second : ISurface, tol : Float = 1e-3 ) : Array { + return verb.eval.Intersect.surfaces( first.asNurbs( ), second.asNurbs( ), tol ) + .map( function( cd ) { return new NurbsCurve(cd); } ); } // The async version of `surfaces` - public static function surfacesAsync( first : ISurface, second : ISurface, tol : Float = 1e-3 ) : Promise> { - return Dispatcher.dispatchMethod( verb.eval.Intersect, "surfaces", [first.asNurbs(), second.asNurbs(), tol]) - .then(function(cds){ - return cds.map(function(cd){ return new NurbsCurve(cd); }); - }); + public static function surfacesAsync( first : ISurface, second : ISurface, tol : Float = 1e-3 ) : Promise> { + return Dispatcher.dispatchMethod( verb.eval.Intersect, "surfaces", [first.asNurbs( ), second.asNurbs( ), tol] ) + .then( function( cds ) { + return cds.map( function( cd ) { return new NurbsCurve(cd); } ); + } ); } } diff --git a/src/verb/geom/Line.hx b/src/verb/geom/Line.hx index 67de765d..6fc7dade 100644 --- a/src/verb/geom/Line.hx +++ b/src/verb/geom/Line.hx @@ -28,9 +28,11 @@ class Line extends NurbsCurve { private var _end : Point; //Length 3 array representing the start point - public function start(){ return _start; } + + public function start( ) { return _start; } //Length 3 array representing the end point - public function end(){ return _end; } + + public function end( ) { return _end; } } \ No newline at end of file diff --git a/src/verb/geom/NurbsCurve.hx b/src/verb/geom/NurbsCurve.hx index 28095629..658e6b25 100644 --- a/src/verb/geom/NurbsCurve.hx +++ b/src/verb/geom/NurbsCurve.hx @@ -64,7 +64,7 @@ class NurbsCurve extends SerializableBase implements ICurve { knots : KnotArray, controlPoints : Array, weights : Array = null ) : NurbsCurve { - return new NurbsCurve( new NurbsCurveData( degree, knots.copy(), Eval.homogenize1d( controlPoints, weights) ) ); + return new NurbsCurve( new NurbsCurveData( degree, knots.copy( ), Eval.homogenize1d( controlPoints, weights ) ) ); } //Construct a NurbsCurve by interpolating a collection of points. The resultant curve @@ -80,23 +80,27 @@ class NurbsCurve extends SerializableBase implements ICurve { //* A new NurbsCurve public static function byPoints( points : Array, degree : Int = 3 ) : NurbsCurve { - return new NurbsCurve( Make.rationalInterpCurve(points, degree) ); + return new NurbsCurve( Make.rationalInterpCurve( points, degree ) ); } //underlying serializable, data object private var _data : NurbsCurveData; //The degree of the curve - public function degree() : Int { return _data.degree; } + + public function degree( ) : Int { return _data.degree; } //The knot array - public function knots() : KnotArray { return _data.knots.slice(0); } + + public function knots( ) : KnotArray { return _data.knots.slice( 0 ); } //Array of control points - public function controlPoints() : Array { return Eval.dehomogenize1d(_data.controlPoints); } + + public function controlPoints( ) : Array { return Eval.dehomogenize1d( _data.controlPoints ); } //Array of weight values - public function weights() : Array { return Eval.weight1d(_data.controlPoints); } + + public function weights( ) : Array { return Eval.weight1d( _data.controlPoints ); } //Obtain a copy of the underlying data structure for the Curve. Used with verb.core. // @@ -104,8 +108,8 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurveData object - public function asNurbs() : NurbsCurveData { - return new NurbsCurveData( degree(), knots(), Eval.homogenize1d( controlPoints(), weights() )); + public function asNurbs( ) : NurbsCurveData { + return new NurbsCurveData( degree( ), knots( ), Eval.homogenize1d( controlPoints( ), weights( ) )); } //Obtain a copy of the curve @@ -114,7 +118,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The copied curve - public function clone(){ + public function clone( ) { return new NurbsCurve( this._data ); } @@ -124,8 +128,8 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* An array representing the high and end point of the domain of the curve - public function domain() : Interval { - return new Interval( _data.knots.first(), _data.knots.last()); + public function domain( ) : Interval { + return new Interval( _data.knots.first( ), _data.knots.last( )); } //Transform a curve with the given matrix. @@ -145,8 +149,8 @@ class NurbsCurve extends SerializableBase implements ICurve { //The async version of `transform` public function transformAsync( mat : Matrix ) : Promise { - return Dispatcher.dispatchMethod( Modify, 'rationalCurveTransform', [ _data, mat ] ) - .then(function(x){ return new NurbsCurve(x); }); + return Dispatcher.dispatchMethod( Modify, 'rationalCurveTransform', [ _data, mat ] ) + .then( function( x ) { return new NurbsCurve(x); } ); } //Sample a point at the given parameter @@ -165,8 +169,8 @@ class NurbsCurve extends SerializableBase implements ICurve { //The async version of `point` - public function pointAsync( u : Float) : Promise { - return Dispatcher.dispatchMethod( Eval, 'rationalCurvePoint', [ _data, u ] ); + public function pointAsync( u : Float ) : Promise { + return Dispatcher.dispatchMethod( Eval, 'rationalCurvePoint', [ _data, u ] ); } //Obtain the curve tangent at the given parameter. This is the first derivative and is @@ -228,7 +232,7 @@ class NurbsCurve extends SerializableBase implements ICurve { //The async version of `closestPoint` public function closestPointAsync( pt : Point ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestPoint', [ _data, pt ] ); + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestPoint', [ _data, pt ] ); } //Determine the closest parameter on the curve to the given point @@ -248,7 +252,7 @@ class NurbsCurve extends SerializableBase implements ICurve { //The async version of `length` public function closestParamAsync( pt : Dynamic ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestParam', [ _data, pt ] ); + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestParam', [ _data, pt ] ); } //Determine the arc length of the curve @@ -257,13 +261,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve - public function length() : Float { + public function length( ) : Float { return Analyze.rationalCurveArcLength( _data ); } //The async version of `length` - public function lengthAsync() : Promise { + public function lengthAsync( ) : Promise { return Dispatcher.dispatchMethod( Analyze, 'rationalCurveArcLength', [ _data ] ); } @@ -283,7 +287,7 @@ class NurbsCurve extends SerializableBase implements ICurve { //The async version of `lengthAtParam` - public function lengthAtParamAsync() : Promise { + public function lengthAtParamAsync( ) : Promise { return Dispatcher.dispatchMethod( Analyze, 'rationalCurveArcLength', [ _data ] ); } @@ -358,16 +362,16 @@ class NurbsCurve extends SerializableBase implements ICurve { //* Two curves - one at the lower end of the parameter range and one at the higher end. public function split( u : Float ) : Array { - return Divide.curveSplit( _data, u ).map(function(x){ return new NurbsCurve(x); }); + return Divide.curveSplit( _data, u ).map( function( x ) { return new NurbsCurve(x); } ); } // The async version of `split` public function splitAsync( u : Float ) : Promise> { - return Dispatcher.dispatchMethod( Divide, 'curveSplit', [ _data, u ]) - .then(function(cs : Array) : Array{ - return cs.map(function(x){ return new NurbsCurve(x); }); - }); + return Dispatcher.dispatchMethod( Divide, 'curveSplit', [ _data, u ] ) + .then( function( cs : Array ) : Array { + return cs.map( function( x ) { return new NurbsCurve(x); } ); + } ); } //Reverse the parameterization of the curve @@ -376,34 +380,34 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A reversed curve - public function reverse() : NurbsCurve { + public function reverse( ) : NurbsCurve { return new NurbsCurve( Modify.curveReverse( _data ) ); } // The async version of `reverse` - public function reverseAsync() : Promise { - return Dispatcher.dispatchMethod( Modify, 'curveReverse', [ _data ]) - .then(function(c){ return new NurbsCurve(c); }); + public function reverseAsync( ) : Promise { + return Dispatcher.dispatchMethod( Modify, 'curveReverse', [ _data ] ) + .then( function( c ) { return new NurbsCurve(c); } ); } //Tessellate a curve at a given tolerance // //**params** // - //* The tolerance at which to sample the curve + //* The tolerance at which to sample the curve, the chord making up the tessellation will not deviate from the curve more than this value // //**returns** // //* A point represented as an array - public function tessellate(tolerance : Float = null) : Array { + public function tessellate( tolerance : Float = 1e-3 ) : Array { return Tess.rationalCurveAdaptiveSample( _data, tolerance, false ); } // The async version of `tessellate` - public function tessellateAsync( tolerance : Float = null ) : Promise> { + public function tessellateAsync( tolerance : Float = 1e-3 ) : Promise> { return Dispatcher.dispatchMethod( Tess, 'rationalCurveAdaptiveSample', [ _data, tolerance, false ] ); } diff --git a/src/verb/geom/NurbsSurface.hx b/src/verb/geom/NurbsSurface.hx index f88aa30b..6caf9c69 100644 --- a/src/verb/geom/NurbsSurface.hx +++ b/src/verb/geom/NurbsSurface.hx @@ -41,7 +41,7 @@ class NurbsSurface extends SerializableBase implements ISurface { //* A new NurbsSurface public function new( data : NurbsSurfaceData ) { - _data = Check.isValidNurbsSurfaceData(data); + _data = Check.isValidNurbsSurfaceData( data ); } @@ -60,13 +60,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public static function byKnotsControlPointsWeights(degreeU : Int, - degreeV : Int, - knotsU : KnotArray, - knotsV : KnotArray, - controlPoints : Array>, - weights : Array> = null ) : NurbsSurface { - return new NurbsSurface( new NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, Eval.homogenize2d(controlPoints, weights) ) ); + public static function byKnotsControlPointsWeights( degreeU : Int, + degreeV : Int, + knotsU : KnotArray, + knotsV : KnotArray, + controlPoints : Array>, + weights : Array> = null ) : NurbsSurface { + return new NurbsSurface( new NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, Eval.homogenize2d( controlPoints, weights ) ) ); } //Construct a NurbsSurface from four perimeter points in counter-clockwise order @@ -97,7 +97,7 @@ class NurbsSurface extends SerializableBase implements ISurface { //* A new NurbsSurface public static function byLoftingCurves( curves : Array, degreeV : Int = null ) : NurbsSurface { - return new NurbsSurface( Make.loftedSurface([for (c in curves) c.asNurbs() ], degreeV )); + return new NurbsSurface( Make.loftedSurface( [for ( c in curves ) c.asNurbs( ) ], degreeV )); } //underlying serializable, data object @@ -107,27 +107,27 @@ class NurbsSurface extends SerializableBase implements ISurface { //The degree in the U direction - public function degreeU() : Int { return _data.degreeU; } + public function degreeU( ) : Int { return _data.degreeU; } //The degree in the V direction - public function degreeV() : Int { return _data.degreeV; } + public function degreeV( ) : Int { return _data.degreeV; } //The knot array in the U direction - public function knotsU() : Array { return _data.knotsU.slice(0); } + public function knotsU( ) : Array { return _data.knotsU.slice( 0 ); } //The knot array in the V direction - public function knotsV() : Array { return _data.knotsV.slice(0); } + public function knotsV( ) : Array { return _data.knotsV.slice( 0 ); } //Two dimensional array of points - public function controlPoints() : Array> { return Eval.dehomogenize2d(_data.controlPoints); } + public function controlPoints( ) : Array> { return Eval.dehomogenize2d( _data.controlPoints ); } //Two dimensional array of weight values - public function weights() : Array { return Eval.weight2d(_data.controlPoints); } + public function weights( ) : Array { return Eval.weight2d( _data.controlPoints ); } //Obtain a copy of the underlying data structure for the Surface. Used with verb.core. // @@ -135,8 +135,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurfaceData object - public function asNurbs() : NurbsSurfaceData { - return new NurbsSurfaceData( degreeU(), degreeV(), knotsU(), knotsV(), Eval.homogenize2d( controlPoints(), weights() )); + public function asNurbs( ) : NurbsSurfaceData { + return new NurbsSurfaceData( degreeU( ), degreeV( ), knotsU( ), knotsV( ), Eval.homogenize2d( controlPoints( ), weights( ) )); } //Obtain a copy of the Surface @@ -145,8 +145,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public function clone() : NurbsSurface { - return new NurbsSurface( asNurbs() ); + public function clone( ) : NurbsSurface { + return new NurbsSurface( asNurbs( ) ); } //The parametric domain in the U direction @@ -155,8 +155,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* An Interval object with min and max property - public function domainU() : Interval { - return new Interval( _data.knotsU.first(), _data.knotsU.last()); + public function domainU( ) : Interval { + return new Interval( _data.knotsU.first( ), _data.knotsU.last( )); } //The parametric domain in the V direction @@ -165,8 +165,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* An Interval object with min and max property - public function domainV() : Interval { - return new Interval( _data.knotsV.first(), _data.knotsV.last()); + public function domainV( ) : Interval { + return new Interval( _data.knotsV.first( ), _data.knotsV.last( )); } //Obtain a point on the surface at the given parameter @@ -291,16 +291,16 @@ class NurbsSurface extends SerializableBase implements ISurface { public function split( u : Float, useV : Bool = false ) : Array { return Divide.surfaceSplit( _data, u, useV ) - .map(function(x){ return new NurbsSurface(x); }); + .map( function( x ) { return new NurbsSurface(x); } ); } //The async version of `split` public function splitAsync( u : Float, useV : Bool = false ) : Promise> { return Dispatcher.dispatchMethod( Divide, 'surfaceSplit', [ _data, u, useV ] ) - .then(function(s){ - return s.map(function(x){ return new NurbsSurface(x); }); - }); + .then( function( s ) { + return s.map( function( x ) { return new NurbsSurface(x); } ); + } ); } //Reverse the parameterization of the curve @@ -320,8 +320,8 @@ class NurbsSurface extends SerializableBase implements ISurface { //The async version of `reverse` public function reverseAsync( useV : Bool = false ) : Promise { - return Dispatcher.dispatchMethod( Modify, 'surfaceReverse', [ _data, useV ]) - .then(function(c){ return new NurbsSurface(c); }); + return Dispatcher.dispatchMethod( Modify, 'surfaceReverse', [ _data, useV ] ) + .then( function( c ) { return new NurbsSurface(c); } ); } //Extract an isocurve from a surface @@ -343,7 +343,7 @@ class NurbsSurface extends SerializableBase implements ISurface { public function isocurveAsync( u : Float, useV : Bool = false ) : Promise { return Dispatcher.dispatchMethod( Make, 'surfaceIsocurve', [ _data, u, useV ] ) - .then(function(x){ return new NurbsCurve(x); }); + .then( function( x ) { return new NurbsCurve(x); } ); } //Extract the boundary curves from a surface @@ -352,17 +352,17 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* an array containing 4 elements, first 2 curves in the V direction, then 2 curves in the U direction - public function boundaries( options : AdaptiveRefinementOptions = null) : Array { - return Make.surfaceBoundaryCurves( _data ).map(function(x){ return new NurbsCurve(x); }); + public function boundaries( options : AdaptiveRefinementOptions = null ) : Array { + return Make.surfaceBoundaryCurves( _data ).map( function( x ) { return new NurbsCurve(x); } ); } //The async version of `boundaries` public function boundariesAsync( options : AdaptiveRefinementOptions = null ) : Promise> { return Dispatcher.dispatchMethod( Make, 'surfaceBoundaryCurves', [ _data ] ) - .then(function(cs : Array){ - return cs.map(function(x){ return new NurbsCurve(x); }); - }); + .then( function( cs : Array ) { + return cs.map( function( x ) { return new NurbsCurve(x); } ); + } ); } @@ -376,14 +376,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A MeshData object - public function tessellate( options : AdaptiveRefinementOptions = null) : MeshData { + public function tessellate( options : AdaptiveRefinementOptions = null ) : MeshData { return Tess.rationalSurfaceAdaptive( _data, options ); } //The async version of `boundaries` public function tessellateAsync( options : AdaptiveRefinementOptions = null ) : Promise { - return Dispatcher.dispatchMethod( Tess, 'rationalSurfaceAdaptive', [ _data, options ] ); + return Dispatcher.dispatchMethod( Tess, 'rationalSurfaceAdaptive', [ _data, options ] ); } //Transform a Surface with the given matrix. @@ -403,7 +403,7 @@ class NurbsSurface extends SerializableBase implements ISurface { //The async version of `transform` public function transformAsync( mat : Matrix ) : Promise { - return Dispatcher.dispatchMethod( Modify, 'rationalSurfaceTransform', [ _data, mat ] ) - .then(function(x){ return new NurbsSurface(x); }); + return Dispatcher.dispatchMethod( Modify, 'rationalSurfaceTransform', [ _data, mat ] ) + .then( function( x ) { return new NurbsSurface(x); } ); } } diff --git a/src/verb/geom/RevolvedSurface.hx b/src/verb/geom/RevolvedSurface.hx index 55871fec..54237a02 100644 --- a/src/verb/geom/RevolvedSurface.hx +++ b/src/verb/geom/RevolvedSurface.hx @@ -18,8 +18,8 @@ class RevolvedSurface extends NurbsSurface { //* The direction of the axis of revolution //* The angle to revolve around. 2 * Math.PI corresponds to a complete revolution - public function new( profile : NurbsCurve, center : Point, axis : Vector, angle : Float ) { - super( Make.revolvedSurface( profile.asNurbs(), center, axis, angle ) ); + public function new( profile : NurbsCurve, center : Point, axis : Vector, angle : Float ) { + super( Make.revolvedSurface( profile.asNurbs( ), center, axis, angle ) ); _profile = profile; _center = center; @@ -34,18 +34,18 @@ class RevolvedSurface extends NurbsSurface { //The profile curve - public function profile() : ICurve { return _profile; } + public function profile( ) : ICurve { return _profile; } //A point on the axis of revolution - public function center() : Point { return _center; } + public function center( ) : Point { return _center; } //The direction of the axis of revolution - public function axis() : Vector { return _center; } + public function axis( ) : Vector { return _center; } //The angle to revolve around. 2 * Math.PI corresponds to a complete revolution - public function angle() : Float { return _angle; } + public function angle( ) : Float { return _angle; } } diff --git a/src/verb/geom/SphericalSurface.hx b/src/verb/geom/SphericalSurface.hx index 8e6bee05..66f71687 100644 --- a/src/verb/geom/SphericalSurface.hx +++ b/src/verb/geom/SphericalSurface.hx @@ -17,9 +17,9 @@ class SphericalSurface extends NurbsSurface { //* Length 3 array representing the center of the circle //* Radius of the circle - public function new( center : Point, - radius : Float ) { - super( Make.sphericalSurface( center, [0,0,1], [1,0,0], radius )); + public function new( center : Point, + radius : Float ) { + super( Make.sphericalSurface( center, [0, 0, 1], [1, 0, 0], radius ) ); _center = center; _radius = radius; @@ -30,11 +30,11 @@ class SphericalSurface extends NurbsSurface { //Length 3 array representing the center of the circle - public function center() : Point{ return _center; } + public function center( ) : Point { return _center; } //Radius of the circle - public function radius() : Float{ return _radius; } + public function radius( ) : Float { return _radius; } } diff --git a/src/verb/geom/SweptSurface.hx b/src/verb/geom/SweptSurface.hx index 024073c7..6bbc69c4 100644 --- a/src/verb/geom/SweptSurface.hx +++ b/src/verb/geom/SweptSurface.hx @@ -18,7 +18,7 @@ class SweptSurface extends NurbsSurface { //* The rail curve public function new( profile : ICurve, rail : ICurve ) { - super( Make.rationalTranslationalSurface( profile.asNurbs(), rail.asNurbs() )); + super( Make.rationalTranslationalSurface( profile.asNurbs( ), rail.asNurbs( ) ) ); _profile = profile; _rail = rail; @@ -29,11 +29,11 @@ class SweptSurface extends NurbsSurface { //The profile curve - public function profile() : ICurve { return _profile; } + public function profile( ) : ICurve { return _profile; } //The rail curve - public function rail() : ICurve { return _rail; } + public function rail( ) : ICurve { return _rail; } } diff --git a/test/testCore.js b/test/testCore.js index 30e7ffff..892b41e3 100755 --- a/test/testCore.js +++ b/test/testCore.js @@ -1,5 +1,5 @@ var should = require('should') - , verb = require('../build/js/verb.js'); + , verb = require('../build/js/verb.js'); // necessary for multi-threading verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/"; @@ -7,815 +7,815 @@ verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/"; // some testing utilities function vecShouldBe( expected, test, tol ){ - if (tol === undefined) tol = verb.core.Constants.TOLERANCE; + if (tol === undefined) tol = verb.core.Constants.TOLERANCE; - test.length.should.be.equal( expected.length ); + test.length.should.be.equal( expected.length ); - for (var i = 0; i < test.length; i++){ - test[i].should.be.approximately( expected[i], tol ); - } + for (var i = 0; i < test.length; i++){ + test[i].should.be.approximately( expected[i], tol ); + } } function last(a){ - return a[a.length-1]; + return a[a.length-1]; } -describe("verb.core.BoundingBox.init",function(){ +describe("verb.core.BoundingBox.init", () => { - it('should allow array of point arguments', function(){ + it('should allow array of point arguments', () => { - var bb1 = new verb.core.BoundingBox([[5,5,5], [10,10,10]]); + 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.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 ); + should.equal( bb1.max[0], 10 ); + should.equal( bb1.max[1], 10 ); + should.equal( bb1.max[2], 10 ); - }); + }); }); -describe("verb.core.BoundingBox.intersects",function(){ +describe("verb.core.BoundingBox.intersects", () => { - it('returns expected results', function(){ + it('returns expected results', () => { - 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] ]); + 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 ); + should.equal( bb1.intersects(bb2), true ); + should.equal( bb1.intersects(bb3), false ); + should.equal( bb2.intersects(bb3), false ); - }); + }); }); -describe("verb.core.BoundingBox.intersect",function(){ +describe("verb.core.BoundingBox.intersect", () => { - it('returns expected results', function(){ + it('returns expected results', () => { - // 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] ]); + // 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); + // 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.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_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 + should.equal( int_bb1_bb3, null ); //non-intersect is null - }); + }); }); -describe("verb.core.BoundingBox.intervalsOverlap",function(){ +describe("verb.core.BoundingBox.intervalsOverlap", () => { - it('returns expected results', function(){ + it('returns expected results', () => { - 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 ); + 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(){ +describe("verb.core.BoundingBox.contains", () => { - it('returns expected results', function(){ + it('returns expected results', () => { - var bb4 = new verb.core.BoundingBox([ [0,0,0], [1,1,1] ]) - , bb5 = new verb.core.BoundingBox(); + 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 ); + 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(){ +describe("verb.core.BoundingBox.contains", () => { - it('BoundingBox.clear', function(){ + it('BoundingBox.clear', () => { - var bb1 = new verb.core.BoundingBox([ [5,5,5], [10,10,10] ]); - bb1.clear(); - should.equal( bb1.initialized, false ); + 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(){ +describe("verb.core.BoundingBox.getAxisLength", () => { - it('should return correct value', function(){ + it('should return correct value', () => { - 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 ); + 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(){ +describe("verb.core.BoundingBox.getLongestAxis", () => { - it('should return correct value', function(){ + it('should return correct value', () => { - var bb1 = new verb.core.BoundingBox([ [-1,2,3], [10,10,10] ]); - should.equal( bb1.getLongestAxis(0), 0 ); + var bb1 = new verb.core.BoundingBox([ [-1,2,3], [10,10,10] ]); + should.equal( bb1.getLongestAxis(0), 0 ); - }); + }); }); -describe("verb.core.BoundingBox.getAxisLength",function(){ +describe("verb.core.BoundingBox.getAxisLength", () => { - it('should return 0 when given out of bounds index', function(){ + it('should return 0 when given out of bounds index', () => { - 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 ); + 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(){ +describe("verb.core.BoundingBox.getAxisLength", () => { - it('should return 0 when given out of bounds index', function(){ + it('should return 0 when given out of bounds index', () => { - 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 ); + 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(){ +describe("verb.core.BoundingBox.clear", () => { - it('should set initialized to false', function(){ + it('should set initialized to false', () => { - var bb1 = new verb.core.BoundingBox([ [5,5,5], [10,10,10] ]); - bb1.clear(); - should.equal( bb1.initialized, false ); + 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 }; + 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(){ +describe("verb.core.AdaptiveRefinementNode.constructor", () => { - it('can be instantiated', function(){ + it('can be instantiated', () => { - var f = new verb.core.AdaptiveRefinementNode( getFlatSurface() ); + 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); + 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(){ +describe("verb.core.AdaptiveRefinementNode.getEdgeCorners", () => { - it('returns expected result for node without children', function(){ + it('returns expected result for node without children', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + 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]] ); + 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(){ + it('returns expected result for node with children', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); - f.divide({ minDepth : 1 }); + f.divide({ minDepth : 1 }); - f.children.length.should.be.equal( 2 ); + 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 ] ] ); + // 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(){ + it('returns expected result for node with nested children', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + 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.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 ] ] ); + 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(){ +describe("verb.core.AdaptiveRefinementNode.getAllCorners", () => { - it('returns expected result for edge with more vertices on opposite side', function(){ + it('returns expected result for edge with more vertices on opposite side', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); - f.divide({ minDepth : 1 }); // now f is split in 2 horizontally + 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].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 ] ] ); + 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(){ + it('returns expected result for edge with neighbors that has with lesser number of vertices on opposite side', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); - f.divide({ minDepth : 1 }); // now f is split in 2 horizontally + 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].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 ] ] ); + 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(){ +describe("verb.core.Vec.signedAngleBetween", () => { + it('computes correct area for triangular prism', () => { 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(){ +describe("verb.core.Trig.isPointInPlane", () => { + it('works for a few basic cases', () => { 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(){ +describe("verb.core.AdaptiveRefinementNode.divide", () => { - it('can be called with options.minDepth', function(){ + it('can be called with options.minDepth', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + 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.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(){ + it('can be called with no options provided', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); - f.divide(); + f.divide(); - // no division is done - should.equal( f.children, null); + // no division is done + should.equal( f.children, null); - }); + }); }); -describe("verb.core.Trig.distToSegment",function(){ +describe("verb.core.Trig.distToSegment", () => { - it('works for simple case', function(){ + it('works for simple case', () => { - verb.core.Trig.distToSegment([ -10,0,0], [3,3,0], [5,0,0] ).should.be.equal( 3 ); + verb.core.Trig.distToSegment([ -10,0,0], [3,3,0], [5,0,0] ).should.be.equal( 3 ); - }); + }); }); -describe("verb.core.AdaptiveRefinementNode.evalSrf",function(){ +describe("verb.core.AdaptiveRefinementNode.evalSrf", () => { - it('works as expected', function(){ + it('works as expected', () => { - var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); + var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); - var res = f.evalSrf( 0, 0 ); + var res = f.evalSrf( 0, 0 ); - vecShouldBe( [0,0,0], res.point ); - vecShouldBe( [0,0,-1], res.normal ); + vecShouldBe( [0,0,0], res.point ); + vecShouldBe( [0,0,-1], res.normal ); - res = f.evalSrf( 1,0 ); + res = f.evalSrf( 1,0 ); - vecShouldBe( [1,0,0], res.point ); - vecShouldBe( [0,0,-1], res.normal ); + vecShouldBe( [1,0,0], res.point ); + vecShouldBe( [0,0,-1], res.normal ); - res = f.evalSrf( 1,1 ); + res = f.evalSrf( 1,1 ); - vecShouldBe( [1,1,0], res.point ); - vecShouldBe( [0,0,-1], res.normal ); + vecShouldBe( [1,1,0], res.point ); + vecShouldBe( [0,0,-1], res.normal ); - }); + }); }); -describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ +describe("verb.core.AdaptiveRefinementNode.triangulate", () => { - function getWarpedSurface(){ + function getWarpedSurface(){ - var p1 = [0,0,0] - , p2 = [1,0,0] - , p3 = [1,1,1] - , p4 = [0,1,0]; + 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]]; + 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); + 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 }; + 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(){ + it('can triangulate a square, planar surface with no options defined', () => { - var srf = getFlatSurface(); + var srf = getFlatSurface(); - var f = new verb.core.AdaptiveRefinementNode( srf ); - f.divide(); - var mesh = f.triangulate(); + 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 ] ] ); + 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(){ + it('can triangulate a warped surface with no options defined', () => { - var srf = getWarpedSurface(); + var srf = getWarpedSurface(); - var f = new verb.core.AdaptiveRefinementNode( srf ); + var f = new verb.core.AdaptiveRefinementNode( srf ); - f.divide(); - var mesh = f.triangulate(); + 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 ); + 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(){ + it('can triangulate a node with children', () => { - var srf = getFlatSurface(); + var srf = getFlatSurface(); - var f = new verb.core.AdaptiveRefinementNode( srf ); + var f = new verb.core.AdaptiveRefinementNode( srf ); - f.divide({ minDepth: 1 }); - var mesh = f.triangulate(); + 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 ); + 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(){ + it('can triangulate a node with children and un-nested neighbors', () => { - var srf = getFlatSurface(); + var srf = getFlatSurface(); - var f = new verb.core.AdaptiveRefinementNode( srf ); + var f = new verb.core.AdaptiveRefinementNode( srf ); - f.divide({ minDepth: 1 }); - f.children[0].divide({ minDepth: 1 }); + f.divide({ minDepth: 1 }); + f.children[0].divide({ minDepth: 1 }); - var mesh = f.triangulate(); + 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 ); + 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(){ + it('can triangulate a node with children and equally nested neighbors', () => { - var srf = getFlatSurface(); + var srf = getFlatSurface(); - var f = new verb.core.AdaptiveRefinementNode( srf ); + var f = new verb.core.AdaptiveRefinementNode( srf ); - f.divide({ minDepth: 2 }); + f.divide({ minDepth: 2 }); - var mesh = f.triangulate(); + 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 ); + 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(){ + it('can triangulate a node with children and more nested neighbors', () => { - var srf = getFlatSurface(); + var srf = getFlatSurface(); - var f = new verb.core.AdaptiveRefinementNode( srf ); + var f = new verb.core.AdaptiveRefinementNode( srf ); - f.divide({ minDepth: 3 }); + f.divide({ minDepth: 3 }); - var mesh = f.triangulate(); + 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 ); + 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(){ +describe("verb.core.Mat.solve", () => { - it('can solve simple case', function(){ + it('can solve simple case', () => { - var A = [[1,0.4], [-0.2,1]]; - var At = verb.core.Mat.transpose(A); - var b = [5,4]; + 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 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] ) - ); + 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 ); + vecShouldBe( b, s ); - }); + }); - function rand1d(n){ + function rand1d(n){ - var row = []; - for (var j = 0; j < n; j++){ - row.push(Math.random()); - } + var row = []; + for (var j = 0; j < n; j++){ + row.push(Math.random()); + } - return row; + return row; - } + } - function rand2d(n){ + function rand2d(n){ - var a = []; - for (var i = 0; i < n; i++){ - a.push(rand1d(n)); - } + var a = []; + for (var i = 0; i < n; i++){ + a.push(rand1d(n)); + } - return a; + return a; - } + } - it('can solve complex case', function(){ + it('can solve complex case', () => { - var n = 5; - var A = rand2d(n); - var At = verb.core.Mat.transpose(A); - var b = rand1d(n); + 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 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) ); + 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 ); + vecShouldBe( b, s ); - }); + }); }); -describe("verb.core.Mesh.makeMeshAabb",function(){ - - it('should return correct result for planar mesh', function(){ - - // - // 0 - 1 - // | / \ - // 2 -- 3 - // | \ / - // 4 - 5 - // +describe("verb.core.Mesh.makeMeshAabb", () => { - 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); + it('should return correct result for planar mesh', () => { - 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] ); + // + // 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); - it('makeMeshAabb should return correct result for non-planar mesh', function(){ + 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] ); - // - // 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] ); + it('makeMeshAabb should return correct result for non-planar mesh', () => { + + // + // 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(){ +describe("verb.core.Mesh.getTriangleCentroid", () => { - it('should return origin for zeroed triangle', function(){ + it('should return origin for zeroed triangle', () => { - var points = [[0,0,0],[0,0,0],[0,0,0]] - , tri = [0,1,2] - , centroid = verb.core.Mesh.getTriangleCentroid( points, tri ); + 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] ); + should.equal( 0, centroid[0] ); + should.equal( 0, centroid[1] ); + should.equal( 0, centroid[2] ); - }); + }); - it('should return correct value', function(){ + it('should return correct value', () => { - var points = [[5,10,2],[3,-4,5],[-10,-3, 10]] - , tri = [0,1,2] - , centroid = verb.core.Mesh.getTriangleCentroid( points, tri ); + 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] ); + should.equal( -2/3, centroid[0] ); + should.equal( 1, centroid[1] ); + should.equal( 17/3, centroid[2] ); - }); + }); }); -describe("verb.eval.Eval.getMinCoordOnAxis",function(){ +describe("verb.eval.Eval.getMinCoordOnAxis", () => { - it('should return correct value', function(){ + it('should return correct value', () => { - 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 ); + 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 ); + should.equal( -10, a1 ); + should.equal( -4, a2 ); + should.equal( 2, a3 ); - }); + }); }); -describe("verb.core.Mesh.sortTrianglesOnLongestAxis",function(){ +describe("verb.core.Mesh.sortTrianglesOnLongestAxis", () => { - it('should return correct result with y axis regular array', function(){ + it('should return correct result with y axis regular array', () => { - // - // 0 - 1 - // | 0 / 3 \ - // 2 -- 3 - // | 1 \ 2 / - // 4 - 5 - // + // + // 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 ); + 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 ]) + sort_tri_indices.should.eql([ 1, 2, 3, 0 ]) - }); + }); - it('should return correct result', function(){ + it('should return correct result', () => { - 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 ); + 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 ]) - }); + sort_tri_indices.should.eql([ 1, 0, 2 ]) + }); }); -describe("verb.core.KdTree",function(){ +describe("verb.core.KdTree", () => { - 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" ) - ]; + 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(){ + it('gives correct results when requesting a single node', () => { - var tree = new verb.core.KdTree(pts, verb.core.Vec.distSquared ); - var res = tree.nearest( [0,2.1,1], 1, 1.0 ); + 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); + res[0].item0.point.should.eql(pts[1].point); - }); + }); - it('gives correct results for multiple nodes', function(){ + it('gives correct results for multiple nodes', () => { - var tree = new verb.core.KdTree(pts, verb.core.Vec.distSquared ); - var res1 = tree.nearest( [0,1.1,1], 2, 1.0 ); + 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); + 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(){ +describe("verb.core.Mesh.triangleUVFromPoint", () => { - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { - 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 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 ); + 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 ); + 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.sortedSetUnion", () => { + it('can merge two empty arrays', () => { + verb.core.Vec.sortedSetUnion([],[]).should.be.eql([]); + }); + + it('can merge array and empty array', () => { + 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', () => { + verb.core.Vec.sortedSetUnion([1,2],[1,2]).should.be.eql([1,2]); + }); + + it('can merge two differing arrays', () => { + 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(){ +describe("verb.core.Vec.sortedSetSub", () => { - it('can handle two empty arrays', function(){ - verb.core.Vec.sortedSetSub([],[]).should.be.eql([]); - }); + it('can handle two empty arrays', () => { + 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 empty array from non-empty array', () => { + 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 identical arrays', () => { + 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([]); - }); + it('can subtract two non-equal arrays', () => { + 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(){ +describe("verb.core.Mat.mult", () => { + it('works for a few basic cases', () => { var mat = [[1,2], [2,3]]; verb.core.Mat.mult( verb.core.Mat.identity(2), mat ).should.eql( mat ); diff --git a/test/testEval.js b/test/testEval.js index 0913a8eb..e827bbe9 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -1,5 +1,5 @@ var should = require('should') - , verb = require('../build/js/verb.js'); + , verb = require('../build/js/verb.js'); // necessary for multi-threading verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/"; @@ -7,642 +7,631 @@ verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/"; // some testing utilities function vecShouldBe( expected, test, tol ){ - if (tol === undefined) tol = verb.core.Constants.TOLERANCE; + if (tol === undefined) tol = verb.core.Constants.TOLERANCE; - test.length.should.be.equal( expected.length ); + test.length.should.be.equal( expected.length ); - for (var i = 0; i < test.length; i++){ - test[i].should.be.approximately( expected[i], tol ); - } + for (var i = 0; i < test.length; i++){ + test[i].should.be.approximately( expected[i], tol ); + } } function last(a){ - return a[a.length-1]; + return a[a.length-1]; } +/* + describe("verb.eval.Eval.knotSpanGivenN",function(){ - it('returns correct result', function(){ + it('returns correct result', () => { - var n = 7 - , degree = 2 - , knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]; + 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 ) ); + 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(){ +describe("verb.eval.Eval.knotSpan",() => { - it('returns correct result for degree 2 curve', function(){ + it('returns correct result for degree 2 curve', () => { - var degree = 2 - , knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]; + 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 + 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(){ +describe("verb.eval.Eval.basisFunctions, basisFunctionsGivenKnotSpanIndex",() => { - it('return correct results', function(){ + it('return correct results', () => { - var degree = 2 - , span = 4 - , knots = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]; + 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 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] ); + 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(){ +describe("verb.eval.Eval.curvePoint",() => { - it('returns correct result for simple curve', function(){ + it('returns correct result for simple curve', () => { - 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 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); + var p = verb.eval.Eval.curvePointGivenN( n, crv, 2.5); - should.equal( p[0], 40 ); - should.equal( p[1], 30 ); + should.equal( p[0], 40 ); + should.equal( p[1], 30 ); - var p_start = verb.eval.Eval.curvePointGivenN( n, crv, 0); + var p_start = verb.eval.Eval.curvePointGivenN( n, crv, 0); - should.equal( p_start[0], 10 ); - should.equal( p_start[1], 0 ); + should.equal( p_start[0], 10 ); + should.equal( p_start[1], 0 ); - var p_end = verb.eval.Eval.curvePointGivenN( n, crv, 5); + var p_end = verb.eval.Eval.curvePointGivenN( n, crv, 5); - should.equal( p_end[0], 70 ); - should.equal( p_end[1], 80 ); + should.equal( p_end[0], 70 ); + should.equal( p_end[1], 80 ); - }); + }); }); -describe("verb.eval.Eval.curvePointGivenN",function(){ +describe("verb.eval.Eval.curvePointGivenN",() => { - it('returns correct result for simple curve', function(){ + it('returns correct result for simple curve', () => { - 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 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); + var p = verb.eval.Eval.curvePoint( crv, u); - should.equal( p[0], 10 ); - should.equal( p[1], 0 ); + should.equal( p[0], 10 ); + should.equal( p[1], 0 ); - var p2 = verb.eval.Eval.curvePoint( crv, 1.0); + var p2 = verb.eval.Eval.curvePoint( crv, 1.0); - should.equal( p2[0], 50 ); - should.equal( p2[1], 50 ); + should.equal( p2[0], 50 ); + should.equal( p2[1], 50 ); - }); + }); }); -describe("verb.eval.Eval.areValidRelations",function(){ +describe("verb.eval.Eval.areValidRelations",() => { - it('returns correct result for two cases', function(){ + it('returns correct result for two cases', () => { - should.equal( false, verb.eval.Eval.areValidRelations( 0, 0, 0 ) ); - should.equal( true, verb.eval.Eval.areValidRelations( 2, 2, 5 ) ); + 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.derivativeBasisFunctionsGivenNI",() => { -describe("verb.eval.Eval.curveDerivativesGivenN",function(){ + it('returns correct results', () => { - it('returns correct result for simple curve', 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 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 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] ); - var p = verb.eval.Eval.curveDerivativesGivenN( n, crv, u, num_derivs ) ; + // 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] ); - should.equal( p[0][0], 10 ); - should.equal( p[0][1], 0 ); - should.equal( p[1][0] / p[1][1], 1 ); + // length + should.equal( n + 1, N1.length ); + should.equal( degree + 1, N1[0].length ); - }); + }); }); -describe("verb.eval.Eval.curveDerivatives",function(){ - - it('returns correct result for simple curve', function(){ +describe("verb.eval.Eval.curveDerivativesGivenN",() => { - // 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 ); + it('returns correct result for simple curve', () => { - var p = verb.eval.Eval.curveDerivatives( crv, u, num_derivs ) ; + 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 ); - should.equal( p[0][0], 10 ); - should.equal( p[0][1], 0 ); - should.equal( p[1][0] / p[1][1], 1 ); + 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.surfacePointGivenNM",function(){ - - it('returns correct result for simple surface', function(){ +describe("verb.eval.Eval.curveDerivatives",() => { - // 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; + it('returns correct result for simple curve', () => { - var p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 0, 0 ); + // 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 ); - should.equal( p[0], 0 ); - should.equal( p[1], 0 ); - should.equal( p[2], 50 ); + var p = verb.eval.Eval.curveDerivatives( crv, u, num_derivs ) ; - p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 1, 1 ); + should.equal( p[0][0], 10 ); + should.equal( p[0][1], 0 ); + should.equal( p[1][0] / p[1][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 ); +describe("verb.eval.Eval.surfacePointGivenNM",() => { - var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); + it('returns correct result for simple surface', () => { - 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 ); - - }); + // 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; - it('returns correct result for another simple surface', function(){ + var p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 0, 0 ); - 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 ); + should.equal( p[0], 0 ); + should.equal( p[1], 0 ); + should.equal( p[2], 50 ); - var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); + p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 1, 1 ); - should.equal( p[0], 0 ); - should.equal( p[1], 0 ); - should.equal( p[2], 50 ); + should.equal( p[0], 30 ); + should.equal( p[1], -30 ); + should.equal( p[2], 0 ); - }); + }); }); -describe("verb.eval.Eval.surfaceDerivativesGivenNM",function(){ +describe("verb.eval.Eval.surfacePoint",() => { - it('returns correct derivatives for simple surface', function(){ + it('returns correct result for simple surface', () => { - 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 ); + // 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.surfaceDerivativesGivenNM( n, m, surface, 0, 0, num_derivatives ); + var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); - // 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 ); + should.equal( p[0], 0 ); + should.equal( p[1], 0 ); + should.equal( p[2], 50 ); - // d/du - should.equal( p[0][1][0] / p[0][1][0], 1 ); - should.equal( p[0][1][2], 0 ); + p = verb.eval.Eval.surfacePoint( surface, 1, 1 ); - // d/dv - should.equal( p[1][0][0] , 0 ); - should.equal( p[1][0][1] , -30 ); - should.equal( p[1][0][2] , 0 ); + should.equal( p[0], 30 ); + should.equal( p[1], -30 ); + should.equal( p[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 ); + }); - }); -}); + it('returns correct result for another simple surface', () => { -describe("verb.eval.Eval.surfaceDerivatives",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 ); - it('returns correct derivatives for simple surface', function(){ + var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); - 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 ); + should.equal( p[0], 0 ); + should.equal( p[1], 0 ); + should.equal( p[2], 50 ); - 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 ); +describe("verb.eval.Eval.surfaceDerivativesGivenNM",() => { + + it('returns correct derivatives for simple surface', () => { + + 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 ); - // 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",() => { + + it('returns correct derivatives for simple surface', () => { + + 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(){ +describe("verb.eval.Eval.homogenize1d",() => { - it('returns correct results', function(){ + it('returns correct results', () => { - var weights = [1, 2, 3, 4] - , controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ] - , homo_controlPoints = verb.eval.Eval.homogenize1d( controlPoints, weights); + 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] ); - } + 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); + 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] ); - } + 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.homogenize2d",() => { + + it('homogenize2d', () => { + + 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 = []; +describe("verb.eval.Eval.dehomogenize",() => { + + it('returns correct result', () => { + + 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] ); + } + } - 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(){ +describe("verb.eval.Eval.rationalCurvePoint",() => { - it('returns correct result for quarter circle', function(){ + it('returns correct result for quarter circle', () => { - // 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 ); + // 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); + var p = verb.eval.Eval.rationalCurvePoint( crv, 0); - should.equal( p[0], 1 ); - should.equal( p[1], 0 ); + should.equal( p[0], 1 ); + should.equal( p[1], 0 ); - p = verb.eval.Eval.rationalCurvePoint( crv, 0.5); + p = verb.eval.Eval.rationalCurvePoint( crv, 0.5); - should.equal( p[0], 0.6 ); - should.equal( p[1], 0.8 ); + should.equal( p[0], 0.6 ); + should.equal( p[1], 0.8 ); - p = verb.eval.Eval.rationalCurvePoint( crv, 1); + p = verb.eval.Eval.rationalCurvePoint( crv, 1); - should.equal( p[0], 0 ); - should.equal( p[1], 1 ); + should.equal( p[0], 0 ); + should.equal( p[1], 1 ); - }); + }); }); -describe("verb.eval.Eval.rationalSurfacePoint",function(){ +describe("verb.eval.Eval.rationalSurfacePoint",() => { - it('returns correct result for cylinder patch', function(){ + it('returns correct result for cylinder patch', () => { - // 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 ); + // 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 ); + var p = verb.eval.Eval.rationalSurfacePoint( surface, 0, 0 ); - should.equal( p[0], 1 ); - should.equal( p[1], 1 ); - should.equal( p[2], 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 ); + 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 ); + 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 ); + p = verb.eval.Eval.rationalSurfacePoint( surface, 1, 1 ); - should.equal( p[0], -1 ); - should.equal( p[1], 0 ); - should.equal( p[2], 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 ); +describe("verb.eval.Eval.rationalCurveDerivatives",() => { - it('returns expected results with 2 derivatives', function(){ - var num_derivatives = 2; + it('returns expected results', () => { - var p = verb.eval.Eval.rationalCurveDerivatives( crv, 0, num_derivatives); + // 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 ); - should.equal( p[0][0], 1 ); - should.equal( p[0][1], 0 ); + var p = verb.eval.Eval.rationalCurveDerivatives( crv, 0, 2); - should.equal( p[1][0], 0 ); - should.equal( p[1][1], 2 ); + should.equal( p[0][0], 1 ); + should.equal( p[0][1], 0 ); - should.equal( p[2][0], -4 ); - should.equal( p[2][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[0][0], 0 ); + should.equal( p[0][1], 1 ); - should.equal( p[1][0], -1 ); - should.equal( p[1][1], 0 ); + should.equal( p[1][0], -1 ); + should.equal( p[1][1], 0 ); - should.equal( p[2][0], 1 ); - should.equal( p[2][1], -1 ); + 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",() => { -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', () => { - it('returns expected results with 1 derivative', function(){ - var num_derivatives = 1; + // 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] ] ] + , num_derivatives = 1 + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - var p = verb.eval.Eval.rationalSurfaceDerivatives( surface, 0, 0, num_derivatives ); + 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][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[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 ); + 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); + 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][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[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 ); + 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; @@ -676,2996 +665,2843 @@ describe("verb.eval.Eval.rationalSurfaceDerivatives",function(){ should.equal( p[2][0][2], 0 ); }); + }); -describe("verb.eval.Eval.rationalCurvePoint",function(){ +describe("verb.eval.Eval.rationalCurvePoint",() => { - it('returns correct results for a line', function(){ + it('returns correct results for a line', () => { - 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 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); + 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); + should.equal(p1[0], 0); + should.equal(p2[0], 5); + should.equal(p3[0], 10); - }); + }); }); -describe("verb.eval.Modify.curveKnotInsert",function(){ +describe("verb.eval.Modify.curveKnotInsert",() => { - it('returns expected results when inserting 1 knot in the middle of a non-rational, cubic b-spline', function(){ + it('returns expected results when inserting 1 knot in the middle of a non-rational, cubic b-spline', () => { - var degree = 3 - , u = 2.5 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ] - , r = 1; + 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 controlPoints = []; + for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0]); - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var after = verb.eval.Modify.curveKnotInsert( crv, u, r ); + 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); }); + 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); + 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 ); + 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); + 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); + 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(){ + it('returns expected results when inserting 3 knots at the middle of a non-rational, cubic b-spline', () => { - var degree = 3 - , u = 2.5 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ] - , r = 3; + 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 controlPoints = []; + for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0]); - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var after = verb.eval.Modify.curveKnotInsert( crv, u, r ); + 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); }); + 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); + 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); + 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); + 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(){ + it('returns expected results when inserting 1 knots at the beginning of a non-rational, cubic b-spline', () => { - var degree = 3 - , u = 0.5 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ] - , r = 1; + 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 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 ); + 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); }); + 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); + 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); + 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); + 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(){ + it('returns expected results when inserting 1 knot at the middle of a non-rational, linear b-spline', () => { - var degree = 1 - , u = 0.5 - , knots = [ 0, 0, 1, 2, 3, 4, 5, 5 ] - , r = 1; + 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 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 ); + 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); }); + 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); + 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); + 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); + 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){ +describe("verb.eval.Divide.curveSplit",() => { - var degree = 3 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ] - , new_knots = []; + function cubicSplit(u){ - for (var i = 0; i < r; i++){ - new_knots.push(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]); + 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.Modify.curveKnotRefine( crv, new_knots ); + var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var after = verb.eval.Divide.curveSplit( crv, u ); - after.controlPoints.forEach(function(cp){ should.exist(cp); }); - after.knots.forEach(function(cp){ should.exist(cp); }); + 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); + } - should.equal(knots.length + r, after.knots.length); - should.equal(controlPoints.length + r, after.controlPoints.length); + for (var i = 0; i < degree + 1; i++){ + var d = 0; + after[1].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE); + } - var p0 = verb.eval.Eval.curvePoint( crv, 2.5); - var p1 = verb.eval.Eval.curvePoint( after, 2.5); + // 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); + 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(){ + it('returns expected results when splitting a non-rational, cubic b-spline', () => { - cubicInsert(2.5, 1); - cubicInsert(2.5, 2); - cubicInsert(2.5, 3); - cubicInsert(2.5, 4); + cubicSplit( 0.5 ); + cubicSplit( 3.5 ); - 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.Analyze.knotMultiplicities",() => { -}); + it('is correct for a basic example', () => { -describe("verb.eval.Divide.curveSplit",function(){ + var res = verb.eval.Analyze.knotMultiplicities( [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3] ); - function cubicSplit(u){ + res.length.should.be.equal( 5 ); - var degree = 3 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]; + res[0].knot.should.be.equal( 0 ); + res[0].mult.should.be.equal( 4 ); - var controlPoints = []; - for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0, 1]); + res[1].knot.should.be.equal( 1 ); + res[1].mult.should.be.equal( 2 ); - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var after = verb.eval.Divide.curveSplit( crv, u ); + res[2].knot.should.be.equal( 2 ); + res[2].mult.should.be.equal( 3 ); - 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); - } + res[3].knot.should.be.equal( 3 ); + res[3].mult.should.be.equal( 1 ); - for (var i = 0; i < degree + 1; i++){ - var d = 0; - after[1].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE); - } + res[4].knot.should.be.equal( 3.3 ); + res[4].mult.should.be.equal( 1 ); - // 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); +describe("verb.core.Mat.transpose",() => { + it('is correct for a basic example', () => { + var a = [ [6,5,4], [1,2,3] ]; + verb.core.Mat.transpose(a).should.eql( [[6,1], [5,2], [4,3]]) + }); - } - it('returns expected results when splitting a non-rational, cubic b-spline', function(){ + it('is correct for empty array', () => { + verb.core.Mat.transpose([]).should.eql( [] ); + }); +}); - cubicSplit( 0.5 ); - cubicSplit( 3.5 ); - }); +describe("verb.eval.Divide.surfaceSplit", () => { -}); + 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 ); -describe("verb.eval.Analyze.knotMultiplicities",function(){ + it('can split a surface in the u direction', () => { - it('is correct for a basic example', function(){ + var u = 0.2; - var res = verb.eval.Analyze.knotMultiplicities( [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3] ); + var res = verb.eval.Divide.surfaceSplit( surface, u, false ); - res.length.should.be.equal( 5 ); + 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[0].knot.should.be.equal( 0 ); - res[0].mult.should.be.equal( 4 ); + 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 ); - res[1].knot.should.be.equal( 1 ); - res[1].mult.should.be.equal( 2 ); + var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); + var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); - res[2].knot.should.be.equal( 2 ); - res[2].mult.should.be.equal( 3 ); + 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); - res[3].knot.should.be.equal( 3 ); - res[3].mult.should.be.equal( 1 ); + p0 = verb.eval.Eval.surfacePoint( surface, 0.8, 0.8 ); + p1 = verb.eval.Eval.surfacePoint( res[1], 0.8, 0.8); - res[4].knot.should.be.equal( 3.3 ); - res[4].mult.should.be.equal( 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); - }); -}); -describe("verb.eval.Modify.decomposeCurveIntoBeziers",function(){ + }); - it('is correct for a basic example', function(){ + it('can split a surface in the v direction', () => { - var degree = 3 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]; + var u = 0.2; - var controlPoints = []; - for (var i = 0; i < 8; i++) { - controlPoints.push([i, 0, 0]); - } + var res = verb.eval.Divide.surfaceSplit( surface, u, true ); - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var res = verb.eval.Modify.decomposeCurveIntoBeziers( crv ); + 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.length.should.be.equal( 5 ); + 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 ); - res.forEach(function(x){ + var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); + var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); - var u0 = x.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); - var pt0 = verb.eval.Eval.curvePoint( x, u0); - var pt1 = verb.eval.Eval.curvePoint( crv, u0); + p0 = verb.eval.Eval.surfacePoint( surface, 0.8, 0.8 ); + p1 = verb.eval.Eval.surfacePoint( res[1], 0.8, 0.8); - ( verb.core.Vec.norm(verb.core.Vec.sub(pt0, pt1))).should.be.approximately(0, verb.core.Constants.TOLERANCE ); + 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.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]]) - }); +describe("verb.eval.Eval.rationalCurveRegularSample",() => { + it('should return 11 samples when asked to', () => { + 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 ); - it('is correct for empty array', function(){ - verb.core.Mat.transpose([]).should.eql( [] ); - }); -}); + var p = verb.eval.Tess.rationalCurveRegularSample( curve, numSamples); -describe("verb.eval.Modify.surfaceKnotRefine",function(){ + should.equal(p.length, 11); - 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 ); + p.map( function(e){ e.length.should.be.equal(3); }); - it('can add knots into a surface in the u direction', function(){ + }); +}); - var r = 1; - var u = 0.2; - var new_knots = []; +describe("verb.eval.Eval.threePointsAreFlat",() => { - for (var i = 0; i < r; i++){ - new_knots.push(u); - } + it('should identify flat line by returning true', () => { - var res = verb.eval.Modify.surfaceKnotRefine( surface, new_knots, false ); + // this represents a single quarter arc, using a rational bezier curve + var p1 = [0,0,0], + p2 = [0,2,0], + p3 = [0,4,0]; - 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(true, verb.core.Trig.threePointsAreFlat(p1,p2,p3,1e-5)); - 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); +describe("verb.eval.Tess.rationalCurveAdaptiveSample",() => { - }); + it('returns two end points for a line', () => { - it('can add knots into a surface in the v direction', 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 r = 1; - var u = 0.2; - var new_knots = []; + var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5); - for (var i = 0; i < r; i++){ - new_knots.push(u); - } + should.equal(p[0][0], 0); + should.equal(p[1][0], 10); - var res = verb.eval.Modify.surfaceKnotRefine( surface, new_knots, true ); + p.map( function(e){ e.length.should.be.equal(3); }); - 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); + it('returns all the control points for a degree 1 curve', () => { - var p0 = verb.eval.Eval.surfacePoint( surface, 0.5, 0.25 ); - var p1 = verb.eval.Eval.surfacePoint( res, 0.5, 0.25); + 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 ); - 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); + 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); }); -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('makes more points for an arc', () => { - it('can split a surface in the u direction', 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 u = 0.2; + var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-8, true); + var p2 = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-4, true); - var res = verb.eval.Divide.surfaceSplit( surface, u, false ); + var prev = - 1e-8; + for (var i = 0; i < p.length; i++){ + p[i][3].should.be.above(prev); + p[i][3].should.be.within(-1e-8, 1 + 1e-8); + prev = p[i][3]; + } - 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 ); + 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); - 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 ); + p[p.length-1][3].should.be.approximately(1.0, 1e-6); + p2[p2.length-1][3].should.be.approximately(1.0, 1e-6); - var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); - var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); + p.map( function(e){ e.length.should.be.equal(4); }); + p2.map( function(e){ e.length.should.be.equal(4); }); - 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.Tess.rationalSurfaceAdaptive",() => { + 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] ]; - it('can split a surface in the v direction', function(){ + pts = verb.eval.Eval.homogenize2d(pts, wts); - var u = 0.2; + var srfObj = { + degreeU : degree, + degreeV : degree, + knotsU : knots, + knotsV : knots, + controlPoints : pts + }; - var res = verb.eval.Divide.surfaceSplit( surface, u, true ); + return srfObj; + } - 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 ); + it('produces a mesh from a divided surface', () => { - 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 srf = getComplexSurface(); - var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); - var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); + var mesh = verb.eval.Tess.rationalSurfaceAdaptive( srf, { minDivsU: 1, minDivsV: 4 } ); - 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); + 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 ); - 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.Make.ellipseArc",() => { + it('returns correct result for unit arc from 0 to 90 deg', () => { - }); + 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 ); -describe("verb.eval.Eval.rationalCurveRegularSample",function(){ - it('should return 10 samples when asked to', function(){ + var p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5); - 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 ); + 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 ); - var p = verb.eval.Tess.rationalCurveRegularSample( curve, numSamples); + p = verb.eval.Eval.rationalCurvePoint( ellipse, 1); - should.equal(p.length, 10); + 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.map( function(e){ e.length.should.be.equal(3); }); + 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.Eval.threePointsAreFlat",function(){ + }); - it('should identify flat line by returning true', function(){ + it('returns correct result for unit arc from 0 to 90 deg', () => { - // this represents a single quarter arc, using a rational bezier curve - var p1 = [0,0,0], - p2 = [0,2,0], - p3 = [0,4,0]; + var center = [0,0,0] + , rx = 5 + , ry = 1 + , x = [rx,0,0] + , y = [0,ry,0] + , start = 0 + , end = Math.PI / 2; - should.equal(true, verb.core.Trig.threePointsAreFlat(p1,p2,p3,1e-5)); + 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 ); -describe("verb.eval.Tess.rationalCurveAdaptiveSample",function(){ + }); - it('returns two end points for a line', function(){ + it('returns correct result for unit arc from 45 to 135 deg', () => { - 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 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 p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5); + var arc = verb.eval.Make.ellipseArc(center, x, y, start, end); - should.equal(p[0][0], 0); - should.equal(p[1][0], 10); + var p = verb.eval.Eval.rationalCurvePoint( arc, 1); - p.map( function(e){ e.length.should.be.equal(3); }); + // 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 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 ); + it('returns correct result for complete ellipse', () => { - var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5); + var center = [0,0,0] + , rx = 1 + , ry = 10 + , x = [rx,0,0] + , y = [0,ry,0] + , start = 0 + , end = Math.PI * 2; - 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]); + var ellipse = verb.eval.Make.ellipseArc(center, x, y, start, end); - p.map( function(e){ e.length.should.be.equal(3); }); + // 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); - it('makes more points for an arc', function(){ + 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 ); - 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 ); + p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.25); - var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-8, true); - var p2 = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-4, true); + 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 ); - 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 = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5); - 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); + 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 ); - should.equal(p[p.length-1][0], 1.0); - should.equal(p2[p2.length-1][0], 1.0); + p = verb.eval.Eval.rationalCurvePoint( ellipse, 0); - p.map( function(e){ e.length.should.be.equal(4); }); - p2.map( function(e){ e.length.should.be.equal(4); }); + 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",() => { -describe("verb.eval.Tess.rationalSurfaceAdaptive",function(){ + it('can extrude a line into a plane', () => { - function getComplexSurface(){ + 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 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] ]; + var comps = verb.eval.Make.extrudedSurface(axis, length, profile); - pts = verb.eval.Eval.homogenize2d(pts, wts); + // 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] ); - var srfObj = { - degreeU : degree, - degreeV : degree, - knotsU : knots, - knotsV : knots, - controlPoints : pts - }; + should.equal( 1, comps.controlPoints[2][1][0] ); + should.equal( 0, comps.controlPoints[2][1][1] ); + should.equal( 0, comps.controlPoints[2][1][2] ); - return srfObj; - } + // sample at the center + var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5); - it('produces a mesh from a divided surface', function(){ + 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 ); - var srf = getComplexSurface(); + }); - var mesh = verb.eval.Tess.rationalSurfaceAdaptive( srf, { minDivsU: 1, minDivsV: 4 } ); + it('can extrude a 90 deg quadratic arc bezier curve', () => { - 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 ); + 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); -describe("verb.eval.Make.ellipseArc",function(){ + // 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] ); - it('returns correct result for unit arc from 0 to 90 deg', function(){ + 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] ); - var center = [0,0,0] - , rx = 5 - , ry = 1 - , x = [rx,0,0] - , y = [0,ry,0] - , start = 0 - , end = Math.PI/2; + 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] ); - var ellipse = verb.eval.Make.ellipseArc(center, x, y, start, end); + // sample at the center + var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5); - // the typical parametric rep of an ellipse - var xmid = rx * Math.cos( Math.PI / 4 ) - , ymid = ry * Math.sin( Math.PI / 4 ); + 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 ); - 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); +describe("verb.eval.Make.arc",() => { - 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 0 to 90 deg', () => { - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0); + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = 0 + , end = Math.PI/2; - 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 ); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - }); + var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); - it('returns correct result for unit arc from 0 to 90 deg', function(){ + 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 ); - 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); + it('returns correct result for unit arc from 0 to 45 deg', () => { - var p = verb.eval.Eval.rationalCurvePoint( arc, 1); + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = 0 + , end = Math.PI/4; - 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 ); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - }); + var p = verb.eval.Eval.rationalCurvePoint( arc, 1); - it('returns correct result for unit arc from 45 to 135 deg', function(){ + 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 ); - 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); + it('returns correct result for unit arc from 45 to 135 deg', () => { - var p = verb.eval.Eval.rationalCurvePoint( arc, 1); + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = Math.PI/4 + , end = 3 * Math.PI/4; - // the typical parametric rep of an ellipse - var xmid = rx * Math.cos( 3 * Math.PI / 4 ) - , ymid = ry * Math.sin( 3 * Math.PI / 4 ); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - 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 ); + 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 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; + it('returns correct result for unit circle', () => { - var ellipse = verb.eval.Make.ellipseArc(center, x, y, start, end); + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 5 + , start = 0 + , end = Math.PI; - // the typical parametric rep of an ellipse - var xmid = rx * Math.cos( Math.PI / 4 ) - , ymid = ry * Math.sin( Math.PI / 4 ); + var arc = verb.eval.Make.arc(center, x, y, r, start, end); - var p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.125); + var p = verb.eval.Eval.rationalCurvePoint( arc, 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[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 ); - 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 ); + it('returns correct result for unit circle', () => { - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5); + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = 0 + , end = Math.PI * 2; - 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 ); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0); + var p = verb.eval.Eval.rationalCurvePoint( arc, 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 ); + 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 ); - }); + }); }); -describe("verb.eval.Make.extrudedSurface",function(){ +describe("verb.eval.Make.polyline",() => { - it('can extrude a line into a plane', function(){ + it('can create a polyline with correct structure', () => { - 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 degree = 1 + , knots = [0, 0, 0.25, 0.5, 0.75, 1, 1] + , controlPoints = [ [0, 0, 0], [10, 10, 0], [14, 20, 0], [10, 32, 4], [12, 16, 22] ] + , weights = [1, 1, 1, 1, 1]; - var comps = verb.eval.Make.extrudedSurface(axis, length, profile); + var comps = verb.eval.Make.polyline( controlPoints ); - // 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] ); + comps.degree.should.equal(degree); + comps.controlPoints.should.eql( verb.eval.Eval.homogenize1d( controlPoints, weights )); - should.equal( 1, comps.controlPoints[2][1][0] ); - should.equal( 0, comps.controlPoints[2][1][1] ); - should.equal( 0, comps.controlPoints[2][1][2] ); + // natural parameterization + for (var i = 1; i < knots.length-1; i++){ + vecShouldBe( controlPoints[i-1], verb.eval.Eval.rationalCurvePoint(comps, comps.knots[i] ) ); + } - // 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(){ +describe("verb.eval.Make.cylindricalSurface",() => { - 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) ); + it('can create a cylinder', () => { - var comps = verb.eval.Make.extrudedSurface(axis, length, profile); + var axis = [0,0,1] + , xaxis = [1,0,0] + , base = [0,0,0] + , height = 5 + , radius = 5; - // 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] ); + var comps = verb.eval.Make.cylindricalSurface(axis, xaxis, base, height, radius); - 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] ); + comps.degreeU.should.equal(2); + comps.degreeV.should.equal(2); - 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); - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5); + p[0].should.be.approximately(-radius, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(radius/2, verb.core.Constants.EPSILON); - 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 ); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 0); - }); + p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(height, verb.core.Constants.EPSILON); -}); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 1, + 0); -describe("verb.eval.Make.arc",function(){ + p[0].should.be.approximately(radius, 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(){ + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 1); - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = 0 - , end = Math.PI/2; + p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(height, verb.core.Constants.EPSILON); - 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 ); +describe("verb.eval.Make.revolvedSurface",() => { - }); + it('creates a 90 degree cone with the given line for a profile', () => { - it('returns correct result for unit arc from 0 to 45 deg', function(){ + var axis = [0,0,1] + , center = [0,0,0] + , angle = Math.PI/2 + , prof_degree = 1 + , prof_ctrl_pts = [[0,0,1,1], [1,0,0,1]] + , prof_knots = [0,0,1,1] + , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = 0 - , end = Math.PI/4; + var comps = verb.eval.Make.revolvedSurface(profile, center, axis, angle ); - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + // the first row are the profile control pts + should.equal( 0, comps.controlPoints[0][0][0] ); + should.equal( 0, comps.controlPoints[0][0][1] ); + should.equal( 1, comps.controlPoints[0][0][2] ); + should.equal( 1, comps.controlPoints[0][0][3] ); - var p = verb.eval.Eval.rationalCurvePoint( arc, 1); + should.equal( 1, comps.controlPoints[0][1][0] ); + should.equal( 0, comps.controlPoints[0][1][1] ); + should.equal( 0, comps.controlPoints[0][1][2] ); + should.equal( 1, comps.controlPoints[0][1][3] ); - 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 ); + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 0.5); - }); + should.equal( Math.abs( Math.sqrt(2)/4 - p[0]) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( Math.sqrt(2)/4 - p[1]) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( 0.5 - p[2]) < verb.core.Constants.EPSILON, true ); - 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; + it('creates a 180 degree cone with the given line for a profile', () => { - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + var axis = [0,0,1] + , center = [0,0,0] + , angle = Math.PI + , prof_degree = 1 + , prof_ctrl_pts = [[0,0,1,1], [1,0,0,1]] + , prof_knots = [0,0,1,1] + , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); - var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); + var comps = verb.eval.Make.revolvedSurface( profile, center, axis, angle ); - 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 ); + // the first row are the profile control pts + should.equal( 0, comps.controlPoints[0][0][0] ); + should.equal( 0, comps.controlPoints[0][0][1] ); + should.equal( 1, comps.controlPoints[0][0][2] ); + should.equal( 1, comps.controlPoints[0][0][2] ); - }); + should.equal( 1, comps.controlPoints[0][1][0] ); + should.equal( 0, comps.controlPoints[0][1][1] ); + should.equal( 0, comps.controlPoints[0][1][2] ); + should.equal( 0, comps.controlPoints[0][1][2] ); - it('returns correct result for unit circle', function(){ + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 0.5); - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 5 - , start = 0 - , end = Math.PI; + should.equal( p[0] < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( 0.5 - p[1]) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( 0.5 - p[2]) < verb.core.Constants.EPSILON, true ); - 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('creates a 360 degree cone with the given line for a profile', () => { - }); + var axis = [0,0,1] + , center = [0,0,0] + , angle = Math.PI * 2 + , prof_degree = 1 + , prof_ctrl_pts = [[0,0,1,1], [1,0,0,1]] + , prof_knots = [0,0,1,1] + , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); - it('returns correct result for unit circle', function(){ + var comps = verb.eval.Make.revolvedSurface( profile, center, axis, angle ); - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = 0 - , end = Math.PI * 2; + // the first row are the profile control pts + should.equal( 0, comps.controlPoints[0][0][0] ); + should.equal( 0, comps.controlPoints[0][0][1] ); + should.equal( 1, comps.controlPoints[0][0][2] ); + should.equal( 1, comps.controlPoints[0][0][3] ); - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + should.equal( 1, comps.controlPoints[0][1][0] ); + should.equal( 0, comps.controlPoints[0][1][1] ); + should.equal( 0, comps.controlPoints[0][1][2] ); + should.equal( 1, comps.controlPoints[0][1][3] ); - var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 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 ); + p[0].should.be.approximately(-0.5, verb.core.Constants.EPSILON ); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON ); + p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - }); + }); }); -describe("verb.eval.Make.polyline",function(){ +describe("verb.core.Trig.rayClosestPoint",() => { - it('can create a polyline with correct structure', function(){ + it('returns correct result for xaxis and 3d pt', () => { - var degree = 1 - , knots = [0, 0, 0.25, 0.5, 0.75, 1, 1] - , controlPoints = [ [0, 0, 0], [10, 10, 0], [14, 20, 0], [10, 32, 4], [12, 16, 22] ] - , weights = [1, 1, 1, 1, 1]; + var r = [1,0,0] + , o = [0,0,0] + , pt = [3,4,-1]; - var comps = verb.eval.Make.polyline( controlPoints ); + var proj = verb.core.Trig.rayClosestPoint(pt, o, r); - comps.degree.should.equal(degree); - comps.controlPoints.should.eql( verb.eval.Eval.homogenize1d( controlPoints, weights )); + should.equal( Math.abs( proj[0] - 3 ) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( proj[1] ) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( proj[2] ) < verb.core.Constants.EPSILON, true ); - // natural parameterization - for (var i = 1; i < knots.length-1; i++){ - vecShouldBe( controlPoints[i-1], verb.eval.Eval.rationalCurvePoint(comps, comps.knots[i] ) ); - } - - }); + }); }); -describe("verb.eval.Make.cylindricalSurface",function(){ +describe("verb.core.Trig.distToRay",() => { - it('can create a cylinder', function(){ + it('returns correct result for xaxis and 3d pt', () => { - var axis = [0,0,1] - , xaxis = [1,0,0] - , base = [0,0,0] - , height = 5 - , radius = 5; + var r = [1,0,0] + , o = [0,0,0] + , pt = [3,4,-1]; - var comps = verb.eval.Make.cylindricalSurface(axis, xaxis, base, height, radius); + var d = verb.core.Trig.distToRay(pt, o, r); - comps.degreeU.should.equal(2); - comps.degreeV.should.equal(2); + d.should.be.approximately( Math.sqrt( 17 ), verb.core.Constants.TOLERANCE ); - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5); + }); - p[0].should.be.approximately(-radius, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(radius/2, verb.core.Constants.EPSILON); +}); - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 0); +describe("verb.eval.Make.conicalSurface",() => { - p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(height, verb.core.Constants.EPSILON); + it('can create a cone', () => { - p = verb.eval.Eval.rationalSurfacePoint( comps, - 1, - 0); + var axis = [0,0,1] + , xaxis = [1,0,0] + , base = [0,0,0] + , height = 5 + , radius = 10; - p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(0, verb.core.Constants.EPSILON); + var comps = verb.eval.Make.conicalSurface(axis, xaxis, base, height, radius); - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 1); + comps.degreeU.should.equal(2); + comps.degreeV.should.equal(1); - p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(height, verb.core.Constants.EPSILON); + // sample at the center + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 0.5); - }); + p[0].should.be.approximately(-radius/2, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(height/2, verb.core.Constants.EPSILON); -}); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 0); -describe("verb.eval.Make.revolvedSurface",function(){ + p[0].should.be.approximately(0, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(height, verb.core.Constants.EPSILON); - it('creates a 90 degree cone with the given line for a profile', function(){ + p = verb.eval.Eval.rationalSurfacePoint( comps, + 1, + 0); - var axis = [0,0,1] - , center = [0,0,0] - , angle = Math.PI/2 - , prof_degree = 1 - , prof_ctrl_pts = [[0,0,1,1], [1,0,0,1]] - , prof_knots = [0,0,1,1] - , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); + p[0].should.be.approximately(0, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(height, verb.core.Constants.EPSILON); - var comps = verb.eval.Make.revolvedSurface(profile, center, axis, angle ); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 1); - // the first row are the profile control pts - should.equal( 0, comps.controlPoints[0][0][0] ); - should.equal( 0, comps.controlPoints[0][0][1] ); - should.equal( 1, comps.controlPoints[0][0][2] ); - should.equal( 1, comps.controlPoints[0][0][3] ); + p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON); + p[2].should.be.approximately(0, verb.core.Constants.EPSILON); + }); - should.equal( 1, comps.controlPoints[0][1][0] ); - should.equal( 0, comps.controlPoints[0][1][1] ); - should.equal( 0, comps.controlPoints[0][1][2] ); - should.equal( 1, comps.controlPoints[0][1][3] ); +}); - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); +describe("verb.eval.Make.sphericalSurface",() => { - should.equal( Math.abs( Math.sqrt(2)/4 - p[0]) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( Math.sqrt(2)/4 - p[1]) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( 0.5 - p[2]) < verb.core.Constants.EPSILON, true ); + it('can create a unit sphere', () => { - }); + var center = [0,0,0] + , axis = [0,0,1] + , xaxis = [1,0,0] + , radius = 1; - it('creates a 180 degree cone with the given line for a profile', function(){ + var comps = verb.eval.Make.sphericalSurface(center, axis, xaxis, radius); - var axis = [0,0,1] - , center = [0,0,0] - , angle = Math.PI - , prof_degree = 1 - , prof_ctrl_pts = [[0,0,1,1], [1,0,0,1]] - , prof_knots = [0,0,1,1] - , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); + comps.degreeU.should.equal(2); + comps.degreeV.should.equal(2); - var comps = verb.eval.Make.revolvedSurface( profile, center, axis, angle ); + // sample at the center + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 0.5); - // the first row are the profile control pts - should.equal( 0, comps.controlPoints[0][0][0] ); - should.equal( 0, comps.controlPoints[0][0][1] ); - should.equal( 1, comps.controlPoints[0][0][2] ); - should.equal( 1, comps.controlPoints[0][0][2] ); + p[0].should.be.approximately(-1, verb.core.Constants.EPSILON ); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON ); + p[2].should.be.approximately(0, verb.core.Constants.EPSILON ); - should.equal( 1, comps.controlPoints[0][1][0] ); - should.equal( 0, comps.controlPoints[0][1][1] ); - should.equal( 0, comps.controlPoints[0][1][2] ); - should.equal( 0, comps.controlPoints[0][1][2] ); + }); + +}); - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); - should.equal( p[0] < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( 0.5 - p[1]) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( 0.5 - p[2]) < verb.core.Constants.EPSILON, true ); +describe("verb.eval.Analyze.rationalBezierCurveArcLength",() => { - }); + it('can compute entire arc length of straight cubic bezier parameterized from 0 to 1', () => { + var degree = 3 + , knots = [0,0,0,0,1,1,1,1] + , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [2,0,0,1], [3,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - it('creates a 360 degree cone with the given line for a profile', function(){ + var res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 1 ); - var axis = [0,0,1] - , center = [0,0,0] - , angle = Math.PI * 2 - , prof_degree = 1 - , prof_ctrl_pts = [[0,0,1,1], [1,0,0,1]] - , prof_knots = [0,0,1,1] - , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); + res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); - var comps = verb.eval.Make.revolvedSurface( profile, center, axis, angle ); + }); - // the first row are the profile control pts - should.equal( 0, comps.controlPoints[0][0][0] ); - should.equal( 0, comps.controlPoints[0][0][1] ); - should.equal( 1, comps.controlPoints[0][0][2] ); - should.equal( 1, comps.controlPoints[0][0][3] ); + it('can compute entire arc length of straight cubic bezier parameterized from 1 to 4', () => { - should.equal( 1, comps.controlPoints[0][1][0] ); - should.equal( 0, comps.controlPoints[0][1][1] ); - should.equal( 0, comps.controlPoints[0][1][2] ); - should.equal( 1, comps.controlPoints[0][1][3] ); + var degree = 3 + , knots = [1,1,1,1,4,4,4,4] + , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); + var res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 4 ); - p[0].should.be.approximately(-0.5, verb.core.Constants.EPSILON ); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON ); - p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); - }); + }); }); -describe("verb.core.Trig.rayClosestPoint",function(){ +describe("verb.eval.Analyze.rationalCurveArcLength",() => { - it('returns correct result for xaxis and 3d pt', function(){ + it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { - var r = [1,0,0] - , o = [0,0,0] - , pt = [3,4,-1]; + var degree = 3 + , knots = [0,0,0,0,0.5,2,2,2,2] + , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [1.8,0,0,1], [2,0,0,1], [3,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var proj = verb.core.Trig.rayClosestPoint(pt, o, r); + var u = 0; + var steps = 2; + var inc = (last(knots) - knots[0]) / (steps-1); + for (var i = 0; i < steps; i++){ + var pt = verb.eval.Eval.rationalCurvePoint( curve, u ); + var res2 = verb.eval.Analyze.rationalCurveArcLength( curve, u ); - should.equal( Math.abs( proj[0] - 3 ) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( proj[1] ) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( proj[2] ) < verb.core.Constants.EPSILON, true ); + res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); - }); + u += inc; + } + }); -}); + it('can compute entire arc length of curved nurbs curve parameterized from 0 to 1', () => { -describe("verb.core.Trig.distToRay",function(){ + var degree = 3 + , knots = [0,0,0,0,0.5,1,1,1,1] + , controlPoints = [ [1,1,1,1], [1.5,0,1,1], [1.8,0,0,1], [2,0.1,5,1], [3.1,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - it('returns correct result for xaxis and 3d pt', function(){ + var gaussLen = verb.eval.Analyze.rationalCurveArcLength( curve ); - var r = [1,0,0] - , o = [0,0,0] - , pt = [3,4,-1]; + // sample the curve with 10,000 pts + var samples = verb.eval.Tess.rationalCurveRegularSample( curve, 10000 ); - var d = verb.core.Trig.distToRay(pt, o, r); + var red = samples.reduce(function(acc, v){ + return { pt: v, l : acc.l + verb.core.Vec.norm( verb.core.Vec.sub( acc.pt, v ) ) }; + }, { pt: samples[0], l : 0 }); - d.should.be.approximately( Math.sqrt( 17 ), verb.core.Constants.TOLERANCE ); + gaussLen.should.be.approximately( red.l, 1e-3 ) - }); + }); -}); + it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { -describe("verb.eval.Make.conicalSurface",function(){ + var degree = 3 + , knots = [0,0,0,0,0.5,2,2,2,2] + , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [1.8,0,0,1], [2,0,0,1], [3,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - it('can create a cone', function(){ + var u = 0; + var steps = 10; + var inc = (last(knots) - knots[0]) / (steps-1); + for (var i = 0; i < steps; i++){ - var axis = [0,0,1] - , xaxis = [1,0,0] - , base = [0,0,0] - , height = 5 - , radius = 10; + var pt = verb.eval.Eval.rationalCurvePoint( curve, u ); + var res2 = verb.eval.Analyze.rationalCurveArcLength( curve, u ); - var comps = verb.eval.Make.conicalSurface(axis, xaxis, base, height, radius); + res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); - comps.degreeU.should.equal(2); - comps.degreeV.should.equal(1); + u += inc; + } - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); + }); - p[0].should.be.approximately(-radius/2, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(height/2, verb.core.Constants.EPSILON); +}); - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 0); +describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",() => { - p[0].should.be.approximately(0, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(height, verb.core.Constants.EPSILON); + it('can compute parameter at arc length of straight bezier curve', () => { - p = verb.eval.Eval.rationalSurfacePoint( comps, - 1, - 0); + var degree = 3 + , knots = [0,0,0,0,1,1,1,1] + , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [2,0,0,1], [3,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - p[0].should.be.approximately(0, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(height, verb.core.Constants.EPSILON); + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 3 / (steps-1);; - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 1); + for (var i = 0; i < steps; i++){ - p[0].should.be.approximately(radius, verb.core.Constants.EPSILON); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON); - p[2].should.be.approximately(0, verb.core.Constants.EPSILON); - }); + var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); -}); + len.should.be.approximately( d, tol ); -describe("verb.eval.Make.sphericalSurface",function(){ + d += inc; + } - it('can create a unit sphere', function(){ + }); - var center = [0,0,0] - , axis = [0,0,1] - , xaxis = [1,0,0] - , radius = 1; + it('can compute parameter at arc length of curved bezier curve', () => { - var comps = verb.eval.Make.sphericalSurface(center, axis, xaxis, radius); + var degree = 3 + , knots = [0,0,0,0,1,1,1,1] + , controlPoints = [ [1,0,0,1], [1,0,-1,1], [2,0,0,1], [5,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - comps.degreeU.should.equal(2); - comps.degreeV.should.equal(2); + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 3 / (steps-1); - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); + for (var i = 0; i < steps; i++){ - p[0].should.be.approximately(-1, verb.core.Constants.EPSILON ); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON ); - p[2].should.be.approximately(0, verb.core.Constants.EPSILON ); + var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); - }); + len.should.be.approximately( d, tol ); -}); + d += inc; + } + }); -describe("verb.eval.Analyze.rationalBezierCurveArcLength",function(){ +}); - it('can compute entire arc length of straight cubic bezier parameterized from 0 to 1', function(){ +describe("verb.eval.Analyze.rationalCurveParamAtArcLength",() => { - var degree = 3 - , knots = [0,0,0,0,1,1,1,1] - , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [2,0,0,1], [3,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + it('can compute parameter at arc length of straight NURBS curve', () => { - var res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 1 ); + var degree = 3 + , knots = [0,0,0,0,0.5,1,1,1,1] + , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 4 / (steps-1); - }); + var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, 2, tol); - it('can compute entire arc length of straight cubic bezier parameterized from 1 to 4', function(){ + for (var i = 0; i < steps; i++){ - var degree = 3 - , knots = [1,1,1,1,4,4,4,4] - , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); - var res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 4 ); + len.should.be.approximately( d, tol ); - res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); + d += inc; + } - }); + }); -}); + it('can compute parameter at arc length of curved NURBS curve', () => { -describe("verb.eval.Analyze.rationalCurveArcLength",function(){ + var degree = 3 + , knots = [0,0,0,0,0.5,1,1,1,1] + , controlPoints = [ [1,0,0,1], [1,0,-1,1], [2,0,0,1], [3,0,1,1], [5,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', function(){ + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 3 / (steps-1); - var degree = 3 - , knots = [0,0,0,0,0.5,2,2,2,2] - , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [1.8,0,0,1], [2,0,0,1], [3,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + for (var i = 0; i < steps; i++){ - var u = 0; - var steps = 2; - var inc = (last(knots) - knots[0]) / (steps-1); - for (var i = 0; i < steps; i++){ - var pt = verb.eval.Eval.rationalCurvePoint( curve, u ); - var res2 = verb.eval.Analyze.rationalCurveArcLength( curve, u ); + var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); - res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); + len.should.be.approximately( d, tol ); - u += inc; - } - }); + d += inc; + } - it('can compute entire arc length of curved nurbs curve parameterized from 0 to 1', function(){ + }); - var degree = 3 - , knots = [0,0,0,0,0.5,1,1,1,1] - , controlPoints = [ [1,1,1,1], [1.5,0,1,1], [1.8,0,0,1], [2,0.1,5,1], [3.1,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); +}); - var gaussLen = verb.eval.Analyze.rationalCurveArcLength( curve ); +describe("verb.eval.Divide.rationalCurveByArcLength",() => { - // sample the curve with 10,000 pts - var samples = verb.eval.Tess.rationalCurveRegularSampleRange( curve, 0, 1, 10000 ); + it('can divide a straight NURBS curve', () => { - var red = samples.reduce(function(acc, v){ - return { pt: v, l : acc.l + verb.core.Vec.norm( verb.core.Vec.sub( acc.pt, v ) ) }; - }, { pt: samples[0], l : 0 }); + var degree = 3 + , knots = [0,0,0,0,0.5,1,1,1,1] + , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ) + , d = 0.5 + , tol = 1e-3; - gaussLen.should.be.approximately( red.l, 1e-3 ) + var res = verb.eval.Divide.rationalCurveByArcLength(curve, d); - }); + var s = 0; + res.forEach(function(u){ - it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', function(){ + var pt = verb.eval.Eval.rationalCurvePoint( curve, u.u ); + u.len.should.be.approximately( s, tol ); + s += d; - var degree = 3 - , knots = [0,0,0,0,0.5,2,2,2,2] - , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [1.8,0,0,1], [2,0,0,1], [3,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + }); - var u = 0; - var steps = 10; - var inc = (last(knots) - knots[0]) / (steps-1); - for (var i = 0; i < steps; i++){ + }); - var pt = verb.eval.Eval.rationalCurvePoint( curve, u ); - var res2 = verb.eval.Analyze.rationalCurveArcLength( curve, u ); +}); - res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); +describe("verb.eval.Divide.rationalCurveByEqualArcLength",() => { - u += inc; - } + it('can divide a straight NURBS curve', () => { - }); + var degree = 3 + , knots = [0,0,0,0,0.5,1,1,1,1] + , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ) + , divs = 8 + , tol = 1e-3 + , d = 4 / divs; -}); + var res = verb.eval.Divide.rationalCurveByEqualArcLength(curve, divs ); -describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",function(){ + var s = 0; + res.forEach(function(u){ - it('can compute parameter at arc length of straight bezier curve', function(){ + var pt = verb.eval.Eval.rationalCurvePoint( curve, u.u ); + u.len.should.be.approximately( s, tol ); + s += d; - var degree = 3 - , knots = [0,0,0,0,1,1,1,1] - , controlPoints = [ [0,0,0,1], [1.5,0,0,1], [2,0,0,1], [3,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + }); - var tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 3 / (steps-1);; + }); - for (var i = 0; i < steps; i++){ +}); - var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); +describe("verb.eval.Analyze.rationalCurveClosestParam",() => { - len.should.be.approximately( d, tol ); + it('can get closest point to a straight curve', () => { - d += inc; - } + var degree = 3 + , knots = [0,0,0,0,0.5,1,1,1,1] + , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ) + , pt = [1,0.2,0]; - }); + var res = verb.eval.Analyze.rationalCurveClosestParam(curve, [1,0.2,0] ); + var p = verb.eval.Eval.rationalCurvePoint( curve, res ); - it('can compute parameter at arc length of curved bezier curve', function(){ + vecShouldBe( [1,0,0], p, 1e-3 ); - var degree = 3 - , knots = [0,0,0,0,1,1,1,1] - , controlPoints = [ [1,0,0,1], [1,0,-1,1], [2,0,0,1], [5,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + res = verb.eval.Analyze.rationalCurveClosestParam(curve, [2,0.2,0] ); + p = verb.eval.Eval.rationalCurvePoint( curve, res ); - var tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 3 / (steps-1); + vecShouldBe( [2,0,0], p, 1e-3 ); - for (var i = 0; i < steps; i++){ + // before start + res = verb.eval.Analyze.rationalCurveClosestParam(curve, [-1,0.2,1] ); + p = verb.eval.Eval.rationalCurvePoint( curve, res ); - var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); + vecShouldBe( [0,0,0], p, 1e-3 ); - len.should.be.approximately( d, tol ); + // beyond end + res = verb.eval.Analyze.rationalCurveClosestParam(curve, [5,0.2,0] ); + p = verb.eval.Eval.rationalCurvePoint( curve, res ); - d += inc; - } + vecShouldBe( [4,0,0], p, 1e-3 ); - }); + }); }); -describe("verb.eval.Analyze.rationalCurveParamAtArcLength",function(){ +describe("verb.eval.Analyze.rationalSurfaceClosestParam",() => { - it('can compute parameter at arc length of straight NURBS curve', function(){ + it('can get closest point to flat bezier patch', () => { - var degree = 3 - , knots = [0,0,0,0,0.5,1,1,1,1] - , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + 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, 0, 1], [10, 0, 0, 1], [20, 0, 0, 1], [30, 0, 0, 1] ], + [ [0, -10, 0, 1], [10, -10, 0, 1], [20, -10, 0, 1], [30, -10, 0, 1] ], + [ [0, -20, 0, 1], [10, -20, 0, 1], [20, -20, 0, 1], [30, -20, 0, 1] ], + [ [0, -30, 0, 1], [10, -30, 0, 1], [20, -30, 0, 1], [30, -30, 0, 1] ] ] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ) + , point = [12,-20,5]; + + var res = verb.eval.Analyze.rationalSurfaceClosestParam( surface, point ); + var p = verb.eval.Eval.rationalSurfacePoint( surface, res[0], res[1] ); - var tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 4 / (steps-1); + vecShouldBe( [12,-20,0], p, 1e-3 ); - var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, 2, tol); + }); - for (var i = 0; i < steps; i++){ +}); - var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); +describe("verb.eval.Intersect.segmentWithTriangle",() => { - len.should.be.approximately( d, tol ); + it('gives correct result for intersecting axis aligned segment and triangle ', () => { - d += inc; - } + // line from [5,5,5] to [5,5,-5] + var p0 = [ 5,5,5 ] + , p1 = [ 5,5,-10 ] + , points = [ [0,0,0], [10,0,0], [5,10,1] ] + , tri = [ 0, 1, 2 ]; - }); + var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); - it('can compute parameter at arc length of curved NURBS curve', function(){ + res.p.should.be.approximately(0.3, verb.core.Constants.TOLERANCE); + res.s.should.be.approximately(0.25, verb.core.Constants.TOLERANCE); + res.t.should.be.approximately(0.5, verb.core.Constants.TOLERANCE); - var degree = 3 - , knots = [0,0,0,0,0.5,1,1,1,1] - , controlPoints = [ [1,0,0,1], [1,0,-1,1], [2,0,0,1], [3,0,1,1], [5,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + console.log() - var tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 3 / (steps-1); + var p_srf = verb.core.Vec.add( points[0], + verb.core.Vec.add( verb.core.Vec.mul( res.s, verb.core.Vec.sub(points[1], points[0])), + verb.core.Vec.mul( res.t, verb.core.Vec.sub(points[2], points[0])))); - for (var i = 0; i < steps; i++){ + verb.core.Vec.norm( verb.core.Vec.sub( res.point, p_srf ) ).should.be.approximately(0, verb.core.Constants.TOLERANCE ); - var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); + }); - len.should.be.approximately( d, tol ); + it('gives correct result for intersecting axis aligned segment and planar triangle ', () => { - d += inc; - } + // line from [5,5,5] to [5,5,-5] + var p0 = [ 5,5,5 ] + , p1 = [ 5,5,-10 ] + , points = [ [0,0,0], [10,0,0], [5,10,0] ] + , tri = [ 0, 1, 2 ]; - }); + var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); -}); + res.p.should.be.approximately(0.333333333333, verb.core.Constants.TOLERANCE); + res.s.should.be.approximately(0.25, verb.core.Constants.TOLERANCE); + res.t.should.be.approximately(0.5, verb.core.Constants.TOLERANCE); -describe("verb.eval.Divide.rationalCurveByArcLength",function(){ + var p_srf = verb.core.Vec.add( points[0], + verb.core.Vec.add( verb.core.Vec.mul( res.s, verb.core.Vec.sub(points[1], points[0])), + verb.core.Vec.mul( res.t, verb.core.Vec.sub(points[2], points[0])))); - it('can divide a straight NURBS curve', function(){ + verb.core.Vec.norm( verb.core.Vec.sub( res.point, p_srf ) ).should.be.approximately(0, verb.core.Constants.TOLERANCE ); - var degree = 3 - , knots = [0,0,0,0,0.5,1,1,1,1] - , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ) - , d = 0.5 - , tol = 1e-3; + }); - var res = verb.eval.Divide.rationalCurveByArcLength(curve, d); + it('gives null for non-intersecting segment and triangle', () => { - var s = 0; - res.forEach(function(u){ + // line from [5,5,5] to [5,5,-5] + var p0 = [ 5,5,5 ] + , p1 = [ 5,5,4 ] - var pt = verb.eval.Eval.rationalCurvePoint( curve, u.u ); - u.len.should.be.approximately( s, tol ); - s += d; + // planar triangle + , points = [ [0,0,0], [10,0,0], [5,10,0] ] + , tri = [ 0, 1, 2 ]; - }); + var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); - }); + (null === res).should.be.true; + + }); }); -describe("verb.eval.Divide.rationalCurveByEqualArcLength",function(){ - it('can divide a straight NURBS curve', function(){ +describe("verb.eval.Make.fourPointSurface",() => { - var degree = 3 - , knots = [0,0,0,0,0.5,1,1,1,1] - , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ) - , divs = 8 - , tol = 1e-3 - , d = 4 / divs; - - var res = verb.eval.Divide.rationalCurveByEqualArcLength(curve, divs ); - - var s = 0; - res.forEach(function(u){ - - var pt = verb.eval.Eval.rationalCurvePoint( curve, u.u ); - u.len.should.be.approximately( s, tol ); - s += d; - - }); - - }); - -}); - -describe("verb.eval.Analyze.rationalCurveClosestParam",function(){ - - it('can get closest point to a straight curve', function(){ - - var degree = 3 - , knots = [0,0,0,0,0.5,1,1,1,1] - , controlPoints = [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ) - , pt = [1,0.2,0]; - - var res = verb.eval.Analyze.rationalCurveClosestParam(curve, [1,0.2,0] ); - var p = verb.eval.Eval.rationalCurvePoint( curve, res ); - - vecShouldBe( [1,0,0], p, 1e-3 ); - - res = verb.eval.Analyze.rationalCurveClosestParam(curve, [2,0.2,0] ); - p = verb.eval.Eval.rationalCurvePoint( curve, res ); - - vecShouldBe( [2,0,0], p, 1e-3 ); - - // before start - res = verb.eval.Analyze.rationalCurveClosestParam(curve, [-1,0.2,1] ); - p = verb.eval.Eval.rationalCurvePoint( curve, res ); - - vecShouldBe( [0,0,0], p, 1e-3 ); - - // beyond end - res = verb.eval.Analyze.rationalCurveClosestParam(curve, [5,0.2,0] ); - p = verb.eval.Eval.rationalCurvePoint( curve, res ); - - vecShouldBe( [4,0,0], p, 1e-3 ); - - }); - -}); - -describe("verb.eval.Analyze.rationalSurfaceClosestParam",function(){ - - it('can get closest point to flat bezier patch', function(){ - - 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, 0, 1], [10, 0, 0, 1], [20, 0, 0, 1], [30, 0, 0, 1] ], - [ [0, -10, 0, 1], [10, -10, 0, 1], [20, -10, 0, 1], [30, -10, 0, 1] ], - [ [0, -20, 0, 1], [10, -20, 0, 1], [20, -20, 0, 1], [30, -20, 0, 1] ], - [ [0, -30, 0, 1], [10, -30, 0, 1], [20, -30, 0, 1], [30, -30, 0, 1] ] ] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ) - , point = [12,-20,5]; - - var res = verb.eval.Analyze.rationalSurfaceClosestParam( surface, point ); - var p = verb.eval.Eval.rationalSurfacePoint( surface, res[0], res[1] ); - - vecShouldBe( [12,-20,0], p, 1e-3 ); - - }); - -}); - -describe("verb.eval.Intersect.segmentWithTriangle",function(){ - - it('gives correct result for intersecting axis aligned segment and triangle ', function(){ - - // line from [5,5,5] to [5,5,-5] - var p0 = [ 5,5,5 ] - , p1 = [ 5,5,-10 ] - , points = [ [0,0,0], [10,0,0], [5,10,1] ] - , tri = [ 0, 1, 2 ]; - - var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); - - res.p.should.be.approximately(0.3, verb.core.Constants.TOLERANCE); - res.s.should.be.approximately(0.25, verb.core.Constants.TOLERANCE); - res.t.should.be.approximately(0.5, verb.core.Constants.TOLERANCE); - - console.log() - - var p_srf = verb.core.Vec.add( points[0], - verb.core.Vec.add( verb.core.Vec.mul( res.s, verb.core.Vec.sub(points[1], points[0])), - verb.core.Vec.mul( res.t, verb.core.Vec.sub(points[2], points[0])))); - - verb.core.Vec.norm( verb.core.Vec.sub( res.point, p_srf ) ).should.be.approximately(0, verb.core.Constants.TOLERANCE ); - - }); - - it('gives correct result for intersecting axis aligned segment and planar triangle ', function(){ - - // line from [5,5,5] to [5,5,-5] - var p0 = [ 5,5,5 ] - , p1 = [ 5,5,-10 ] - , points = [ [0,0,0], [10,0,0], [5,10,0] ] - , tri = [ 0, 1, 2 ]; - - var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); - - res.p.should.be.approximately(0.333333333333, verb.core.Constants.TOLERANCE); - res.s.should.be.approximately(0.25, verb.core.Constants.TOLERANCE); - res.t.should.be.approximately(0.5, verb.core.Constants.TOLERANCE); - - var p_srf = verb.core.Vec.add( points[0], - verb.core.Vec.add( verb.core.Vec.mul( res.s, verb.core.Vec.sub(points[1], points[0])), - verb.core.Vec.mul( res.t, verb.core.Vec.sub(points[2], points[0])))); - - verb.core.Vec.norm( verb.core.Vec.sub( res.point, p_srf ) ).should.be.approximately(0, verb.core.Constants.TOLERANCE ); - - }); - - it('gives null for non-intersecting segment and triangle', function(){ - - // line from [5,5,5] to [5,5,-5] - var p0 = [ 5,5,5 ] - , p1 = [ 5,5,4 ] - - // planar triangle - , points = [ [0,0,0], [10,0,0], [5,10,0] ] - , tri = [ 0, 1, 2 ]; - - var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); - - (null === res).should.be.true; - - }); - -}); - - -describe("verb.eval.Make.fourPointSurface",function(){ - - it('can create an inclined plane', function(){ + it('can create an inclined plane', () => { - var p1 = [0,0,0] - , p2 = [1,0,0] - , p3 = [1,1,1] - , p4 = [0,1,1]; + var p1 = [0,0,0] + , p2 = [1,0,0] + , p3 = [1,1,1] + , p4 = [0,1,1]; - var comps = verb.eval.Make.fourPointSurface(p1, p2, p3, p4); + var comps = verb.eval.Make.fourPointSurface(p1, p2, p3, p4); - comps.degreeU.should.equal(3); - comps.degreeV.should.equal(3); + comps.degreeU.should.equal(3); + comps.degreeV.should.equal(3); - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); + // sample at the center + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 0.5); - p[0].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - p[1].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + p[0].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + p[1].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - }); + }); - it('can create a hypar', function(){ + it('can create a hypar', () => { - var p1 = [0,0,1] - , p2 = [1,0,0] - , p3 = [1,1,1] - , p4 = [0,1,0]; + var p1 = [0,0,1] + , p2 = [1,0,0] + , p3 = [1,1,1] + , p4 = [0,1,0]; - var comps = verb.eval.Make.fourPointSurface(p1, p2, p3, p4); + var comps = verb.eval.Make.fourPointSurface(p1, p2, p3, p4); - comps.degreeU.should.equal(3); - comps.degreeV.should.equal(3); + comps.degreeU.should.equal(3); + comps.degreeV.should.equal(3); - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, - 0.5, - 0.5); + // sample at the center + var p = verb.eval.Eval.rationalSurfacePoint( comps, + 0.5, + 0.5); - p[0].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - p[1].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + p[0].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + p[1].should.be.approximately(0.5, verb.core.Constants.EPSILON ); + p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - // bottom left - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 0); + // bottom left + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 0); - p[0].should.be.approximately(0, verb.core.Constants.EPSILON ); - p[1].should.be.approximately(0, verb.core.Constants.EPSILON ); - p[2].should.be.approximately(1, verb.core.Constants.EPSILON ); + p[0].should.be.approximately(0, verb.core.Constants.EPSILON ); + p[1].should.be.approximately(0, verb.core.Constants.EPSILON ); + p[2].should.be.approximately(1, verb.core.Constants.EPSILON ); - // bottom right - p = verb.eval.Eval.rationalSurfacePoint( comps, - 1, - 0); + // bottom right + p = verb.eval.Eval.rationalSurfacePoint( comps, + 1, + 0); - p[0].should.be.approximately(1, 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[0].should.be.approximately(1, 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.Intersect.polylines",function(){ +describe("verb.eval.Intersect.polylines",() => { - it('can intersect two simple lines', function(){ + it('can intersect two simple lines', () => { - var p1 = [0,0,0] - , p2 = [0,1,0] - , p3 = [-0.5,0.5,0] - , p4 = [0.5,0.5,0] - , pl0 = new verb.core.PolylineData([ p1, p2 ], [0, 1]) - , pl1 = new verb.core.PolylineData([ p3, p4 ], [0, 1]); + var p1 = [0,0,0] + , p2 = [0,1,0] + , p3 = [-0.5,0.5,0] + , p4 = [0.5,0.5,0] + , pl0 = new verb.core.PolylineData([ p1, p2 ], [0, 1]) + , pl1 = new verb.core.PolylineData([ p3, p4 ], [0, 1]); - var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); + var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); - inter.length.should.be.equal(1); + inter.length.should.be.equal(1); - inter[0].u0.should.be.approximately(0.5, verb.core.Constants.TOLERANCE ); - inter[0].u1.should.be.approximately(0.5, verb.core.Constants.TOLERANCE ); - vecShouldBe( [0, 0.5, 0], inter[0].point0 ); - vecShouldBe( [0, 0.5, 0], inter[0].point1 ); + inter[0].u0.should.be.approximately(0.5, verb.core.Constants.TOLERANCE ); + inter[0].u1.should.be.approximately(0.5, verb.core.Constants.TOLERANCE ); + vecShouldBe( [0, 0.5, 0], inter[0].point0 ); + vecShouldBe( [0, 0.5, 0], inter[0].point1 ); - }); + }); - it('can intersect a length 2 polyline and line', function(){ + it('can intersect a length 2 polyline and line', () => { - var p1 = [0,0.5,0] - , p2 = [2,0.5,0] - , p3 = [0,0,0] - , p4 = [1,0,0] - , p5 = [1,1,0] - , pl0 = new verb.core.PolylineData([ p1, p2 ], [0, 1]) - , pl1 = new verb.core.PolylineData([ p3, p4, p5], [0, 0.5, 1]); + var p1 = [0,0.5,0] + , p2 = [2,0.5,0] + , p3 = [0,0,0] + , p4 = [1,0,0] + , p5 = [1,1,0] + , pl0 = new verb.core.PolylineData([ p1, p2 ], [0, 1]) + , pl1 = new verb.core.PolylineData([ p3, p4, p5], [0, 0.5, 1]); - var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); + var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); - inter.length.should.be.equal(1); + inter.length.should.be.equal(1); - inter[0].u0.should.be.approximately(0.5, verb.core.Constants.TOLERANCE ); - inter[0].u1.should.be.approximately(0.75, verb.core.Constants.TOLERANCE ); + inter[0].u0.should.be.approximately(0.5, verb.core.Constants.TOLERANCE ); + inter[0].u1.should.be.approximately(0.75, verb.core.Constants.TOLERANCE ); - vecShouldBe( [1, 0.5, 0], inter[0].point0 ); - vecShouldBe( [1, 0.5, 0], inter[0].point1 ); + vecShouldBe( [1, 0.5, 0], inter[0].point0 ); + vecShouldBe( [1, 0.5, 0], inter[0].point1 ); - }); + }); - it('can intersect two length 2 polylines', function(){ + it('can intersect two length 2 polylines', () => { - var p1 = [0.5,-0.5,0] - , p2 = [0.5,0.5,0] - , p3 = [1.5,0.5,0] - , p4 = [0,0,0] - , p5 = [1,0,0] - , p6 = [1,1,0] - , pl0 = new verb.core.PolylineData([ p1, p2, p3 ], [0, 0.5, 1]) - , pl1 = new verb.core.PolylineData([ p4, p5, p6 ], [0, 0.5, 1]); + var p1 = [0.5,-0.5,0] + , p2 = [0.5,0.5,0] + , p3 = [1.5,0.5,0] + , p4 = [0,0,0] + , p5 = [1,0,0] + , p6 = [1,1,0] + , pl0 = new verb.core.PolylineData([ p1, p2, p3 ], [0, 0.5, 1]) + , pl1 = new verb.core.PolylineData([ p4, p5, p6 ], [0, 0.5, 1]); - var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); + var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); - inter.length.should.be.equal(2); + inter.length.should.be.equal(2); - inter[0].u0.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); - inter[0].u1.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); + inter[0].u0.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); + inter[0].u1.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); - inter[1].u0.should.be.approximately(0.75, verb.core.Constants.TOLERANCE ); - inter[1].u1.should.be.approximately(0.75, verb.core.Constants.TOLERANCE ); + inter[1].u0.should.be.approximately(0.75, verb.core.Constants.TOLERANCE ); + inter[1].u1.should.be.approximately(0.75, verb.core.Constants.TOLERANCE ); - vecShouldBe( [0.5, 0, 0], inter[0].point0 ); - vecShouldBe( [0.5, 0, 0], inter[0].point1 ); + vecShouldBe( [0.5, 0, 0], inter[0].point0 ); + vecShouldBe( [0.5, 0, 0], inter[0].point1 ); - vecShouldBe( [1, 0.5, 0], inter[1].point0 ); - vecShouldBe( [1, 0.5, 0], inter[1].point1 ); + vecShouldBe( [1, 0.5, 0], inter[1].point0 ); + vecShouldBe( [1, 0.5, 0], inter[1].point1 ); - }); + }); - it('correctly misses when two lines do not intersect', function(){ + it('correctly misses when two lines do not intersect', () => { - var p1 = [0,0,0.5] - , p2 = [0,1,0.5] - , p3 = [-0.5,0.5,0] - , p4 = [0.5,0.5,0] - , pl0 = new verb.core.PolylineData([ p1, p2 ], [0, 1]) - , pl1 = new verb.core.PolylineData([ p3, p4 ], [0, 1]); + var p1 = [0,0,0.5] + , p2 = [0,1,0.5] + , p3 = [-0.5,0.5,0] + , p4 = [0.5,0.5,0] + , pl0 = new verb.core.PolylineData([ p1, p2 ], [0, 1]) + , pl1 = new verb.core.PolylineData([ p3, p4 ], [0, 1]); - var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); + var inter = verb.eval.Intersect.polylines( pl0, pl1, verb.core.Constants.TOLERANCE ); - inter.length.should.be.equal(0); + inter.length.should.be.equal(0); - }); + }); }); -describe("verb.eval.Intersect.threePlanes",function(){ +describe("verb.eval.Intersect.threePlanes",() => { - it('is correct for intersection of 3 basis planes', function(){ + it('is correct for intersection of 3 basis planes', () => { - var d1 = 0; - var n1 = [1,0,0]; - var d2 = 0; - var n2 = [0,1,0]; - var d3 = 0; - var n3 = [0,0,1]; + var d1 = 0; + var n1 = [1,0,0]; + var d2 = 0; + var n2 = [0,1,0]; + var d3 = 0; + var n3 = [0,0,1]; - var res = verb.eval.Intersect.threePlanes(n1, d1, n2, d2, n3, d3); - res.should.be.eql( [0,0,0] ); + var res = verb.eval.Intersect.threePlanes(n1, d1, n2, d2, n3, d3); + res.should.be.eql( [0,0,0] ); - }); + }); - it('is correct for intersection of shifted basis planes', function(){ + it('is correct for intersection of shifted basis planes', () => { - var n1 = [1,0,0]; - var n2 = [0,1,0]; - var n3 = [0,0,1]; - var d1, d2, d3, res; + var n1 = [1,0,0]; + var n2 = [0,1,0]; + var n3 = [0,0,1]; + var d1, d2, d3, res; - for (var i = 0; i < 100; i++){ + for (var i = 0; i < 100; i++){ - d1 = (Math.random() - 0.5) * 10000; - d2 = (Math.random() - 0.5) * 10000; - d3 = (Math.random() - 0.5) * 10000; + d1 = (Math.random() - 0.5) * 10000; + d2 = (Math.random() - 0.5) * 10000; + d3 = (Math.random() - 0.5) * 10000; - res = verb.eval.Intersect.threePlanes(n1, d1, n2, d2, n3, d3); + res = verb.eval.Intersect.threePlanes(n1, d1, n2, d2, n3, d3); - res[0].should.be.approximately( d1, verb.core.Constants.EPSILON ); - res[1].should.be.approximately( d2, verb.core.Constants.EPSILON ); - res[2].should.be.approximately( d3, verb.core.Constants.EPSILON ); + res[0].should.be.approximately( d1, verb.core.Constants.EPSILON ); + res[1].should.be.approximately( d2, verb.core.Constants.EPSILON ); + res[2].should.be.approximately( d3, verb.core.Constants.EPSILON ); - } + } - }); + }); - it('is null for repeat planes', function(){ + it('is null for repeat planes', () => { - var d1 = 10; - var n1 = [0,1,0]; - var d2 = 0; - var n2 = [0,1,0]; - var d3 = 10; - var n3 = [0,0,1]; + var d1 = 10; + var n1 = [0,1,0]; + var d2 = 0; + var n2 = [0,1,0]; + var d3 = 10; + var n3 = [0,0,1]; - var res = verb.eval.Intersect.threePlanes(n1, d1, n2, d2, n3, d3); - should.equal( res, null ); //non-intersect is null + var res = verb.eval.Intersect.threePlanes(n1, d1, n2, d2, n3, d3); + should.equal( res, null ); //non-intersect is null - }); + }); }); -describe("verb.eval.Intersect.planes",function(){ +describe("verb.eval.Intersect.planes",() => { - it('is correct for intersection of xz and yz planes', function(){ + it('is correct for intersection of xz and yz planes', () => { - var o1 = [0,0,0]; - var n1 = [1,0,0]; - var o2 = [0,0,0]; - var n2 = [0,1,0]; + var o1 = [0,0,0]; + var n1 = [1,0,0]; + var o2 = [0,0,0]; + var n2 = [0,1,0]; - var res = verb.eval.Intersect.planes(o1, n1, o2, n2); + var res = verb.eval.Intersect.planes(o1, n1, o2, n2); - res.origin.should.be.eql( [0,0,0] ); - res.dir.should.be.eql( [0,0,1] ); + res.origin.should.be.eql( [0,0,0] ); + res.dir.should.be.eql( [0,0,1] ); - }); + }); - it('is correct for intersection of xz and shifted yz plane', function(){ + it('is correct for intersection of xz and shifted yz plane', () => { - var o1 = [20,0,0]; - var n1 = [1,0,0]; - var o2 = [0,0,0]; - var n2 = [0,1,0]; + var o1 = [20,0,0]; + var n1 = [1,0,0]; + var o2 = [0,0,0]; + var n2 = [0,1,0]; - var res = verb.eval.Intersect.planes(o1, n1, o2, n2); + var res = verb.eval.Intersect.planes(o1, n1, o2, n2); - res.origin.should.be.eql( [20,0,0] ); - res.dir.should.be.eql( [0,0,1] ); + res.origin.should.be.eql( [20,0,0] ); + res.dir.should.be.eql( [0,0,1] ); - }); + }); - it('is correct for intersection of shifted xz and yz plane', function(){ + it('is correct for intersection of shifted xz and yz plane', () => { - var o1 = [0,0,0]; - var n1 = [1,0,0]; - var o2 = [0,20,0]; - var n2 = [0,1,0]; + var o1 = [0,0,0]; + var n1 = [1,0,0]; + var o2 = [0,20,0]; + var n2 = [0,1,0]; - // should be z-axis - var res = verb.eval.Intersect.planes(o1, n1, o2, n2); + // should be z-axis + var res = verb.eval.Intersect.planes(o1, n1, o2, n2); - res.origin.should.be.eql( [0,20,0] ); - res.dir.should.be.eql( [0,0,1] ); + res.origin.should.be.eql( [0,20,0] ); + res.dir.should.be.eql( [0,0,1] ); - }); + }); }); -describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ +describe("verb.eval.Intersect.clipRayInCoplanarTriangle",() => { - it('is correct for a basic example 1', function(){ + it('is correct for a basic example 1', () => { - var o = [0,1,0]; - var d = [1,0,0]; + var o = [0,1,0]; + var d = [1,0,0]; - var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri = [[ 0, 1, 2 ]]; - var uvs = [ [0,0], [2,0], [2, 2] ]; - var mesh = new verb.core.MeshData(tri, pts, null, uvs); + var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri = [[ 0, 1, 2 ]]; + var uvs = [ [0,0], [2,0], [2, 2] ]; + var mesh = new verb.core.MeshData(tri, pts, null, uvs); - var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0); + var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0); - res.min.u.should.be.approximately(1, verb.core.Constants.TOLERANCE); - res.max.u.should.be.approximately(2, verb.core.Constants.TOLERANCE); + res.min.u.should.be.approximately(1, verb.core.Constants.TOLERANCE); + res.max.u.should.be.approximately(2, verb.core.Constants.TOLERANCE); - vecShouldBe( [1,1], res.min.uv ); - vecShouldBe( [2,1], res.max.uv ); + vecShouldBe( [1,1], res.min.uv ); + vecShouldBe( [2,1], res.max.uv ); - vecShouldBe( [1,1,0], res.min.point ); - vecShouldBe( [2,1,0], res.max.point ); + vecShouldBe( [1,1,0], res.min.point ); + vecShouldBe( [2,1,0], res.max.point ); - }); + }); - it('is correct for a basic example 2', function(){ + it('is correct for a basic example 2', () => { - var o = [0.5,-0.5,0]; - var d = [0,1,0]; + var o = [0.5,-0.5,0]; + var d = [0,1,0]; - var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri = [[ 0, 1, 2 ]]; - var uvs = [ [0,0], [2,0], [2, 2] ]; + var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri = [[ 0, 1, 2 ]]; + var uvs = [ [0,0], [2,0], [2, 2] ]; - var mesh = new verb.core.MeshData(tri, pts, null, uvs); - var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); + var mesh = new verb.core.MeshData(tri, pts, null, uvs); + var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); - res.min.u.should.be.approximately(0.5, verb.core.Constants.TOLERANCE); - res.max.u.should.be.approximately(1, verb.core.Constants.TOLERANCE); + res.min.u.should.be.approximately(0.5, verb.core.Constants.TOLERANCE); + res.max.u.should.be.approximately(1, verb.core.Constants.TOLERANCE); - vecShouldBe( [0.5,0], res.min.uv ); - vecShouldBe( [0.5,0.5], res.max.uv ); + vecShouldBe( [0.5,0], res.min.uv ); + vecShouldBe( [0.5,0.5], res.max.uv ); - vecShouldBe( [0.5,0,0], res.min.point ); - vecShouldBe( [0.5,0.5,0], res.max.point ); + vecShouldBe( [0.5,0,0], res.min.point ); + vecShouldBe( [0.5,0.5,0], res.max.point ); - }); + }); - it('is correct for a basic example 3', function(){ + it('is correct for a basic example 3', () => { - var o = [0.5,-0.5,0]; - var d = [Math.sqrt(2)/2,Math.sqrt(2)/2,0]; + var o = [0.5,-0.5,0]; + var d = [Math.sqrt(2)/2,Math.sqrt(2)/2,0]; - var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri = [[ 0, 1, 2 ]]; - var uvs = [ [0,0], [2,0], [2, 2] ]; + var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri = [[ 0, 1, 2 ]]; + var uvs = [ [0,0], [2,0], [2, 2] ]; - var mesh = new verb.core.MeshData(tri, pts, null, uvs); - var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); + var mesh = new verb.core.MeshData(tri, pts, null, uvs); + var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); - res.min.u.should.be.approximately(Math.sqrt(2)/2, verb.core.Constants.TOLERANCE); - res.max.u.should.be.approximately(3 * Math.sqrt(2)/2, verb.core.Constants.TOLERANCE); + res.min.u.should.be.approximately(Math.sqrt(2)/2, verb.core.Constants.TOLERANCE); + res.max.u.should.be.approximately(3 * Math.sqrt(2)/2, verb.core.Constants.TOLERANCE); - vecShouldBe( [1,0], res.min.uv ); - vecShouldBe( [2,1], res.max.uv ); + vecShouldBe( [1,0], res.min.uv ); + vecShouldBe( [2,1], res.max.uv ); - vecShouldBe( [1,0,0], res.min.point ); - vecShouldBe( [2,1,0], res.max.point ); + vecShouldBe( [1,0,0], res.min.point ); + vecShouldBe( [2,1,0], res.max.point ); - }); + }); - it('is correct for a basic example 4', function(){ + it('is correct for a basic example 4', () => { - var o = [0, 2,0]; - var d = [Math.sqrt(2)/2,-Math.sqrt(2)/2,0]; + var o = [0, 2,0]; + var d = [Math.sqrt(2)/2,-Math.sqrt(2)/2,0]; - var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri = [[ 0, 1, 2 ]]; - var uvs = [ [0,0], [2,0], [2, 2] ]; + var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri = [[ 0, 1, 2 ]]; + var uvs = [ [0,0], [2,0], [2, 2] ]; - var mesh = new verb.core.MeshData(tri, pts, null, uvs); - var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); + var mesh = new verb.core.MeshData(tri, pts, null, uvs); + var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); - res.min.u.should.be.approximately(Math.sqrt(2), verb.core.Constants.TOLERANCE); - res.max.u.should.be.approximately(2 * Math.sqrt(2), verb.core.Constants.TOLERANCE); + res.min.u.should.be.approximately(Math.sqrt(2), verb.core.Constants.TOLERANCE); + res.max.u.should.be.approximately(2 * Math.sqrt(2), verb.core.Constants.TOLERANCE); - vecShouldBe( [1,1], res.min.uv ); - vecShouldBe( [2,0], res.max.uv ); + vecShouldBe( [1,1], res.min.uv ); + vecShouldBe( [2,0], res.max.uv ); - vecShouldBe( [1,1,0], res.min.point ); - vecShouldBe( [2,0,0], res.max.point ); + vecShouldBe( [1,1,0], res.min.point ); + vecShouldBe( [2,0,0], res.max.point ); - }); + }); - it('is correct for a basic example 5', function(){ + it('is correct for a basic example 5', () => { - var o = [1,1,0]; - var d = [Math.sqrt(2)/2,-Math.sqrt(2)/2,0]; + var o = [1,1,0]; + var d = [Math.sqrt(2)/2,-Math.sqrt(2)/2,0]; - var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri = [[ 0, 1, 2 ]]; - var uvs = [ [0,0], [2,0], [2, 2] ]; + var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri = [[ 0, 1, 2 ]]; + var uvs = [ [0,0], [2,0], [2, 2] ]; - var mesh = new verb.core.MeshData(tri, pts, null, uvs); - var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); + var mesh = new verb.core.MeshData(tri, pts, null, uvs); + var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); - res.min.u.should.be.approximately(0, verb.core.Constants.TOLERANCE); - res.max.u.should.be.approximately(Math.sqrt(2), verb.core.Constants.TOLERANCE); + res.min.u.should.be.approximately(0, verb.core.Constants.TOLERANCE); + res.max.u.should.be.approximately(Math.sqrt(2), verb.core.Constants.TOLERANCE); - vecShouldBe( [1,1], res.min.uv ); - vecShouldBe( [2,0], res.max.uv ); + vecShouldBe( [1,1], res.min.uv ); + vecShouldBe( [2,0], res.max.uv ); - vecShouldBe( [1,1,0], res.min.point ); - vecShouldBe( [2,0,0], res.max.point ); + vecShouldBe( [1,1,0], res.min.point ); + vecShouldBe( [2,0,0], res.max.point ); - }); + }); - it('is correct for a basic example 6', function(){ + it('is correct for a basic example 6', () => { - var o = [3,1,0]; - var d = [-1,0,0]; + var o = [3,1,0]; + var d = [-1,0,0]; - var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri = [[ 0, 1, 2 ]]; - var uvs = [ [0,0], [2,0], [2, 2] ]; + var pts = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri = [[ 0, 1, 2 ]]; + var uvs = [ [0,0], [2,0], [2, 2] ]; - var mesh = new verb.core.MeshData(tri, pts, null, uvs); - var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); + var mesh = new verb.core.MeshData(tri, pts, null, uvs); + var res = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh, 0 ); - res.min.u.should.be.approximately(1, verb.core.Constants.TOLERANCE); - res.max.u.should.be.approximately(2, verb.core.Constants.TOLERANCE); + res.min.u.should.be.approximately(1, verb.core.Constants.TOLERANCE); + res.max.u.should.be.approximately(2, verb.core.Constants.TOLERANCE); - vecShouldBe( [2,1], res.min.uv ); - vecShouldBe( [1,1], res.max.uv ); + vecShouldBe( [2,1], res.min.uv ); + vecShouldBe( [1,1], res.max.uv ); - vecShouldBe( [2,1,0], res.min.point ); - vecShouldBe( [1,1,0], res.max.point ); + vecShouldBe( [2,1,0], res.min.point ); + vecShouldBe( [1,1,0], res.max.point ); - }); + }); }); -describe("verb.eval.Intersect.mergeTriangleClipIntervals",function(){ +describe("verb.eval.Intersect.mergeTriangleClipIntervals",() => { - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { - var o = [1,0,0]; - var d = [0,1,0]; + var o = [1,0,0]; + var d = [0,1,0]; - var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri1 = [[ 0, 1, 2 ]]; - var uvs1 = [ [0,0], [2,0], [2, 2] ]; - var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); + var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri1 = [[ 0, 1, 2 ]]; + var uvs1 = [ [0,0], [2,0], [2, 2] ]; + var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); - var clip1 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh1, 0 ); + var clip1 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh1, 0 ); - var pts2 = [ [1,0.5,-1], [1,2.5,-1], [1,0.5,1] ]; - var tri2 = [[ 0, 1, 2 ]]; - var uvs2 = [ [0,0], [2,0], [0,2] ]; - var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); + var pts2 = [ [1,0.5,-1], [1,2.5,-1], [1,0.5,1] ]; + var tri2 = [[ 0, 1, 2 ]]; + var uvs2 = [ [0,0], [2,0], [0,2] ]; + var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); - var clip2 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh2, 0 ); + var clip2 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh2, 0 ); - var res = verb.eval.Intersect.mergeTriangleClipIntervals(clip1, clip2, mesh1, 0, mesh2, 0); + var res = verb.eval.Intersect.mergeTriangleClipIntervals(clip1, clip2, mesh1, 0, mesh2, 0); - vecShouldBe( [1, 0.5], res.min.uv0 ); - vecShouldBe( [0, 1], res.min.uv1 ); - vecShouldBe( [1, 0.5, 0], res.min.point ); + vecShouldBe( [1, 0.5], res.min.uv0 ); + vecShouldBe( [0, 1], res.min.uv1 ); + vecShouldBe( [1, 0.5, 0], res.min.point ); - vecShouldBe( [1, 1], res.max.uv0 ); - vecShouldBe( [0.5, 1], res.max.uv1 ); - vecShouldBe( [1, 1, 0], res.max.point ); + vecShouldBe( [1, 1], res.max.uv0 ); + vecShouldBe( [0.5, 1], res.max.uv1 ); + vecShouldBe( [1, 1, 0], res.max.point ); - }); + }); - it('is correct for triangles sharing an edge', function(){ + it('is correct for triangles sharing an edge', () => { - var o = [2,-1,0]; - var d = [0,1,0]; + var o = [2,-1,0]; + var d = [0,1,0]; - var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri1 = [[ 0, 1, 2 ]]; - var uvs1 = [ [0,0], [2,0], [2, 2] ]; - var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); + var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri1 = [[ 0, 1, 2 ]]; + var uvs1 = [ [0,0], [2,0], [2, 2] ]; + var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); - var clip1 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh1, 0 ); + var clip1 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh1, 0 ); - var pts2 = [ [2,0,0], [2, 2, 0], [2, 0, 2] ]; - var tri2 = [[ 0, 1, 2 ]]; - var uvs2 = [ [0,0], [2,0], [0,2] ]; - var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); + var pts2 = [ [2,0,0], [2, 2, 0], [2, 0, 2] ]; + var tri2 = [[ 0, 1, 2 ]]; + var uvs2 = [ [0,0], [2,0], [0,2] ]; + var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); - var clip2 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh2, 0 ); + var clip2 = verb.eval.Intersect.clipRayInCoplanarTriangle(new verb.core.Ray(o, d), mesh2, 0 ); - var res = verb.eval.Intersect.mergeTriangleClipIntervals(clip1, clip2, mesh1, 0, mesh2, 0); + var res = verb.eval.Intersect.mergeTriangleClipIntervals(clip1, clip2, mesh1, 0, mesh2, 0); - vecShouldBe( [2, 0], res.min.uv0 ); - vecShouldBe( [0, 0], res.min.uv1 ); - vecShouldBe( [2, 0, 0], res.min.point ); + vecShouldBe( [2, 0], res.min.uv0 ); + vecShouldBe( [0, 0], res.min.uv1 ); + vecShouldBe( [2, 0, 0], res.min.point ); - vecShouldBe( [2, 2], res.max.uv0 ); - vecShouldBe( [2, 0], res.max.uv1 ); - vecShouldBe( [2, 2, 0], res.max.point ); + vecShouldBe( [2, 2], res.max.uv0 ); + vecShouldBe( [2, 0], res.max.uv1 ); + vecShouldBe( [2, 2, 0], res.max.point ); - }); + }); }); -describe("verb.eval.Intersect.triangles",function(){ +describe("verb.eval.Intersect.triangles",() => { - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { - var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri1 = [[ 0, 1, 2 ]]; - var uvs1 = [ [0,0], [2,0], [2, 2] ]; - var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); + var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri1 = [[ 0, 1, 2 ]]; + var uvs1 = [ [0,0], [2,0], [2, 2] ]; + var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); - var pts2 = [ [1,0.5,-1], [1,2.5,-1], [1,0.5,1] ]; - var tri2 = [[ 0, 1, 2 ]]; - var uvs2 = [ [0,0], [2,0], [0,2] ]; - var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); + var pts2 = [ [1,0.5,-1], [1,2.5,-1], [1,0.5,1] ]; + var tri2 = [[ 0, 1, 2 ]]; + var uvs2 = [ [0,0], [2,0], [0,2] ]; + var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); - var res = verb.eval.Intersect.triangles( mesh1, 0, mesh2, 0 ); + var res = verb.eval.Intersect.triangles( mesh1, 0, mesh2, 0 ); - vecShouldBe( [1, 0.5], res.min.uv0 ); - vecShouldBe( [0, 1], res.min.uv1 ); - vecShouldBe( [1, 0.5, 0], res.min.point ); + vecShouldBe( [1, 0.5], res.min.uv0 ); + vecShouldBe( [0, 1], res.min.uv1 ); + vecShouldBe( [1, 0.5, 0], res.min.point ); - vecShouldBe( [1, 1], res.max.uv0 ); - vecShouldBe( [0.5, 1], res.max.uv1 ); - vecShouldBe( [1, 1, 0], res.max.point ); + vecShouldBe( [1, 1], res.max.uv0 ); + vecShouldBe( [0.5, 1], res.max.uv1 ); + vecShouldBe( [1, 1, 0], res.max.point ); - }); + }); - it('is correct for triangles sharing an edge', function(){ + it('is correct for triangles sharing an edge', () => { - var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tri1 = [[ 0, 1, 2 ]]; - var uvs1 = [ [0,0], [2,0], [2, 2] ]; - var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); + var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tri1 = [[ 0, 1, 2 ]]; + var uvs1 = [ [0,0], [2,0], [2, 2] ]; + var mesh1 = new verb.core.MeshData(tri1, pts1, null, uvs1); - var pts2 = [ [2, 0, 0], [2, 2, 0], [2,0,2] ]; - var tri2 = [[ 0, 1, 2 ]]; - var uvs2 = [ [0,0], [2,0], [0,2] ]; - var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); + var pts2 = [ [2, 0, 0], [2, 2, 0], [2,0,2] ]; + var tri2 = [[ 0, 1, 2 ]]; + var uvs2 = [ [0,0], [2,0], [0,2] ]; + var mesh2 = new verb.core.MeshData(tri2, pts2, null, uvs2); - var res = verb.eval.Intersect.triangles( mesh1, 0, mesh2, 0 ); + var res = verb.eval.Intersect.triangles( mesh1, 0, mesh2, 0 ); - vecShouldBe( [2,0], res.min.uv0 ); - vecShouldBe( [0,0], res.min.uv1 ); - vecShouldBe( [2,0,0], res.min.point ); + vecShouldBe( [2,0], res.min.uv0 ); + vecShouldBe( [0,0], res.min.uv1 ); + vecShouldBe( [2,0,0], res.min.point ); - vecShouldBe( [2,2], res.max.uv0 ); - vecShouldBe( [2,0], res.max.uv1 ); - vecShouldBe( [2, 2, 0], res.max.point ); + vecShouldBe( [2,2], res.max.uv0 ); + vecShouldBe( [2,0], res.max.uv1 ); + vecShouldBe( [2, 2, 0], res.max.point ); - }); + }); }); -describe("verb.eval.Intersect.curves",function(){ +describe("verb.eval.Intersect.curves",() => { - it('gives valid result for two planar lines', function(){ + it('gives valid result for two planar lines', () => { - var degree1 = 1, - knots1 = [0,0,1,1], - controlPoints1 = [[0,0,0,1], [2,0,0,1]], - curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), - degree2 = 1, - knots2 = [0,0,1,1], - controlPoints2 = [[0.5,0.5,0,1], [0.5,-1.5,0,1]] - curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); + var degree1 = 1, + knots1 = [0,0,1,1], + controlPoints1 = [[0,0,0,1], [2,0,0,1]], + curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), + degree2 = 1, + knots2 = [0,0,1,1], + controlPoints2 = [[0.5,0.5,0,1], [0.5,-1.5,0,1]] + curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); - var res = verb.eval.Intersect.curves( curve1, curve2, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curves( curve1, curve2, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal(1); + res.length.should.be.equal(1); - res[0].u0.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); - res[0].u1.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); + res[0].u0.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); + res[0].u1.should.be.approximately(0.25, verb.core.Constants.TOLERANCE ); - }); + }); - it('gives valid result for planar degree 2 bezier and planar line', function(){ + it('gives valid result for planar degree 2 bezier and planar line', () => { - var degree1 = 1, - knots1 = [0,0,1,1], - controlPoints1 = [[0,0,0,1], [2,0,0,1]], - curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), - degree2 = 2, - knots2 = [0,0,0,1,1,1], - controlPoints2 = [[0.5,0.5,0,1], [0.7,0,0,1], [0.5,-1.5,0,1]] - curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); + var degree1 = 1, + knots1 = [0,0,1,1], + controlPoints1 = [[0,0,0,1], [2,0,0,1]], + curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), + degree2 = 2, + knots2 = [0,0,0,1,1,1], + controlPoints2 = [[0.5,0.5,0,1], [0.7,0,0,1], [0.5,-1.5,0,1]] + curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); - var res = verb.eval.Intersect.curves( curve1,curve2, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curves( curve1,curve2, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal(1); + res.length.should.be.equal(1); - res[0].u0.should.be.approximately(0.2964101616038012, verb.core.Constants.TOLERANCE ); - res[0].u1.should.be.approximately(0.3660254038069307, verb.core.Constants.TOLERANCE ); + res[0].u0.should.be.approximately(0.2964101616038012, verb.core.Constants.TOLERANCE ); + res[0].u1.should.be.approximately(0.3660254038069307, verb.core.Constants.TOLERANCE ); - }); + }); - it('gives valid result for planar line and planar degree 2 bezier as second arg', function(){ + it('gives valid result for planar line and planar degree 2 bezier as second arg', () => { - var degree1 = 1, - knots1 = [0,0,1,1], - controlPoints1 = [[0,0,0,1], [2,0,0,1]], - curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), - degree2 = 2, - knots2 = [0,0,0,1,1,1], - controlPoints2 = [[0.5,0.5,0,1], [0.7,0,0,1], [0.5,-1.5,0,1]] - curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); + var degree1 = 1, + knots1 = [0,0,1,1], + controlPoints1 = [[0,0,0,1], [2,0,0,1]], + curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), + degree2 = 2, + knots2 = [0,0,0,1,1,1], + controlPoints2 = [[0.5,0.5,0,1], [0.7,0,0,1], [0.5,-1.5,0,1]] + curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); - var res = verb.eval.Intersect.curves(curve2, curve1, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curves(curve2, curve1, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal(1); + res.length.should.be.equal(1); - res[0].u0.should.be.approximately(0.3660254038069307, verb.core.Constants.TOLERANCE ); - res[0].u1.should.be.approximately(0.2964101616038012, verb.core.Constants.TOLERANCE ); + res[0].u0.should.be.approximately(0.3660254038069307, verb.core.Constants.TOLERANCE ); + res[0].u1.should.be.approximately(0.2964101616038012, verb.core.Constants.TOLERANCE ); - }); + }); - it('gives valid result for 2 planar degree 2 beziers', function(){ + it('gives valid result for 2 planar degree 2 beziers', () => { - var degree1 = 2, - knots1 = [0,0,0,1,1,1], - controlPoints1 = [[0,0,0,1], [0.5,0.1,0,1], [2,0,0,1]], - curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), - degree2 = 2, - knots2 = [0,0,0,1,1,1], - controlPoints2 = [[0.5,0.5,0,1], [0.7,0,0,1], [0.5,-1.5,0,1]] - curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); + var degree1 = 2, + knots1 = [0,0,0,1,1,1], + controlPoints1 = [[0,0,0,1], [0.5,0.1,0,1], [2,0,0,1]], + curve1 = new verb.core.NurbsCurveData( degree1, knots1, controlPoints1 ), + degree2 = 2, + knots2 = [0,0,0,1,1,1], + controlPoints2 = [[0.5,0.5,0,1], [0.7,0,0,1], [0.5,-1.5,0,1]] + curve2 = new verb.core.NurbsCurveData( degree2, knots2, controlPoints2 ); - var res = verb.eval.Intersect.curves( curve1, curve2, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curves( curve1, curve2, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal(1); + res.length.should.be.equal(1); - verb.core.Vec.dist( res[0].point0, res[0].point1 ).should.be.lessThan( verb.core.Constants.TOLERANCE ); + verb.core.Vec.dist( res[0].point0, res[0].point1 ).should.be.lessThan( verb.core.Constants.TOLERANCE ); - }); + }); }); -describe("verb.eval.Intersect.curveAndSurface",function(){ +describe("verb.eval.Intersect.curveAndSurface",() => { - it('gives valid result for planar surface and line', function(){ + it('gives valid result for planar surface and line', () => { - // build planar surface in the xy plane - var homo_controlPoints_srf = [ [ [0,0,0,1], [20,0,0,1] ], [[0,10,0,1], [20,10,0,1] ] ] - , degreeU = 1 - , degreeV = 1 - , knotsU = [0,0,1,1] - , knotsV = [0,0,1,1] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); + // build planar surface in the xy plane + var homo_controlPoints_srf = [ [ [0,0,0,1], [20,0,0,1] ], [[0,10,0,1], [20,10,0,1] ] ] + , degreeU = 1 + , degreeV = 1 + , knotsU = [0,0,1,1] + , knotsV = [0,0,1,1] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); - // line from [5,5,5] to [5,5,-5] - var degree_crv = 1 - , knots_crv = [0,0,1,1] - , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.2,5.2,-10,1] ] - , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); + // line from [5,5,5] to [5,5,-5] + var degree_crv = 1 + , knots_crv = [0,0,1,1] + , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.2,5.2,-10,1] ] + , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); - var res = verb.eval.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal( 1 ); + res.length.should.be.equal( 1 ); - res[0].u.should.be.approximately( 1/3, 1e-3 ); - res[0].uv[0].should.be.approximately( 0.52, 1e-3 ); - res[0].uv[1].should.be.approximately( 0.26, 1e-3 ); + res[0].u.should.be.approximately( 1/3, 1e-3 ); + res[0].uv[0].should.be.approximately( 0.52, 1e-3 ); + res[0].uv[1].should.be.approximately( 0.26, 1e-3 ); - }); + }); - it('gives valid result for planar surface and degree 1 nurbs', function(){ + it('gives valid result for planar surface and degree 1 nurbs', () => { - // build planar surface in the xy plane - var homo_controlPoints_srf = [ [ [0,0,0,1], [20,0,0,1] ], [[0,10,0,1], [20,10,0,1] ] ] - , degreeU = 1 - , degreeV = 1 - , knotsU = [0,0,1,1] - , knotsV = [0,0,1,1] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); + // build planar surface in the xy plane + var homo_controlPoints_srf = [ [ [0,0,0,1], [20,0,0,1] ], [[0,10,0,1], [20,10,0,1] ] ] + , degreeU = 1 + , degreeV = 1 + , knotsU = [0,0,1,1] + , knotsV = [0,0,1,1] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); - // line from [5,5,5] to [5,5,-5] - var degree_crv = 1 - , knots_crv = [0,0,0.5,1,1] - , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.2,5.2,-2.5,1], [5.2,5.2,-10,1] ] - , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); + // line from [5,5,5] to [5,5,-5] + var degree_crv = 1 + , knots_crv = [0,0,0.5,1,1] + , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.2,5.2,-2.5,1], [5.2,5.2,-10,1] ] + , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); - var res = verb.eval.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal( 1 ); - res[0].u.should.be.approximately( 1/3, 1e-3 ); - res[0].uv[0].should.be.approximately( 0.52, 1e-3 ); - res[0].uv[1].should.be.approximately( 0.26, 1e-3 ); + res.length.should.be.equal( 1 ); + res[0].u.should.be.approximately( 1/3, 1e-3 ); + res[0].uv[0].should.be.approximately( 0.52, 1e-3 ); + res[0].uv[1].should.be.approximately( 0.26, 1e-3 ); - }); + }); - it('gives valid result for planar surface and degree 2 bezier', function(){ + it('gives valid result for planar surface and degree 2 bezier', () => { - // build planar surface in the xy plane - var homo_controlPoints_srf = [ [ [0,0,0,1], [0,10,0,1] ], [[20,0,0,1], [20,10,0,1] ] ] - , degreeU = 1 - , degreeV = 1 - , knotsU = [0,0,1,1] - , knotsV = [0,0,1,1] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); + // build planar surface in the xy plane + var homo_controlPoints_srf = [ [ [0,0,0,1], [0,10,0,1] ], [[20,0,0,1], [20,10,0,1] ] ] + , degreeU = 1 + , degreeV = 1 + , knotsU = [0,0,1,1] + , knotsV = [0,0,1,1] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); - // line from [5,5,5] to [5,5,-5] - var degree_crv = 2 - , knots_crv = [0,0,0,1,1,1] - , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.4,4.8,0,1], [5.2,5.2,-5,1] ] - , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); + // line from [5,5,5] to [5,5,-5] + var degree_crv = 2 + , knots_crv = [0,0,0,1,1,1] + , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.4,4.8,0,1], [5.2,5.2,-5,1] ] + , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); - var res = verb.eval.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); - res.length.should.be.equal( 1 ); - res[0].u.should.be.approximately( 0.5, 1e-3 ); - res[0].uv[0].should.be.approximately( 0.265, 1e-3 ); - res[0].uv[1].should.be.approximately( 0.5, 1e-3 ); + res.length.should.be.equal( 1 ); + res[0].u.should.be.approximately( 0.5, 1e-3 ); + res[0].uv[0].should.be.approximately( 0.265, 1e-3 ); + res[0].uv[1].should.be.approximately( 0.5, 1e-3 ); - }); + }); - it('gives valid result for non-intersecting planar surface and line', function(){ + it('gives valid result for non-intersecting planar surface and line', () => { - // build planar surface in the xy plane - var homo_controlPoints_srf = [ [ [0,0,0,1], [20,0,0,1] ], [[0,10,0,1], [20,10,0,1] ] ] - , degreeU = 1 - , degreeV = 1 - , knotsU = [0,0,1,1] - , knotsV = [0,0,1,1] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); + // build planar surface in the xy plane + var homo_controlPoints_srf = [ [ [0,0,0,1], [20,0,0,1] ], [[0,10,0,1], [20,10,0,1] ] ] + , degreeU = 1 + , degreeV = 1 + , knotsU = [0,0,1,1] + , knotsV = [0,0,1,1] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); - // line from [5,5,5] to [5,5,-5] - var degree_crv = 1 - , knots_crv = [0,0,1,1] - , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.2,5.2,2,1] ] - , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); + // line from [5,5,5] to [5,5,-5] + var degree_crv = 1 + , knots_crv = [0,0,1,1] + , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.2,5.2,2,1] ] + , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); - var res = verb.eval.Intersect.curveAndSurface( curve, surface ); - res.length.should.be.equal( 0 ); + var res = verb.eval.Intersect.curveAndSurface( curve, surface ); + res.length.should.be.equal( 0 ); - }); + }); }); -describe("verb.eval.Intersect.curveAndSurfaceWithEstimate",function(){ +describe("verb.eval.Intersect.curveAndSurfaceWithEstimate",() => { - it('gives valid result for planar surface and degree 2 bezier', function(){ + it('gives valid result for planar surface and degree 2 bezier', () => { - var homo_controlPoints_srf = [ [ [0,0,0,1], [0,10,0,1] ], [[20,0,0,1], [20,10,0,1] ] ] - , degreeU = 1 - , degreeV = 1 - , knotsU = [0,0,1,1] - , knotsV = [0,0,1,1] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); + var homo_controlPoints_srf = [ [ [0,0,0,1], [0,10,0,1] ], [[20,0,0,1], [20,10,0,1] ] ] + , degreeU = 1 + , degreeV = 1 + , knotsU = [0,0,1,1] + , knotsV = [0,0,1,1] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, homo_controlPoints_srf ); - var degree_crv = 2 - , knots_crv = [0,0,0,1,1,1] - , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.4,4.8,0,1], [5.2,5.2,-5,1] ] - , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); + var degree_crv = 2 + , knots_crv = [0,0,0,1,1,1] + , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.4,4.8,0,1], [5.2,5.2,-5,1] ] + , curve = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); - var start_params = [ 0.45, 0.25, 0.55 ]; + var start_params = [ 0.45, 0.25, 0.55 ]; - var res = verb.eval.Intersect.curveAndSurfaceWithEstimate( curve, surface, start_params, verb.core.Constants.TOLERANCE ); + var res = verb.eval.Intersect.curveAndSurfaceWithEstimate( curve, surface, start_params, verb.core.Constants.TOLERANCE ); - res.u.should.be.approximately(0.5, 1e-3); - res.uv[0].should.be.approximately(0.265, 1e-3); - res.uv[1].should.be.approximately(0.5, 1e-3); + res.u.should.be.approximately(0.5, 1e-3); + res.uv[0].should.be.approximately(0.265, 1e-3); + res.uv[1].should.be.approximately(0.5, 1e-3); - }); + }); }); -describe("verb.eval.Intersect.lookupAdjacentSegment",function(){ +describe("verb.eval.Intersect.lookupAdjacentSegment",() => { - var segs = [ - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [1,2,3], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [5,6,7], 0, 0 )), - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [2,2,3], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [6,6,7], 0, 0 )), - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [3,2,3], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [7,6,7], 0, 0 )) ]; + var segs = [ + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [1,2,3], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [5,6,7], 0, 0 )), + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [2,2,3], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [6,6,7], 0, 0 )), + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [3,2,3], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [7,6,7], 0, 0 )) ]; - it('returns null when only nearest is argument itself', function(){ + it('returns null when only nearest is argument itself', () => { - var end = segs[0].min; + var end = segs[0].min; - var tree = verb.eval.Intersect.kdTreeFromSegments( segs ); - var nearest = verb.eval.Intersect.lookupAdjacentSegment( end, tree, 3 ); + var tree = verb.eval.Intersect.kdTreeFromSegments( segs ); + var nearest = verb.eval.Intersect.lookupAdjacentSegment( end, tree, 3 ); - should.equal( nearest, null ); + should.equal( nearest, null ); - }); + }); - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { - var end = new verb.core.MeshIntersectionPoint([0,0], [0,0], [1,2,3], 0, 0 ); // same pos, but different object + var end = new verb.core.MeshIntersectionPoint([0,0], [0,0], [1,2,3], 0, 0 ); // same pos, but different object - var tree = verb.eval.Intersect.kdTreeFromSegments( segs ); - var nearest = verb.eval.Intersect.lookupAdjacentSegment( end, tree, 3 ); + var tree = verb.eval.Intersect.kdTreeFromSegments( segs ); + var nearest = verb.eval.Intersect.lookupAdjacentSegment( end, tree, 3 ); - nearest.should.be.equal(segs[0].min) + nearest.should.be.equal(segs[0].min) - }); + }); }); -describe("verb.eval.Intersect.makeMeshIntersectionPolylines ",function(){ +describe("verb.eval.Intersect.makeMeshIntersectionPolylines ",() => { - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { - var segs = [ - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [10,0,0], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [10,10,0], 0, 0 )), - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [0,10,0], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [10,10,0], 0, 0 )), - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [5,0,0], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [0,10,0], 0, 0 )) ]; + var segs = [ + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [10,0,0], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [10,10,0], 0, 0 )), + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [0,10,0], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [10,10,0], 0, 0 )), + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [5,0,0], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [0,10,0], 0, 0 )) ]; - var pls = verb.eval.Intersect.makeMeshIntersectionPolylines( segs ); + var pls = verb.eval.Intersect.makeMeshIntersectionPolylines( segs ); - pls.length.should.be.equal( 1 ); - pls[0].length.should.be.equal( 4 ); - pls[0][0].point.should.be.eql( [5,0,0] ); - pls[0][1].point.should.be.eql( [0,10,0] ); - pls[0][2].point.should.be.eql( [10,10,0] ); - pls[0][3].point.should.be.eql( [10,0,0] ); + pls.length.should.be.equal( 1 ); + pls[0].length.should.be.equal( 4 ); + pls[0][0].point.should.be.eql( [5,0,0] ); + pls[0][1].point.should.be.eql( [0,10,0] ); + pls[0][2].point.should.be.eql( [10,10,0] ); + pls[0][3].point.should.be.eql( [10,0,0] ); - }); + }); }); -describe("verb.eval.Intersect.kdTreeFromSegments",function(){ +describe("verb.eval.Intersect.kdTreeFromSegments",() => { - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { - var segs = [ - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [1,2,3], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [5,6,7], 0, 0 )), - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [2,2,3], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [6,6,7], 0, 0 )), - new verb.core.Interval( - new verb.core.MeshIntersectionPoint([0,0], [0,0], [3,2,3], 0, 0 ), - new verb.core.MeshIntersectionPoint([0,0], [0,0], [7,6,7], 0, 0 )) ]; + var segs = [ + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [1,2,3], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [5,6,7], 0, 0 )), + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [2,2,3], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [6,6,7], 0, 0 )), + new verb.core.Interval( + new verb.core.MeshIntersectionPoint([0,0], [0,0], [3,2,3], 0, 0 ), + new verb.core.MeshIntersectionPoint([0,0], [0,0], [7,6,7], 0, 0 )) ]; - var tree = verb.eval.Intersect.kdTreeFromSegments( segs ); + var tree = verb.eval.Intersect.kdTreeFromSegments( segs ); - tree.should.not.be.null; + tree.should.not.be.null; - }); + }); }); -describe("verb.eval.Intersect.meshes",function(){ +describe("verb.eval.Intersect.meshes",() => { - it('is correct for two intersecting triangles', function(){ + it('is correct for two intersecting triangles', () => { - var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; - var tris1 = [[ 0, 1, 2 ]]; - var uvs1 = [ [0,0], [2,0], [2, 2] ]; - var mesh1 = new verb.core.MeshData(tris1, pts1, null, uvs1); + var pts1 = [ [0,0,0], [2,0,0], [2, 2,0] ]; + var tris1 = [[ 0, 1, 2 ]]; + var uvs1 = [ [0,0], [2,0], [2, 2] ]; + var mesh1 = new verb.core.MeshData(tris1, pts1, null, uvs1); - var pts2 = [ [1,1,-1], [1,1,5], [1,-5,-1] ]; - var tris2 = [[ 0, 1, 2 ]]; - var uvs2 = [ [0,0], [3,0], [3,3] ]; - var mesh2 = new verb.core.MeshData(tris2, pts2, null, uvs2); + var pts2 = [ [1,1,-1], [1,1,5], [1,-5,-1] ]; + var tris2 = [[ 0, 1, 2 ]]; + var uvs2 = [ [0,0], [3,0], [3,3] ]; + var mesh2 = new verb.core.MeshData(tris2, pts2, null, uvs2); - var pls = verb.eval.Intersect.meshes( mesh1, mesh2 ); + var pls = verb.eval.Intersect.meshes( mesh1, mesh2 ); - pls.length.should.be.equal( 1 ); - pls[0].length.should.be.equal( 2 ); + pls.length.should.be.equal( 1 ); + pls[0].length.should.be.equal( 2 ); - }); + }); - it('is correct for two non-intersecting triangles', function(){ + it('is correct for two non-intersecting triangles', () => { - var pts1 = [ [10,10,10], [2,10,10], [2, 2,10] ]; - var tris1 = [[ 0, 1, 2 ]]; - var uvs1 = [ [0,0], [2,0], [2, 2] ]; - var mesh1 = new verb.core.MeshData(tris1, pts1, null, uvs1); + var pts1 = [ [10,10,10], [2,10,10], [2, 2,10] ]; + var tris1 = [[ 0, 1, 2 ]]; + var uvs1 = [ [0,0], [2,0], [2, 2] ]; + var mesh1 = new verb.core.MeshData(tris1, pts1, null, uvs1); - var pts2 = [ [1,1,-1], [3,1,-1], [3,1,2] ]; - var tris2 = [[ 0, 1, 2 ]]; - var uvs2 = [ [0,0], [3,0], [3,3] ]; - var mesh2 = new verb.core.MeshData(tris2, pts2, null, uvs2); + var pts2 = [ [1,1,-1], [3,1,-1], [3,1,2] ]; + var tris2 = [[ 0, 1, 2 ]]; + var uvs2 = [ [0,0], [3,0], [3,3] ]; + var mesh2 = new verb.core.MeshData(tris2, pts2, null, uvs2); - var res = verb.eval.Intersect.meshes( mesh1, mesh2 ); + var res = verb.eval.Intersect.meshes( mesh1, mesh2 ); - res.length.should.be.equal( 0 ); + res.length.should.be.equal( 0 ); - }); + }); - it('is correct for two intersecting four point surfaces', function(){ + it('is correct for two intersecting four point surfaces', () => { - var p1 = [0,0,0] - , p2 = [1,0,0] - , p3 = [1,1,0] - , p4 = [0,1,0]; + var p1 = [0,0,0] + , p2 = [1,0,0] + , p3 = [1,1,0] + , p4 = [0,1,0]; - var srf1 = verb.eval.Make.fourPointSurface( p1, p2, p3, p4 ); + var srf1 = verb.eval.Make.fourPointSurface( p1, p2, p3, p4 ); - var p5 = [0.5,-0.5,-0.5] - , p6 = [0.5,0.5,-0.5] - , p7 = [0.5,0.5,0.5] - , p8 = [0.5,-0.5,0.5]; + var p5 = [0.5,-0.5,-0.5] + , p6 = [0.5,0.5,-0.5] + , p7 = [0.5,0.5,0.5] + , p8 = [0.5,-0.5,0.5]; - var srf2 = verb.eval.Make.fourPointSurface( p5, p6, p7, p8 ); + var srf2 = verb.eval.Make.fourPointSurface( p5, p6, p7, p8 ); - var tess1 = verb.eval.Tess.rationalSurfaceAdaptive( srf1 ); - var tess2 = verb.eval.Tess.rationalSurfaceAdaptive( srf2 ); + var tess1 = verb.eval.Tess.rationalSurfaceAdaptive( srf1 ); + var tess2 = verb.eval.Tess.rationalSurfaceAdaptive( srf2 ); - var res = verb.eval.Intersect.meshes( tess1, tess2 ); + var res = verb.eval.Intersect.meshes( tess1, tess2 ); - res.length.should.be.equal( 1 ); - }); + res.length.should.be.equal( 1 ); + }); }); -describe("verb.eval.Eval.volumePoint",function(){ +describe("verb.eval.Eval.volumePoint",() => { - it('gives valid result for uniform 3x3x3 cube', function(){ + it('gives valid result for uniform 3x3x3 cube', () => { - var degreeU = 1 - , knotsU = [ 0,0,0.5,1,1 ] - , degreeV = 1 - , knotsV = [ 0,0,0.5,1,1 ] - , degreeW = 1 - , knotsW = [ 0,0,0.5,1,1 ] - , controlPoints = []; + var degreeU = 1 + , knotsU = [ 0,0,0.5,1,1 ] + , degreeV = 1 + , knotsV = [ 0,0,0.5,1,1 ] + , degreeW = 1 + , knotsW = [ 0,0,0.5,1,1 ] + , controlPoints = []; - // build a 3d grid of points - for (var i = 0; i < 3; i++){ + // build a 3d grid of points + for (var i = 0; i < 3; i++){ - var row = []; - controlPoints.push( row ); + var row = []; + controlPoints.push( row ); - for (var j = 0; j < 3; j++){ + for (var j = 0; j < 3; j++){ - var col = []; - row.push( col ); + var col = []; + row.push( col ); - for (var k = 0; k < 3; k++){ + for (var k = 0; k < 3; k++){ - col.push( [ i/2, j/2, k/2 ] ); + col.push( [ i/2, j/2, k/2 ] ); - } - } - } + } + } + } - var volume = new verb.core.VolumeData( degreeU, degreeV, degreeW, knotsU, knotsV, knotsW, controlPoints ); + var volume = new verb.core.VolumeData( degreeU, degreeV, degreeW, knotsU, knotsV, knotsW, controlPoints ); - // sample a bunch of times and confirm the values are as expected - for (var i = 0; i < 10; i++){ + // sample a bunch of times and confirm the values are as expected + for (var i = 0; i < 10; i++){ - var u = Math.random(), v = Math.random(), w = Math.random() - var result = verb.eval.Eval.volumePoint( volume, u, v, w ); + var u = Math.random(), v = Math.random(), w = Math.random() + var result = verb.eval.Eval.volumePoint( volume, u, v, w ); - result[0].should.be.approximately( u, verb.core.Constants.TOLERANCE ); - result[1].should.be.approximately( v, verb.core.Constants.TOLERANCE ); - result[2].should.be.approximately( w, verb.core.Constants.TOLERANCE ); + result[0].should.be.approximately( u, verb.core.Constants.TOLERANCE ); + result[1].should.be.approximately( v, verb.core.Constants.TOLERANCE ); + result[2].should.be.approximately( w, verb.core.Constants.TOLERANCE ); - } + } - }); + }); }); function sameCurve( crvd0, crvd1 ){ - var u0 = crvd0.knots[0]; - var u1 = crvd0.knots[crvd0.knots.length-1]; + var u0 = crvd0.knots[0]; + var u1 = crvd0.knots[crvd0.knots.length-1]; - var u01 = crvd1.knots[0]; - var u11 = crvd1.knots[crvd1.knots.length-1]; + var u01 = crvd1.knots[0]; + var u11 = crvd1.knots[crvd1.knots.length-1]; - u0.should.be.approximately(u01, 1e-10); - u1.should.be.approximately(u11, 1e-10); + u0.should.be.approximately(u01, 1e-10); + u1.should.be.approximately(u11, 1e-10); - var numSamples = 100; - var step = (u1 - u0) / (numSamples-1); + var numSamples = 100; + var step = (u1 - u0) / (numSamples-1); - for (var i = 0; i < numSamples; i++ ){ - var p0 = verb.eval.Eval.rationalCurvePoint( crvd0, u0 + step*i ); - var p1 = verb.eval.Eval.rationalCurvePoint( crvd1, u0 + step*i ); + for (var i = 0; i < numSamples; i++ ){ + var p0 = verb.eval.Eval.rationalCurvePoint( crvd0, u0 + step*i ); + var p1 = verb.eval.Eval.rationalCurvePoint( crvd1, u0 + step*i ); - var dist = verb.core.Vec.dist( p0, p1 ); - dist.should.be.lessThan( verb.core.Constants.TOLERANCE ); - } + var dist = verb.core.Vec.dist( p0, p1 ); + dist.should.be.lessThan( verb.core.Constants.TOLERANCE ); + } } -describe("verb.eval.Modify.curveElevateDegree",function(){ +describe("verb.eval.Modify.curveElevateDegree",() => { - // line from [5,5,5] to [5,5,-5] - var degree_crv = 2 - , knots_crv = [1,1,1,2,2,2] - , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.4,4.8,0,1], [5.2,5.2,-5,1] ] - , bezierCurveData = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); + // line from [5,5,5] to [5,5,-5] + var degree_crv = 2 + , knots_crv = [1,1,1,2,2,2] + , homo_controlPoints_crv = [ [5.2,5.2,5,1], [5.4,4.8,0,1], [5.2,5.2,-5,1] ] + , bezierCurveData = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ); - var lineCurveData = new verb.core.NurbsCurveData( 1, [0,0,1,1], [[7,3,-10,1], [5,4,3,1]] ); + var lineCurveData = new verb.core.NurbsCurveData( 1, [0,0,1,1], [[7,3,-10,1], [5,4,3,1]] ); - it('can elevate degree 2 bezier to degree 3', function(){ - var curveData = verb.eval.Modify.curveElevateDegree( bezierCurveData, 3 ); + it('can elevate degree 2 bezier to degree 3', () => { + var curveData = verb.eval.Modify.curveElevateDegree( bezierCurveData, 3 ); - curveData.degree.should.be.equal( 3 ); - sameCurve( bezierCurveData, curveData ); - }); + curveData.degree.should.be.equal( 3 ); + sameCurve( bezierCurveData, curveData ); + }); - it('can elevate degree 2 bezier to degree 4', function(){ - var curveData = verb.eval.Modify.curveElevateDegree( bezierCurveData, 4 ); + it('can elevate degree 2 bezier to degree 4', () => { + var curveData = verb.eval.Modify.curveElevateDegree( bezierCurveData, 4 ); - curveData.degree.should.be.equal( 4 ); - sameCurve( bezierCurveData, curveData ); - }); + curveData.degree.should.be.equal( 4 ); + sameCurve( bezierCurveData, curveData ); + }); - it('can elevate degree 1 line to degree 3', function(){ - var curveData = verb.eval.Modify.curveElevateDegree( lineCurveData, 3 ); + it('can elevate degree 1 line to degree 3', () => { + var curveData = verb.eval.Modify.curveElevateDegree( lineCurveData, 3 ); - curveData.degree.should.be.equal( 3 ); - sameCurve( lineCurveData, curveData ); - }); + curveData.degree.should.be.equal( 3 ); + sameCurve( lineCurveData, curveData ); + }); }); -describe("verb.eval.Modify.unifyCurveKnotVectors",function(){ +describe("verb.eval.Modify.unifyCurveKnotVectors",() => { - var c0 = new verb.core.NurbsCurveData( 2, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - var c1 = new verb.core.NurbsCurveData( 3, [0,0,0,0,1,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1] ] ); - var c2 = new verb.core.NurbsCurveData( 3, [0,0,0,0,0.5,1,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] ); + var c0 = new verb.core.NurbsCurveData( 2, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + var c1 = new verb.core.NurbsCurveData( 3, [0,0,0,0,1,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1] ] ); + var c2 = new verb.core.NurbsCurveData( 3, [0,0,0,0,0.5,1,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [3,0,0,1], [4,0,0,1] ] ); - it('can handle straight beziers', function(){ + it('can handle straight beziers', () => { - var curves = [c0, c1, c2] - var res = verb.eval.Modify.unifyCurveKnotVectors(curves); + var curves = [c0, c1, c2] + var res = verb.eval.Modify.unifyCurveKnotVectors(curves); - res.forEach(function(x,i){ - sameCurve(x, curves[i]); - x.knots.should.eql( c2.knots ); - }); + res.forEach(function(x,i){ + sameCurve(x, curves[i]); + x.knots.should.eql( c2.knots ); + }); - }); + }); }); -describe("verb.eval.Make.loftedSurface",function(){ +describe("verb.eval.Make.loftedSurface",() => { - var c0 = new verb.core.NurbsCurveData( 2, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - var c1 = new verb.core.NurbsCurveData( 3, [0,0,0,0,1,1,1,1], [ [0,0,1,1], [1,0,1,1], [2,0,1,1], [3,0,1,1] ] ); - var c2 = new verb.core.NurbsCurveData( 3, [0,0,0,0,0.5,1,1,1,1], [ [0,0,2,1], [1,0,2,1], [2,0,2,1], [3,0,2,1], [4,0,2,1] ] ); + var c0 = new verb.core.NurbsCurveData( 2, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + var c1 = new verb.core.NurbsCurveData( 3, [0,0,0,0,1,1,1,1], [ [0,0,1,1], [1,0,1,1], [2,0,1,1], [3,0,1,1] ] ); + var c2 = new verb.core.NurbsCurveData( 3, [0,0,0,0,0.5,1,1,1,1], [ [0,0,2,1], [1,0,2,1], [2,0,2,1], [3,0,2,1], [4,0,2,1] ] ); - it('can handle straight beziers', function(){ + it('can handle straight beziers', () => { - var curves = [c0, c1, c2]; - var surface = verb.eval.Make.loftedSurface( curves ); + var curves = [c0, c1, c2]; + var surface = verb.eval.Make.loftedSurface( curves ); - var p0 = verb.eval.Eval.dehomogenize( c0.controlPoints[0] ); - var closest0 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p0 ) ; - vecShouldBe( p0, closest0 ); + var p0 = verb.eval.Eval.dehomogenize( c0.controlPoints[0] ); + var closest0 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p0 ) ; + vecShouldBe( p0, closest0 ); - var p1 = verb.eval.Eval.dehomogenize( c0.controlPoints[2] ); - var closest1 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p1 ) ; - vecShouldBe( p1, closest1 ); + var p1 = verb.eval.Eval.dehomogenize( c0.controlPoints[2] ); + var closest1 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p1 ) ; + vecShouldBe( p1, closest1 ); - var p2 = verb.eval.Eval.dehomogenize( c1.controlPoints[0] ); - var closest2 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p2 ) ; - vecShouldBe( p2, closest2 ); + var p2 = verb.eval.Eval.dehomogenize( c1.controlPoints[0] ); + var closest2 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p2 ) ; + vecShouldBe( p2, closest2 ); - var p3 = verb.eval.Eval.dehomogenize( c1.controlPoints[3] ); - var closest3 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p3 ) ; - vecShouldBe( p3, closest3 ); + var p3 = verb.eval.Eval.dehomogenize( c1.controlPoints[3] ); + var closest3 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p3 ) ; + vecShouldBe( p3, closest3 ); - var p4 = verb.eval.Eval.dehomogenize( c2.controlPoints[0] ); - var closest4 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p4 ) ; - vecShouldBe( p4, closest4 ); + var p4 = verb.eval.Eval.dehomogenize( c2.controlPoints[0] ); + var closest4 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p4 ) ; + vecShouldBe( p4, closest4 ); - var p5 = verb.eval.Eval.dehomogenize( c2.controlPoints[4] ); - var closest5 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p5 ) ; - vecShouldBe( p5, closest5 ); + var p5 = verb.eval.Eval.dehomogenize( c2.controlPoints[4] ); + var closest5 = verb.eval.Analyze.rationalSurfaceClosestPoint( surface, p5 ) ; + vecShouldBe( p5, closest5 ); - }); + }); }); -describe("verb.eval.Check.isValidNurbsCurveData",function(){ +describe("verb.eval.Check.isValidNurbsCurveData",() => { - it('is correct for basic case', function(){ - var c = new verb.core.NurbsCurveData( 2, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - verb.eval.Check.isValidNurbsCurveData(c); - }); + it('is correct for basic case', () => { + var c = new verb.core.NurbsCurveData( 2, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + verb.eval.Check.isValidNurbsCurveData(c); + }); - it('detects negative degree', function( done ){ - var c = new verb.core.NurbsCurveData( -1, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects negative degree', function( done ){ + var c = new verb.core.NurbsCurveData( -1, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects low degree', function( done ){ - var c = new verb.core.NurbsCurveData( 1, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects low degree', function( done ){ + var c = new verb.core.NurbsCurveData( 1, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects high degree', function( done ){ - var c = new verb.core.NurbsCurveData( 3, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects high degree', function( done ){ + var c = new verb.core.NurbsCurveData( 3, [0,0,0,1,1,1], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects null degree', function( done ){ - var c = new verb.core.NurbsCurveData( null, [0,0,0,0.5,1,1,2], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects null degree', function( done ){ + var c = new verb.core.NurbsCurveData( null, [0,0,0,0.5,1,1,2], [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects null knots', function( done ){ - var c = new verb.core.NurbsCurveData( 2, null, [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects null knots', function( done ){ + var c = new verb.core.NurbsCurveData( 2, null, [ [0,0,0,1], [1,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects null control points', function( done ){ - var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.5,1,1,2], null ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects null control points', function( done ){ + var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.5,1,1,2], null ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects too few control points', function( done ){ - var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.5,1,1,2], [ [0,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects too few control points', function( done ){ + var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.5,1,1,2], [ [0,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); - it('detects too many control points', function( done ){ - var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.5,1,1,2], [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [2,0,0,1] ] ); - try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } - }); + it('detects too many control points', function( done ){ + var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.5,1,1,2], [ [0,0,0,1], [1,0,0,1], [2,0,0,1], [2,0,0,1] ] ); + try { verb.eval.Check.isValidNurbsCurveData(c) } catch (e) { done(); } + }); }); -describe("verb.eval.Check.isValidNurbsSurfaceData",function(){ +describe("verb.eval.Check.isValidNurbsSurfaceData",() => { - 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] ] ]; + 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] ] ]; - it('is correct for basic case', function(){ - var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - verb.eval.Check.isValidNurbsSurfaceData(c); - }); + it('is correct for basic case', () => { + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + verb.eval.Check.isValidNurbsSurfaceData(c); + }); - it('detects negative degree', function( done ){ - var c = new verb.core.NurbsSurfaceData( -1, degreeV, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects negative degree', function( done ){ + var c = new verb.core.NurbsSurfaceData( -1, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects negative degree', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, -1, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects negative degree', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, -1, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects low degreeU', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, 1, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects low degreeU', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, 1, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects low degreeV', function( done ){ - var c = new verb.core.NurbsSurfaceData( 1, degreeV, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects low degreeV', function( done ){ + var c = new verb.core.NurbsSurfaceData( 1, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects high degreeU', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, 5, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects high degreeU', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, 5, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects high degreeV', function( done ){ - var c = new verb.core.NurbsSurfaceData( 5, degreeV, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects high degreeV', function( done ){ + var c = new verb.core.NurbsSurfaceData( 5, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects null degreeU', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, 1, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects null degreeU', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, 1, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects null degreeV', function( done ){ - var c = new verb.core.NurbsSurfaceData( 1, degreeV, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects null degreeV', function( done ){ + var c = new verb.core.NurbsSurfaceData( 1, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects null knotsU', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, null, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects null knotsU', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, null, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects null knotsV', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, null, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects null knotsV', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, null, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects null control points', function( done ){ - var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, null ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects null control points', function( done ){ + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, null ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects too few control points', function( done ){ - var 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] ] ]; - var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + it('detects too few control points', function( done ){ + var 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] ] ]; + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + }); - it('detects too many control points', function( done ){ - var 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, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ], - [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]; + it('detects too many control points', function( done ){ + var 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, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ]; - var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } - }); + }); }); -describe("verb.eval.Check.isValidKnotVector",function(){ +describe("verb.eval.Check.isValidKnotVector",() => { - it('detects correct knot vector', function(){ - verb.eval.Check.isValidKnotVector( [0,0,0,1,1,1], 2 ).should.be.equal(true); - verb.eval.Check.isValidKnotVector( [0,0,0,0.5,1,1,1], 2 ).should.be.equal(true); - }); + it('detects correct knot vector', () => { + verb.eval.Check.isValidKnotVector( [0,0,0,1,1,1], 2 ).should.be.equal(true); + verb.eval.Check.isValidKnotVector( [0,0,0,0.5,1,1,1], 2 ).should.be.equal(true); + }); - it('detects incorrect knot vector 0', function(){ - verb.eval.Check.isValidKnotVector( [0,0,1,1,1], 2 ).should.be.equal(false); - }); + it('detects incorrect knot vector 0', () => { + verb.eval.Check.isValidKnotVector( [0,0,1,1,1], 2 ).should.be.equal(false); + }); - it('detects incorrect knot vector 1', function(){ - verb.eval.Check.isValidKnotVector( [0,0,0.5,1,1,1], 2 ).should.be.equal(false); - }); + it('detects incorrect knot vector 1', () => { + verb.eval.Check.isValidKnotVector( [0,0,0.5,1,1,1], 2 ).should.be.equal(false); + }); - it('detects incorrect knot vector 2', function(){ - verb.eval.Check.isValidKnotVector( [0,0,0,1,1,2], 2 ).should.be.equal(false); - }); + it('detects incorrect knot vector 2', () => { + verb.eval.Check.isValidKnotVector( [0,0,0,1,1,2], 2 ).should.be.equal(false); + }); - it('detects incorrect knot vector 3', function(){ - verb.eval.Check.isValidKnotVector( [0,0,0,0.5,1,1,2], 2 ).should.be.equal(false); - }); + it('detects incorrect knot vector 3', () => { + verb.eval.Check.isValidKnotVector( [0,0,0,0.5,1,1,2], 2 ).should.be.equal(false); + }); - it('detects incorrect knot vector 4', function(){ - verb.eval.Check.isValidKnotVector( [0,0,0,0.5,0.25,1,1,1], 2 ).should.be.equal(false); - }); + it('detects incorrect knot vector 4', () => { + verb.eval.Check.isValidKnotVector( [0,0,0,0.5,0.25,1,1,1], 2 ).should.be.equal(false); + }); }); -describe("verb.eval.Intersect.meshes",function(){ +describe("verb.eval.Intersect.meshes",() => { - function glancingPlaneCylindricalSurface(){ + function glancingPlaneCylindricalSurface(){ - var axis = [0,0,1] - , xaxis = [1,0,0] - , base = [0,0,0] - , height = 5 - , radius = 3; + var axis = [0,0,1] + , xaxis = [1,0,0] + , base = [0,0,0] + , height = 5 + , radius = 3; - var srf1 = new verb.geom.CylindricalSurface( axis, xaxis, base, height, radius ); + var srf1 = new verb.geom.CylindricalSurface( axis, xaxis, base, height, radius ); - var p5 = [5,5,0] - , p6 = [-5,5,0] - , p7 = [-5,-5,0] - , p8 = [5,-5,0]; + var p5 = [5,5,0] + , p6 = [-5,5,0] + , p7 = [-5,-5,0] + , p8 = [5,-5,0]; - var srf2 = verb.geom.NurbsSurface.byCorners( p5, p6, p7, p8 ); + var srf2 = verb.geom.NurbsSurface.byCorners( p5, p6, p7, p8 ); - return [srf1, srf2]; + return [srf1, srf2]; - } + } - function nurbsSurfacePlane(){ + function nurbsSurfacePlane(){ - 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, 9] ], - [ [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, 0], [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] ], ]; - var srf1 = new verb.geom.NurbsSurface.byKnotsControlPointsWeights( degree, degree, knots, knots, pts ); - - var p5 = [50,-50,3] - , p6 = [50,0,3] - , p7 = [0,0,3] - , p8 = [0,-50,5]; - - var srf2 = verb.geom.NurbsSurface.byCorners( p5, p6, p7, p8 ); - - return [srf1,srf2]; - } - - function torusCylindricalSurface(){ - // center, xaxis, yaxis, radius - var profile = new verb.geom.Circle( [5,0,0], [1,0,0], [0,0,1], 2 ); - - var base = [0,0,0]; - var axis = [0,0,1]; - var angle = 2 * Math.PI - var srf1 = new verb.geom.RevolvedSurface( profile, base, axis, angle ); - - var axis = [-1,0,0] - , xaxis = [0,0,1] - , base = [8,0,0] - , height = 16 - , radius = 2; - - var srf2 = new verb.geom.CylindricalSurface( axis, xaxis, base, height, radius ); - - return [srf1,srf2]; - } - - it('detects all 4 polylines in nurbs surface plane intersection', function(){ - var srfs = nurbsSurfacePlane(); - var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); - - res.length.should.be.equal( 4 ); - }); + 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, 9] ], + [ [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, 0], [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] ], ]; + var srf1 = new verb.geom.NurbsSurface.byKnotsControlPointsWeights( degree, degree, knots, knots, pts ); - it('detects all 8 intersection lines in torus cylinder intersection', function(){ - var srfs = torusCylindricalSurface(); - var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); + var p5 = [50,-50,3] + , p6 = [50,0,3] + , p7 = [0,0,3] + , p8 = [0,-50,5]; - res.length.should.be.equal( 8 ); - }); + var srf2 = verb.geom.NurbsSurface.byCorners( p5, p6, p7, p8 ); - it('detects glancing intersection between cylinder and plane', function(){ - var srfs = glancingPlaneCylindricalSurface(); - var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); + return [srf1,srf2]; + } - res.length.should.be.equal( 1 ); - }); + function torusCylindricalSurface(){ + // center, xaxis, yaxis, radius + var profile = new verb.geom.Circle( [5,0,0], [1,0,0], [0,0,1], 2 ); + + var base = [0,0,0]; + var axis = [0,0,1]; + var angle = 2 * Math.PI + var srf1 = new verb.geom.RevolvedSurface( profile, base, axis, angle ); + + var axis = [-1,0,0] + , xaxis = [0,0,1] + , base = [8,0,0] + , height = 16 + , radius = 2; + + var srf2 = new verb.geom.CylindricalSurface( axis, xaxis, base, height, radius ); + + return [srf1,srf2]; + } + + it('detects all 4 polylines in nurbs surface plane intersection', () => { + var srfs = nurbsSurfacePlane(); + var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); + + res.length.should.be.equal( 4 ); + }); + + it('detects all 8 intersection lines in torus cylinder intersection', () => { + var srfs = torusCylindricalSurface(); + var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); + + res.length.should.be.equal( 8 ); + }); + + it('detects glancing intersection between cylinder and plane', () => { + var srfs = glancingPlaneCylindricalSurface(); + var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); + + res.length.should.be.equal( 1 ); + }); }); -describe("verb.eval.Modify.knotsReverse",function(){ - it('can reverse basic knot array', function(){ - verb.eval.Modify.knotsReverse( [0,1,3,5] ).should.be.eql( [0,2,4,5] ); - }); +describe("verb.eval.Modify.knotsReverse",() => { + it('can reverse basic knot array', () => { + verb.eval.Modify.knotsReverse( [0,1,3,5] ).should.be.eql( [0,2,4,5] ); + }); }); -describe("verb.eval.Modify.curveReverse",function(){ - it('can reverse curve with uneven parameterization', function(){ - var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.24,1,1,1], [ [0,0,0,1], [1,0,0,1], [0.5,1,0,1], [2,0,0,1] ] ); - var cr = verb.eval.Modify.curveReverse( c ); - var crr = verb.eval.Modify.curveReverse( cr ); +describe("verb.eval.Modify.curveReverse",() => { + it('can reverse curve with uneven parameterization', () => { + var c = new verb.core.NurbsCurveData( 2, [0,0,0,0.24,1,1,1], [ [0,0,0,1], [1,0,0,1], [0.5,1,0,1], [2,0,0,1] ] ); + var cr = verb.eval.Modify.curveReverse( c ); + var crr = verb.eval.Modify.curveReverse( cr ); - var cp0 = verb.eval.Eval.rationalCurvePoint( c, 0 ); - var cp1 = verb.eval.Eval.rationalCurvePoint( cr, 1.0 ); + var cp0 = verb.eval.Eval.rationalCurvePoint( c, 0 ); + var cp1 = verb.eval.Eval.rationalCurvePoint( cr, 1.0 ); - vecShouldBe( cp0, cp1, verb.core.Constants.EPSILON ); + vecShouldBe( cp0, cp1, verb.core.Constants.EPSILON ); - sameCurve( c, crr ); - }); + sameCurve( c, crr ); + }); }); -describe("verb.eval.Modify.surfaceReverse",function(){ +describe("verb.eval.Modify.surfaceReverse",() => { - var degreeU = 3 - , degreeV = 3 - , knotsU = [0, 0, 0, 0, 0.25, 1, 1, 1, 1] - , knotsV = [0, 0, 0, 0, 0.70, 1, 1, 1, 1] - , controlPoints = [ [ [0, 0, 0], [10, 0, 0], [20, 0, 0], [25, 0, 0], [30, 0, 0] ], - [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [25, -10, 0], [30, -10, 0] ], - [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [25, -20, 0], [30, -20, 0] ], - [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [25, -20, 0], [30, -20, 0] ], - [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [25, -30, 0], [30, -30, 0] ] ] - , s = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + var degreeU = 3 + , degreeV = 3 + , knotsU = [0, 0, 0, 0, 0.25, 1, 1, 1, 1] + , knotsV = [0, 0, 0, 0, 0.70, 1, 1, 1, 1] + , controlPoints = [ [ [0, 0, 0], [10, 0, 0], [20, 0, 0], [25, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [25, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [25, -20, 0], [30, -20, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [25, -20, 0], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [25, -30, 0], [30, -30, 0] ] ] + , s = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - it('is correct for u direction', function(){ + it('is correct for u direction', () => { - var sr = verb.eval.Modify.surfaceReverse( s, true ); + var sr = verb.eval.Modify.surfaceReverse( s, true ); - var sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); - var sp1 = verb.eval.Eval.surfacePoint( sr, 0, 1.0 ); - vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); + var sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); + var sp1 = verb.eval.Eval.surfacePoint( sr, 0, 1.0 ); + vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); - var srr = verb.eval.Modify.surfaceReverse( sr, true ); + var srr = verb.eval.Modify.surfaceReverse( sr, true ); - var sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); - var sp1 = verb.eval.Eval.surfacePoint( srr, 0, 0 ); - vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); + var sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); + var sp1 = verb.eval.Eval.surfacePoint( srr, 0, 0 ); + vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); - var sp0 = verb.eval.Eval.surfacePoint( s, 1.0, 0 ); - var sp1 = verb.eval.Eval.surfacePoint( srr, 1.0, 0 ); - vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); + var sp0 = verb.eval.Eval.surfacePoint( s, 1.0, 0 ); + var sp1 = verb.eval.Eval.surfacePoint( srr, 1.0, 0 ); + vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); - }); + }); - it('is correct for v direction', function(){ + it('is correct for v direction', () => { - var sr = verb.eval.Modify.surfaceReverse( s, false ); + var sr = verb.eval.Modify.surfaceReverse( s, false ); - var sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); - var sp1 = verb.eval.Eval.surfacePoint( sr, 1.0, 0 ); - vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); + var sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); + var sp1 = verb.eval.Eval.surfacePoint( sr, 1.0, 0 ); + vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); - var srr = verb.eval.Modify.surfaceReverse( sr, false ); + var srr = verb.eval.Modify.surfaceReverse( sr, false ); - sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); - sp1 = verb.eval.Eval.surfacePoint( srr, 0, 0 ); - vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); + sp0 = verb.eval.Eval.surfacePoint( s, 0, 0 ); + sp1 = verb.eval.Eval.surfacePoint( srr, 0, 0 ); + vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); - sp0 = verb.eval.Eval.surfacePoint( s, 1.0, 0 ); - sp1 = verb.eval.Eval.surfacePoint( srr, 1.0, 0 ); - vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); + sp0 = verb.eval.Eval.surfacePoint( s, 1.0, 0 ); + sp1 = verb.eval.Eval.surfacePoint( srr, 1.0, 0 ); + vecShouldBe( sp0, sp1, verb.core.Constants.EPSILON ); - }); + }); }); -describe("verb.eval.Intersect.sliceMeshes",function(){ +describe("verb.eval.Intersect.sliceMeshes",() => { - it('is correct for basic example', function(){ + it('is correct for basic example', () => { - var srf = verb.geom.NurbsSurface.byCorners( [0,1,0], [10,0,0], [10,10,10], [0,10,10] ); - var mesh = srf.tessellate(); + var srf = verb.geom.NurbsSurface.byCorners( [0,1,0], [10,0,0], [10,10,10], [0,10,10] ); + var mesh = srf.tessellate(); - var res = verb.eval.Intersect.meshSlices( mesh, 0, 10, 0.5 ); + var res = verb.eval.Intersect.meshSlices( mesh, 0, 10, 0.5 ); // need better example - }); + }); }); -describe("verb.eval.Make.rationalTranslationalSurface",function(){ +describe("verb.eval.Make.rationalTranslationalSurface",() => { - it('provides expected result for linear rail and profile', function(){ + it('provides expected result for linear rail and profile', () => { - var rail = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1]] ); + var rail = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1]] ); var prof = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,0,0]] ); var srf = verb.eval.Make.rationalTranslationalSurface( prof, rail ); @@ -3675,9 +3511,9 @@ describe("verb.eval.Make.rationalTranslationalSurface",function(){ vecShouldBe( verb.eval.Eval.rationalSurfacePoint( srf, 1, 1 ), [2,1,1] ); vecShouldBe( verb.eval.Eval.rationalSurfacePoint( srf, 0, 1 ), [1,1,1] ); - }); + }); - it('provides expected result for linear profile, curved rail', function(){ + it('provides expected result for linear profile, curved rail', () => { var rail = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,0.5,1], [2,1,1]] ); var prof = verb.eval.Make.rationalBezierCurve( [[0,0,0], [2,0,0]] ); @@ -3693,20 +3529,20 @@ describe("verb.eval.Make.rationalTranslationalSurface",function(){ }); -describe("verb.eval.Make.surfaceIsocurve",function(){ +describe("verb.eval.Make.surfaceIsocurve",() => { - 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, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], - [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], - [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] ], - [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] - , bezier = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + 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, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , bezier = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - it('provides boundary isocurves at extremes of domain', function(){ + it('provides boundary isocurves at extremes of domain', () => { var res = verb.eval.Make.surfaceIsocurve( bezier, 0, false ); @@ -3720,28 +3556,28 @@ describe("verb.eval.Make.surfaceIsocurve",function(){ }); - it('provides isocurves at expected location in v direction', function(){ + it('provides isocurves at expected location in v direction', () => { - for (var i = 0; i <= 1.0; i += 0.1 ){ + for (var i = 0; i <= 1.0; i += 0.1 ){ - var res = verb.eval.Make.surfaceIsocurve( bezier, i, true ); + var res = verb.eval.Make.surfaceIsocurve( bezier, i, true ); - var cpts = res.controlPoints; + var cpts = res.controlPoints; - var pt0 = verb.eval.Eval.surfacePoint( bezier, 0.0, i ); - var pt1 = verb.eval.Eval.surfacePoint( bezier, 1.0, i ); + var pt0 = verb.eval.Eval.surfacePoint( bezier, 0.0, i ); + var pt1 = verb.eval.Eval.surfacePoint( bezier, 1.0, i ); - vecShouldBe( pt0, cpts[0] ); - vecShouldBe( pt1, cpts[cpts.length-1] ); + vecShouldBe( pt0, cpts[0] ); + vecShouldBe( pt1, cpts[cpts.length-1] ); - } + } - }); + }); }); -describe("verb.eval.Make.surfaceBoundaryCurves",function(){ +describe("verb.eval.Make.surfaceBoundaryCurves",() => { - it('provides expected result for planar surface', function(){ + it('provides expected result for planar surface', () => { var a = [0,0,0]; var b = [1,0,0]; @@ -3773,134 +3609,951 @@ describe("verb.eval.Make.surfaceBoundaryCurves",function(){ }); -describe("verb.eval.Intersect.segmentAndPlane",function(){ - it('works for simple cases', function(){ - verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,0,1], [0,0,0.5], [0,0,1] ).p.should.be.approximately( 0.5, verb.core.Constants.EPSILON ); - verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,0,1], [0,0,0.1], [0,0,1] ).p.should.be.approximately( 0.1, verb.core.Constants.EPSILON ); - verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,0,1], [0,0,0.9], [0,0,1] ).p.should.be.approximately( 0.9, verb.core.Constants.EPSILON ); - verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,1,0], [0,0.5,0], [0,1,0] ).p.should.be.approximately( 0.5, verb.core.Constants.EPSILON ); - verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,1,0], [0,0.1,0], [0,1,0] ).p.should.be.approximately( 0.1, verb.core.Constants.EPSILON ); - }); +describe("verb.eval.Intersect.segmentAndPlane",() => { + it('works for simple cases', () => { + verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,0,1], [0,0,0.5], [0,0,1] ).p.should.be.approximately( 0.5, verb.core.Constants.EPSILON ); + verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,0,1], [0,0,0.1], [0,0,1] ).p.should.be.approximately( 0.1, verb.core.Constants.EPSILON ); + verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,0,1], [0,0,0.9], [0,0,1] ).p.should.be.approximately( 0.9, verb.core.Constants.EPSILON ); + verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,1,0], [0,0.5,0], [0,1,0] ).p.should.be.approximately( 0.5, verb.core.Constants.EPSILON ); + verb.eval.Intersect.segmentAndPlane( [0,0,0], [0,1,0], [0,0.1,0], [0,1,0] ).p.should.be.approximately( 0.1, verb.core.Constants.EPSILON ); + }); }); -describe("verb.eval.Make.rationalInterpCurve",function(){ +describe("verb.eval.Make.rationalInterpCurve",() => { - function shouldInterpPointsWithTangents(pts, degree, isHomo, start_tangent, end_tangent){ + function shouldInterpPointsWithTangents(pts, degree, isHomo, start_tangent, end_tangent){ - var crv = shouldInterpPoints(pts, degree, isHomo, start_tangent, end_tangent); + var crv = shouldInterpPoints(pts, degree, isHomo, start_tangent, end_tangent); - var tan0 = verb.eval.Eval.rationalCurveDerivatives( crv, 0, 1)[1]; - var tan1 = verb.eval.Eval.rationalCurveDerivatives( crv, 1, 1)[1]; + var tan0 = verb.eval.Eval.rationalCurveDerivatives( crv, 0, 1)[1]; + var tan1 = verb.eval.Eval.rationalCurveDerivatives( crv, 1, 1)[1]; - vecShouldBe( start_tangent, tan0 ); - vecShouldBe( end_tangent, tan1 ); + vecShouldBe( start_tangent, tan0 ); + vecShouldBe( end_tangent, tan1 ); - } + } - function shouldInterpPoints(pts, degree, isHomo, start_tangent, end_tangent){ + function shouldInterpPoints(pts, degree, isHomo, start_tangent, end_tangent){ - var crv = verb.eval.Make.rationalInterpCurve( pts, degree, isHomo, start_tangent, end_tangent ); + var crv = verb.eval.Make.rationalInterpCurve( pts, degree, isHomo, start_tangent, end_tangent ); - crv.degree.should.be.equal( degree ); + crv.degree.should.be.equal( degree ); - crv.controlPoints[0][0].should.be.approximately(pts[0][0], verb.core.Constants.TOLERANCE); - crv.controlPoints[0][1].should.be.approximately(pts[0][1], verb.core.Constants.TOLERANCE); + crv.controlPoints[0][0].should.be.approximately(pts[0][0], verb.core.Constants.TOLERANCE); + crv.controlPoints[0][1].should.be.approximately(pts[0][1], verb.core.Constants.TOLERANCE); - last(crv.controlPoints)[0].should.be.approximately(last(pts)[0], verb.core.Constants.TOLERANCE); - last(crv.controlPoints)[1].should.be.approximately(last(pts)[1], verb.core.Constants.TOLERANCE); + last(crv.controlPoints)[0].should.be.approximately(last(pts)[0], verb.core.Constants.TOLERANCE); + last(crv.controlPoints)[1].should.be.approximately(last(pts)[1], verb.core.Constants.TOLERANCE); - // // the internal points are interped (TODO: do this more efficiently) - var tess = verb.eval.Tess.rationalCurveAdaptiveSample( crv, 1e-8 ); + // // the internal points are interped + var tess = verb.eval.Tess.rationalCurveAdaptiveSample( crv, 1e-3 ); - for (var j = 0; j < pts.length; j++){ + for (var j = 0; j < pts.length; j++){ - var min = Number.MAX_VALUE; - for (var i = 1; i < tess.length; i++){ + var min = Number.MAX_VALUE; + for (var i = 1; i < tess.length; i++){ - var pt = pts[j]; - var o = tess[i-1]; - var r = verb.core.Vec.normalized( verb.core.Vec.sub( tess[i], tess[i-1] ) ); + var pt = pts[j]; + var o = tess[i-1]; + var r = verb.core.Vec.normalized( verb.core.Vec.sub( tess[i], tess[i-1] ) ); - var dist = verb.core.Trig.distToRay( pt, o, r ); + var dist = verb.core.Trig.distToRay( pt, o, r ); - if (dist < min) { - min = dist; - } + if (dist < min) { + min = dist; + } + } - } + min.should.be.lessThan( 1e-3 ); + } - min.should.be.lessThan( 1e-3 ); - } + return crv; + } - return crv; - } + it('can compute valid cubic interpolating curve for 4 points', () => { - it('can compute valid cubic interpolating curve for 4 points', function(){ + var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0] ]; - var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + shouldInterpPoints( pts, 3 ); - shouldInterpPoints( pts, 3 ); + }); - }); + it('can compute valid degree 4 interpolating curve for 4 points', () => { + var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - it('can compute valid degree 4 interpolating curve for 4 points', function(){ + shouldInterpPoints( pts, 4 ); - var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + }); - shouldInterpPoints( pts, 4 ); + it('can compute valid quadratic interpolating curve for 4 points', () => { - }); + var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - it('can compute valid quadratic interpolating curve for 4 points', function(){ + shouldInterpPoints( pts, 2 ); - var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + }); - shouldInterpPoints( pts, 2 ); + it('can compute valid cubic interpolating curve for 100 points', () => { - }); + var pts = []; + for (var i = 0; i < 100; i++){ - it('can compute valid cubic interpolating curve for 100 points', function(){ + pts.push( [ 50 * Math.sin( (i / 100) * Math.PI ), + 50 * Math.cos( (i / 100) * Math.PI ), + 0 ]); - var pts = []; - for (var i = 0; i < 100; i++){ + } - pts.push( [ 50 * Math.sin( (i / 100) * Math.PI ), - 50 * Math.cos( (i / 100) * Math.PI ), - 0 ]); + shouldInterpPoints( pts, 3 ); - } + }); - shouldInterpPoints( pts, 3 ); + it('can compute valid cubic interpolating points and tangents', () => { - }); + var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - it('can compute valid cubic interpolating points and tangents', function(){ + shouldInterpPointsWithTangents( pts, 3, false, [1,0,0], [0,1,0] ); - var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + }); - shouldInterpPointsWithTangents( pts, 3, false, [1,0,0], [0,1,0] ); + // this fails occasionally - don't know why + // it('can compute valid quadratic curve interpolating points and tangents', () => { - }); + // var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - // this fails occasionally - don't know why - // it('can compute valid quadratic curve interpolating points and tangents', function(){ + // shouldInterpPointsWithTangents( pts, 2, false, [1,0,0], [0,1,0] ); - // var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + // }); - // shouldInterpPointsWithTangents( pts, 2, false, [1,0,0], [0,1,0] ); + // it('can compute valid quadratic curve interpolating points and tangents', () => { - // }); + // var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - // it('can compute valid quadratic curve interpolating points and tangents', function(){ + // shouldInterpPointsWithTangents( pts, 4, false, [1,0,0], [0,1,0] ); - // var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + // }); - // shouldInterpPointsWithTangents( pts, 4, false, [1,0,0], [0,1,0] ); +}); - // }); + +describe("verb.eval.Tess.surfaceRegularSample",() => { + + 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; + } + + var complexSurface = getComplexSurface(); + + it('returns correct result for complex surface', () => { + + var p = verb.eval.Tess.surfaceRegularSample( complexSurface, 10, 10 ); + + var ar = []; + var sp = 1 / 10; + + var i, j; + + for (i = 0; i < 11; i++){ + var ari = []; + ar.push(ari); + for (var j = 0; j < 11; j++){ + ari.push( verb.eval.Eval.surfacePoint( complexSurface, i*sp, j*sp ) ) + } + } + + p.length.should.equal(ar.length); + + for (i = 0; i < ar.length; i++){ + + p[i].length.should.equal(ar[i].length); + + for (j = 0; j < ar[i].length; j++){ + vecShouldBe( p[i][j], ar[i][j] ); + } + } + }); +}); + + +describe("verb.eval.Modify.decomposeCurveIntoBeziers",() => { + + it('is correct for a degree 3 spline curve with 5 internal knot spans', () => { + + 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 ); + + }); + }); + + it('is correct for a degree 3 spline curve with 2 internal knot spans', () => { + + var degree = 3 + , knots = [0, 0, 0, 0, 0.3, 0.666, 1, 1, 1, 1 ] + , controlPoints = [ [1,0,1], [1,2,1], [1,1,1], [0,1,2], [0,2,2], [0,2,2] ] + , crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + + var res = verb.eval.Modify.decomposeCurveIntoBeziers( crv ); + + res.length.should.be.equal( 3 ); + + 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.eval.Tess.rationalCurveRegularSample",() => { + + function evalAndCompare(crv){ + + var divs = 100; + var p = verb.eval.Tess.rationalCurveRegularSample( crv, divs ); + + var p2 = []; + var sp = 1 / divs; + + for (var i = 0; i < divs+1; i++){ + p2.push( verb.eval.Eval.rationalCurvePoint( crv, i*sp ) ) + } + + p.length.should.equal( p2.length ); + + for (var i = 0; i < p.length; i++){ + vecShouldBe( p[i], p2[i] ); + } + } + + it('returns correct result for basic bezier curve', () => { + + var crv = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1], [2,1,1], [3,1,0]] ); + evalAndCompare(crv); + + }); + + it('returns correct result for degree 2 b spline curve with 2 internal knot spans', () => { + + var degree = 2 + , knots = [0, 0, 0, 0.3, 1, 1, 1 ] + , controlPoints = [ [1,0,1], [1,2,1], [1,1,1], [0,2,2] ] + , crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + + evalAndCompare(crv); + + }); + + it('returns correct result for degree 2 b spline curve with 3 internal knot spans', () => { + + var degree = 2 + , knots = [0, 0, 0, 0.3, 0.666, 1, 1, 1 ] + , controlPoints = [ [1,0,1], [1,2,1], [1,1,1], [0,1,2], [0,2,2] ] + , crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + + evalAndCompare(crv); + + }); + +}); + +describe("verb.eval.Tess.rationalBezierCurveStepLength",() => { + it('works for simple cases', () => { + + var pts = [ [0, 0, 0], [1, 2, 0], [2, 0, 0], [3, 0, 0] ]; + var crv = verb.eval.Make.rationalInterpCurve( pts, 3, false ); + var l = verb.eval.Tess.rationalBezierCurveStepLength( crv, 0.001 ); + + console.log( l ); + + }); +}); + + + +describe("verb.eval.Tess.rationalBezierSurfaceStepLength",() => { + + function getComplexSurface(){ + + var degree = 3 + , knots = [0, 0, 0, 0, 1, 1, 1, 1] + , pts = [ [ [0, 0, -1], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, -2], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , 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); + + return { + degreeU : degree, + degreeV : degree, + knotsU : knots, + knotsV : knots, + controlPoints : pts + }; + } + + it('works for simple cases', () => { + + var l = verb.eval.Tess.rationalBezierSurfaceStepLength( getComplexSurface(), 0.001 ); + + console.log( l ); + + }); +}); + + + +describe("verb.eval.Eval.curveKnotRefine",() => { + + 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', () => { + + 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.Modify.surfaceKnotRefine",() => { + + 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', () => { + + var r = 3; + 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', () => { + + var r = 3; + 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.Modify.surfaceKnotRefine",() => { + + 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', () => { + + 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 multiple knots into a surface in the u direction', () => { + + var r = 3; + 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', () => { + + 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); + + + }); + + it('can add multiple duplicate knots into a surface in the v direction', () => { + + var r = 4; + 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); + + }); + + it('can add multiple duplicate knots into a bezier patch in the u direction', () => { + + 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, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , bezier = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + + var r = 4; + var u = 0.2; + var new_knots = []; + + for (var i = 0; i < r; i++){ + new_knots.push(u); + } + + var res = verb.eval.Modify.surfaceKnotRefine( bezier, new_knots, false ); + + var d = 20; + + var u0 = u = res.knotsU[0]; + var v0 = v = res.knotsV[0]; + + var ur = res.knotsU[res.knotsU.length-1] - res.knotsV[0]; + var vr = res.knotsV[res.knotsV.length-1] - res.knotsV[0]; + + var us = ur / (d-1); + var vs = vr / (d-1); + + for (var i = 0; i < d; i++){ + + v = v0; + + for (var j= 0; j < d; j++){ + var p0 = verb.eval.Eval.surfacePoint( bezier, u, v); + var p1 = verb.eval.Eval.surfacePoint( res, u, v); + + vecShouldBe(p0, p1); + + u += us; + } + + v += vs; + } + + + 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( bezier, 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 multiple duplicate knots into a bezier patch in the v direction', () => { + + 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, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , bezier = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + + var r = 4; + var u = 0.2; + var new_knots = []; + + for (var i = 0; i < r; i++){ + new_knots.push(u); + } + + var res = verb.eval.Modify.surfaceKnotRefine( bezier, new_knots, true ); + + var d = 20; + + var u0 = u = res.knotsU[0]; + var v0 = v = res.knotsV[0]; + + var ur = res.knotsU[res.knotsU.length-1] - res.knotsV[0]; + var vr = res.knotsV[res.knotsV.length-1] - res.knotsV[0]; + + var us = ur / (d-1); + var vs = vr / (d-1); + + for (var i = 0; i < d; i++){ + + v = v0; + + for (var j= 0; j < d; j++){ + var p0 = verb.eval.Eval.surfacePoint( bezier, u, v); + var p1 = verb.eval.Eval.surfacePoint( res, u, v); + + vecShouldBe(p0, p1); + + u += us; + } + + v += vs; + } + + 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( bezier, 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.Modify.decomposeSurfaceIntoBeziers",() => { + + var getSurface11 = () => { + + 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, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , bezier = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + + return bezier; + }; + + var getSurface23 = () => { + + 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, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] , [40, -20, 0], [50, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ], + [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 0] , [40, -40, -20], [50, -40, 0] ] ] + , surface23 = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); + + return surface23; + }; + + var checkSurfaceDecomposition = (surface, decomp, divsU, divsV) => { + + should.equal( divsU, decomp.length ); + + for (var i = 0; i < divsU; i++){ + should.equal( divsV, decomp[i].length ); + } + + var d = 10; + + decomp.forEach((x,k) => { + x.forEach((y, l) => { + + var u0 = u = y.knotsU[0]; + var v0 = v = y.knotsV[0]; + + var ur = y.knotsU[y.knotsU.length-1] - y.knotsV[0]; + var vr = y.knotsV[y.knotsV.length-1] - y.knotsV[0]; + + var us = ur / (d-1); + var vs = vr / (d-1); + + for (var i = 0; i < d; i++){ + + v = v0; + + for (var j= 0; j < d; j++){ + var p0 = verb.eval.Eval.surfacePoint( surface, u, v); + var p1 = verb.eval.Eval.surfacePoint( y, u, v); + + vecShouldBe(p0, p1); + + u += us; + } + + v += vs; + } + }); + }); + + }; + + it('can decompose into 2 x 3 set of bezier patches with no distortion', () => { + + var surface23 = getSurface23(); + var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface23 ); + + checkSurfaceDecomposition( surface23, res, 2, 3 ); + + }); + + it('can decompose into 1 x 1 set of bezier patches with no distortion', () => { + + var surface11 = getSurface11(); + var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface11 ); + + checkSurfaceDecomposition( surface11, res, 1, 1 ); + + }); }); +describe("verb.eval.Tess.rationalSurfaceAdaptiveSample",() => { + + var getSurface11 = () => { + + var degreeU = 3 + , degreeV = 3 + , knotsU = [0, 0, 0, 0, 1, 1, 1, 1] + , knotsV = [0, 0, 0, 0, 1, 1, 1, 1] + , pts = [ [ [0, 0, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , 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] ] + , bezier = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, verb.eval.Eval.homogenize2d(pts, wts) ); + + return bezier; + }; + + var getSurface23 = () => { + + 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] + , pts = [ [ [0, 0, 0], [10, 0, 0], [20, 0, 0], [30, 0, 0], [40, 0, 0], [50, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0], [40, -10, 0], [50, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0], [40, -20, 0], [50, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0], [40, -30, 0], [50, -30, 0] ], + [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 0], [40, -40, 0], [50, -40, 0] ] ] + , 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] ] + , surface23 = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, verb.eval.Eval.homogenize2d(pts, wts) ); + + return surface23; + }; + + var getSurface23Curved = () => { + + 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] + , pts = [ [ [0, 0, 0], [10, 0, 0], [20, 0, 23], [30, 0, 0], [40, 0, 0], [50, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0], [40, -10, 0], [50, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0], [40, -20, 0], [50, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, -32], [40, -30, 0], [50, -30, 0] ], + [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 0], [40, -40, 0], [50, -40, 0] ] ] + , 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] ] + , surface23 = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, verb.eval.Eval.homogenize2d(pts, wts) ); + + return surface23; + }; + + var getSurface23Deg2Curved = () => { + var degree = 2 + , knotsV = [0, 0, 0, 0.333, 0.666, 1, 1, 1] + , knotsU = [0, 0, 0, 0.5, 1, 1, 1] + , pts = [ [ [0, 0, 0], [10, 0, 0], [20, 0, 23], [30, 0, 0], [40, 0, 0] ], + [ [0, -10, 0], [10, -10, 0], [20, -10, 0], [30, -10, 0], [40, -10, 0] ], + [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [30, -20, 0], [40, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, -32], [40, -30, 0] ] ] + , 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] ] + , surface23 = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, verb.eval.Eval.homogenize2d(pts, wts) ); + + return surface23; + }; + + it('can tessellate rational flat patch 1x1', () => { + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( getSurface11(), 1 ); + + should.equal( 8, res.faces.length ); + }); + + it('can tessellate 2 x 3 rational flat patch', () => { + var surface23 = getSurface23(); + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface23, 1 ); + + should.equal( 320, res.faces.length ); + }); + + it('can tessellate 2 x 3 rational non-flat patch', () => { + var surface23 = getSurface23Curved(); + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface23, 1 ); + + should.equal( 663, res.faces.length ); + }); + + it('throws with degree2 patch', () => { + var surface23 = getSurface23Deg2Curved(); + console.log( verb.eval.Check.isValidNurbsSurfaceData(surface23) ); + + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface23, 1 ); + + should.equal( 663, res.faces.length ); + }); + + +}); \ No newline at end of file diff --git a/test/testGeom.js b/test/testGeom.js index 79fc9bc1..8b768e71 100755 --- a/test/testGeom.js +++ b/test/testGeom.js @@ -45,7 +45,7 @@ function sameCurve( crvd0, crvd1 ){ } } -describe("verb.geom.NurbsCurve.lengthAtParam",function(){ +describe("verb.geom.NurbsCurve.lengthAtParam", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -55,7 +55,7 @@ describe("verb.geom.NurbsCurve.lengthAtParam",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { var res = crv.lengthAtParam( 1 ); res.should.be.approximately(4, 1e-3 ) }); @@ -68,7 +68,7 @@ describe("verb.geom.NurbsCurve.lengthAtParam",function(){ }); }); -describe("verb.geom.NurbsCurve.derivatives",function(){ +describe("verb.geom.NurbsCurve.derivatives", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -78,7 +78,7 @@ describe("verb.geom.NurbsCurve.derivatives",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('returns the derivatives for a straight curve', function(){ + it('returns the derivatives for a straight curve', () => { var p = crv.derivatives( 0.5 ); vecShouldBe( [2,0,0], p[0], 1e-3 ); vecShouldBe( [3,0,0], p[1], 1e-3 ); @@ -93,7 +93,7 @@ describe("verb.geom.NurbsCurve.derivatives",function(){ }); }); -describe("verb.geom.NurbsCurve.tangent",function(){ +describe("verb.geom.NurbsCurve.tangent", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -103,7 +103,7 @@ describe("verb.geom.NurbsCurve.tangent",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('can get the tangent for a straight curve', function(){ + it('can get the tangent for a straight curve', () => { var p = crv.tangent( 0.5 ); vecShouldBe( [3,0,0], p, 1e-3 ); }); @@ -116,7 +116,7 @@ describe("verb.geom.NurbsCurve.tangent",function(){ }); }); -describe("verb.geom.NurbsCurve.paramAtLength",function(){ +describe("verb.geom.NurbsCurve.paramAtLength", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -126,7 +126,7 @@ describe("verb.geom.NurbsCurve.paramAtLength",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('can get closest point to straight curve', function(){ + it('can get closest point to straight curve', () => { var res = crv.paramAtLength( 2 ); var p = crv.point( res ); vecShouldBe( [2,0,0], p, 1e-3 ); @@ -141,7 +141,7 @@ describe("verb.geom.NurbsCurve.paramAtLength",function(){ }); }); -describe("verb.geom.NurbsCurve.divideByEqualArcLength",function(){ +describe("verb.geom.NurbsCurve.divideByEqualArcLength", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -152,7 +152,7 @@ describe("verb.geom.NurbsCurve.divideByEqualArcLength",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('can divide straight curve', function(){ + it('can divide straight curve', () => { var res = crv.divideByEqualArcLength( divs ); @@ -196,7 +196,7 @@ describe("verb.geom.NurbsCurve.divideByEqualArcLength",function(){ }); -describe("verb.geom.NurbsCurve.divideByArcLength",function(){ +describe("verb.geom.NurbsCurve.divideByArcLength", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -208,7 +208,7 @@ describe("verb.geom.NurbsCurve.divideByArcLength",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); var tol = 1e-3; - it('can divide straight curve', function(){ + it('can divide straight curve', () => { var res = crv.divideByArcLength( d ); @@ -225,7 +225,7 @@ describe("verb.geom.NurbsCurve.divideByArcLength",function(){ }); - it('can divide straight curve async', function(){ + it('can divide straight curve async', () => { crv.divideByArcLengthAsync( d ).then(function(res){ @@ -246,7 +246,7 @@ describe("verb.geom.NurbsCurve.divideByArcLength",function(){ }); -describe("verb.geom.NurbsCurve.closestParam",function(){ +describe("verb.geom.NurbsCurve.closestParam", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -255,7 +255,7 @@ describe("verb.geom.NurbsCurve.closestParam",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('can get point on straight curve', function(){ + it('can get point on straight curve', () => { var pt = [1,0,0]; var res = crv.closestParam( pt ); @@ -265,7 +265,7 @@ describe("verb.geom.NurbsCurve.closestParam",function(){ }); - it('can get closest point to straight curve', function(){ + it('can get closest point to straight curve', () => { var pt = [1,1,0]; var res = crv.closestParam(pt); @@ -304,7 +304,7 @@ describe("verb.geom.NurbsCurve.closestParam",function(){ }); }); -describe("verb.geom.NurbsCurve.split",function(){ +describe("verb.geom.NurbsCurve.split", () => { var degree = 3 , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]; @@ -340,7 +340,7 @@ describe("verb.geom.NurbsCurve.split",function(){ } - it('returns expected results when splitting curve', function(){ + it('returns expected results when splitting curve', () => { var res = crv.split( 2.5 ); check(2.5, res); @@ -356,7 +356,7 @@ describe("verb.geom.NurbsCurve.split",function(){ }); -describe("verb.geom.NurbsCurve.transform",function(){ +describe("verb.geom.NurbsCurve.transform", () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -370,7 +370,7 @@ describe("verb.geom.NurbsCurve.transform",function(){ var crv = verb.geom.NurbsCurve.byKnotsControlPointsWeights( degree, knots, controlPoints, weights ); - it('works for basic case', function(){ + it('works for basic case', () => { var ta = crv.transform( t ); ta.point( 0.5 ).should.be.eql([2 + 5, 2, -1 ]); }); @@ -383,9 +383,9 @@ describe("verb.geom.NurbsCurve.transform",function(){ }); }); -describe("verb.geom.Arc.constructor",function(){ +describe("verb.geom.Arc.constructor", () => { - it('has correct properties', function(){ + it('has correct properties', () => { var arc = new verb.geom.Arc([0,0,0], [1,0,0], [0,1,0], 5, 0, Math.PI/ 2 ); @@ -402,9 +402,9 @@ describe("verb.geom.Arc.constructor",function(){ }); -describe("verb.geom.Arc.point",function(){ +describe("verb.geom.Arc.point", () => { - it('returns expected results', function(){ + it('returns expected results', () => { var arc = new verb.geom.Arc([0,0,1], [1,0,0], [0,1,0], 1, 0, Math.PI/ 2 ); var p1 = arc.point(0); @@ -445,9 +445,9 @@ describe("verb.geom.Arc.point",function(){ }); -describe("verb.geom.Arc.tessellate",function(){ +describe("verb.geom.Arc.tessellate", () => { - it('should return a list of vertices', function(){ + it('should return a list of vertices', () => { var arc = new verb.geom.Arc([0,0,1], [1,0,0], [0,1,0], 1, 0, Math.PI/ 2 ); var pts = arc.tessellate(); @@ -460,9 +460,9 @@ describe("verb.geom.Arc.tessellate",function(){ }); -describe("new verb.geom.Line",function(){ +describe("new verb.geom.Line", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var p1 = [0,0,1] , p2 = [1,0,0]; @@ -475,9 +475,9 @@ describe("new verb.geom.Line",function(){ }); -describe("verb.geom.Line.point",function(){ +describe("verb.geom.Line.point", () => { - it('evaluates correctly', function(){ + it('evaluates correctly', () => { var p1 = [0,0,0] , p2 = [1,1,1]; @@ -496,9 +496,9 @@ describe("verb.geom.Line.point",function(){ }); -describe("verb.geom.Line.derivatives",function(){ +describe("verb.geom.Line.derivatives", () => { - it('gives nice result', function(){ + it('gives nice result', () => { var p1 = [0,0,0] , p2 = [1,1,1]; @@ -516,9 +516,9 @@ describe("verb.geom.Line.derivatives",function(){ }); -describe("verb.geom.Line.tessellate",function(){ +describe("verb.geom.Line.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var p1 = [0,0,0] , p2 = [1,1,1]; @@ -537,9 +537,9 @@ describe("verb.geom.Line.tessellate",function(){ }); -describe("verb.geom.BezierCurve.constructor",function(){ +describe("verb.geom.BezierCurve.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var p1 = [0,0,0] , p2 = [1,0,1] @@ -554,9 +554,9 @@ describe("verb.geom.BezierCurve.constructor",function(){ }); -describe("verb.geom.BezierCurve.point",function(){ +describe("verb.geom.BezierCurve.point", () => { - it('evaluates correctly', function(){ + it('evaluates correctly', () => { var p1 = [0,0,0] , p2 = [1,0,1] @@ -575,9 +575,9 @@ describe("verb.geom.BezierCurve.point",function(){ }); -describe("verb.geom.BezierCurve.derivatives",function(){ +describe("verb.geom.BezierCurve.derivatives", () => { - it('gives nice result', function(){ + it('gives nice result', () => { var p1 = [0,0,0] , p2 = [1,0,1] @@ -597,9 +597,9 @@ describe("verb.geom.BezierCurve.derivatives",function(){ }); -describe("verb.geom.BezierCurve.tessellate",function(){ +describe("verb.geom.BezierCurve.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var p1 = [0,0,0] , p2 = [1,0,1] @@ -620,9 +620,9 @@ describe("verb.geom.BezierCurve.tessellate",function(){ }); -describe("verb.geom.Circle.constructor",function(){ +describe("verb.geom.Circle.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var c = new verb.geom.Circle([0,0,0], [1,0,0], [0,1,0], 5); @@ -632,9 +632,9 @@ describe("verb.geom.Circle.constructor",function(){ }); -describe("verb.geom.Circle.point",function(){ +describe("verb.geom.Circle.point", () => { - it('evaluates correctly', function(){ + it('evaluates correctly', () => { var c = new verb.geom.Circle([0,0,0], [1,0,0], [0,1,0], 5); @@ -650,9 +650,9 @@ describe("verb.geom.Circle.point",function(){ }); -describe("verb.geom.Circle.derivatives",function(){ +describe("verb.geom.Circle.derivatives", () => { - it('gives correct result', function(){ + it('gives correct result', () => { var c = new verb.geom.Circle([0,0,0], [1,0,0], [0,1,0], 5); @@ -675,9 +675,9 @@ describe("verb.geom.Circle.derivatives",function(){ }); -describe("verb.geom.Circle.tessellate",function(){ +describe("verb.geom.Circle.tessellate", () => { - it('gives correct result', function(){ + it('gives correct result', () => { var c = new verb.geom.Circle([0,0,0], [1,0,0], [0,1,0], 5); @@ -692,9 +692,9 @@ describe("verb.geom.Circle.tessellate",function(){ }); -describe("verb.geom.Ellipse.constructor",function(){ +describe("verb.geom.Ellipse.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var c = new verb.geom.Ellipse([0,0,0], [5,0,0], [0,10,0]); @@ -704,9 +704,9 @@ describe("verb.geom.Ellipse.constructor",function(){ }); -describe("verb.geom.Ellipse.point",function(){ +describe("verb.geom.Ellipse.point", () => { - it('evaluates correctly', function(){ + it('evaluates correctly', () => { var c = new verb.geom.Ellipse([0,0,0], [5,0,0], [0,10,0]); @@ -728,9 +728,9 @@ describe("verb.geom.Ellipse.point",function(){ }); -describe("verb.geom.Ellipse.derivatives",function(){ +describe("verb.geom.Ellipse.derivatives", () => { - it('gives correct result', function(){ + it('gives correct result', () => { var c = new verb.geom.Ellipse([0,0,0], [5,0,0], [0,10,0]); @@ -766,9 +766,9 @@ describe("verb.geom.Ellipse.derivatives",function(){ }); -describe("verb.geom.Ellipse.tessellate",function(){ +describe("verb.geom.Ellipse.tessellate", () => { - it('gives correct result', function(){ + it('gives correct result', () => { var c = new verb.geom.Ellipse([0,0,0], [5,0,0], [0,10,0]); @@ -783,9 +783,9 @@ describe("verb.geom.Ellipse.tessellate",function(){ }); -describe("verb.geom.EllipseArc.constructor",function(){ +describe("verb.geom.EllipseArc.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var c = new verb.geom.EllipseArc([0,0,0], [1,0,0], [0,1,0], 0, Math.PI); @@ -795,9 +795,9 @@ describe("verb.geom.EllipseArc.constructor",function(){ }); -describe("verb.geom.EllipseArc.point",function(){ +describe("verb.geom.EllipseArc.point", () => { - it('evaluates correctly', function(){ + it('evaluates correctly', () => { var c = new verb.geom.EllipseArc([0,0,0], [1,0,0], [0,10,0], 0, Math.PI); @@ -813,9 +813,9 @@ describe("verb.geom.EllipseArc.point",function(){ }); -describe("verb.geom.EllipseArc.derivatives",function(){ +describe("verb.geom.EllipseArc.derivatives", () => { - it('gives correct result', function(){ + it('gives correct result', () => { var c = new verb.geom.EllipseArc([0,0,0], [1,0,0], [0,10,0], 0, Math.PI); @@ -838,9 +838,9 @@ describe("verb.geom.EllipseArc.derivatives",function(){ }); -describe("verb.geom.EllipseArc.tessellate",function(){ +describe("verb.geom.EllipseArc.tessellate", () => { - it('gives correct result', function(){ + it('gives correct result', () => { var c = new verb.geom.EllipseArc([0,0,0], [1,0,0], [0,10,0], 0, Math.PI); @@ -855,7 +855,7 @@ describe("verb.geom.EllipseArc.tessellate",function(){ }); -describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights",function(){ +describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights", () => { var degreeU = 3 , degreeV = 3 @@ -871,7 +871,7 @@ describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('has expected properties', function(){ + it('has expected properties', () => { surface.degreeU().should.be.equal( 3 ); surface.degreeV().should.be.equal( 3 ); @@ -884,7 +884,7 @@ describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights",function(){ }); -describe("verb.geom.NurbsSurface.domainU",function(){ +describe("verb.geom.NurbsSurface.domainU", () => { var degreeU = 3 , degreeV = 3 @@ -900,7 +900,7 @@ describe("verb.geom.NurbsSurface.domainU",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { var d = surface.domainU(); d.min.should.be.equal( 0 ); @@ -908,7 +908,7 @@ describe("verb.geom.NurbsSurface.domainU",function(){ }); }); -describe("verb.geom.NurbsSurface.domainV",function(){ +describe("verb.geom.NurbsSurface.domainV", () => { var degreeU = 3 , degreeV = 3 @@ -924,7 +924,7 @@ describe("verb.geom.NurbsSurface.domainV",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { var d = surface.domainU(); d.min.should.be.equal( 0 ); @@ -932,7 +932,7 @@ describe("verb.geom.NurbsSurface.domainV",function(){ }); }); -describe("verb.geom.NurbsSurface.point",function(){ +describe("verb.geom.NurbsSurface.point", () => { var degreeU = 3 , degreeV = 3 @@ -948,7 +948,7 @@ describe("verb.geom.NurbsSurface.point",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { vecShouldBe( [15, -15, 0], surface.point(0.5,0.5) ); @@ -965,7 +965,7 @@ describe("verb.geom.NurbsSurface.point",function(){ }); -describe("verb.geom.NurbsSurface.normal",function(){ +describe("verb.geom.NurbsSurface.normal", () => { var degreeU = 3 , degreeV = 3 @@ -981,7 +981,7 @@ describe("verb.geom.NurbsSurface.normal",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { vecShouldBe( [0, 0, 900], surface.normal(0.5,0.5) ); }); @@ -996,7 +996,7 @@ describe("verb.geom.NurbsSurface.normal",function(){ }); -describe("verb.geom.NurbsSurface.derivatives",function(){ +describe("verb.geom.NurbsSurface.derivatives", () => { var degreeU = 3 , degreeV = 3 @@ -1012,7 +1012,7 @@ describe("verb.geom.NurbsSurface.derivatives",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { var d = surface.derivatives( 0.5, 0.5, 1 ); vecShouldBe( [15, -15, 0], d[0][0] ); @@ -1033,7 +1033,7 @@ describe("verb.geom.NurbsSurface.derivatives",function(){ }); -describe("verb.geom.NurbsSurface.closestParam",function(){ +describe("verb.geom.NurbsSurface.closestParam", () => { var degreeU = 3 , degreeV = 3 @@ -1049,7 +1049,7 @@ describe("verb.geom.NurbsSurface.closestParam",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { var d = surface.closestParam( [ 15, -15, 1] ); vecShouldBe( [0.5, 0.5], d ); }); @@ -1092,7 +1092,7 @@ describe("verb.geom.NurbsSurface.closestParam",function(){ }); }); -describe("verb.geom.NurbsSurface.closestPoint",function(){ +describe("verb.geom.NurbsSurface.closestPoint", () => { var degreeU = 3 , degreeV = 3 @@ -1108,7 +1108,7 @@ describe("verb.geom.NurbsSurface.closestPoint",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case', function(){ + it('is correct for basic case', () => { var d = surface.closestPoint( [ 15, -15, 1] ); vecShouldBe( [15, -15, 0], d ); }); @@ -1121,7 +1121,7 @@ describe("verb.geom.NurbsSurface.closestPoint",function(){ }); }); -describe("verb.geom.NurbsSurface.split",function(){ +describe("verb.geom.NurbsSurface.split", () => { var degreeU = 3 , degreeV = 3 @@ -1137,7 +1137,7 @@ describe("verb.geom.NurbsSurface.split",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case 1', function(){ + it('is correct for basic case 1', () => { var d = surface.split( 0.5, true ); d[0].domainV().min.should.be.equal(0); @@ -1153,7 +1153,7 @@ describe("verb.geom.NurbsSurface.split",function(){ d[1].domainU().max.should.be.equal(1.0); }); - it('is correct for basic case 2', function(){ + it('is correct for basic case 2', () => { var d = surface.split( 0.5, false ); d[0].domainV().min.should.be.equal(0); @@ -1189,7 +1189,7 @@ describe("verb.geom.NurbsSurface.split",function(){ }); }); -describe("verb.geom.NurbsSurface.tessellate",function(){ +describe("verb.geom.NurbsSurface.tessellate", () => { var degreeU = 3 , degreeV = 3 @@ -1205,7 +1205,7 @@ describe("verb.geom.NurbsSurface.tessellate",function(){ [ 1, 1, 1, 1 ] ] , surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints, weights ); - it('is correct for basic case with no options', function(){ + it('is correct for basic case with no options', () => { var d = surface.tessellate(); d.faces.length.should.be.greaterThan( 2 ); @@ -1229,7 +1229,7 @@ describe("verb.geom.NurbsSurface.tessellate",function(){ // }); }); -describe("verb.geom.NurbsSurface.transform",function(){ +describe("verb.geom.NurbsSurface.transform", () => { var degreeU = 3 , degreeV = 3 @@ -1250,7 +1250,7 @@ describe("verb.geom.NurbsSurface.transform",function(){ [ 0, 0, 1, -1], [ 0, 0, 0, 1 ] ]; - it('is correct for basic case with no options', function(){ + it('is correct for basic case with no options', () => { var ta = surface.transform( t ); @@ -1267,12 +1267,12 @@ describe("verb.geom.NurbsSurface.transform",function(){ }); }); -describe("verb.geom.NurbsCurve.byPoints",function(){ +describe("verb.geom.NurbsCurve.byPoints", () => { function shouldInterpPoints(curve, pts){ // // the internal points are interped - var tess = curve.tessellate( 1e-8 ); + var tess = curve.tessellate( 1e-3 ); for (var j = 0; j < pts.length; j++){ @@ -1296,15 +1296,15 @@ describe("verb.geom.NurbsCurve.byPoints",function(){ var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - it('can compute valid cubic interpolating curve for 4 points', function(){ + it('can compute valid cubic interpolating curve for 4 points', () => { shouldInterpPoints( verb.geom.NurbsCurve.byPoints( pts ), pts ); }); }); -describe("verb.geom.ExtrudedSurface",function(){ +describe("verb.geom.ExtrudedSurface", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var profile = new verb.geom.Line( [0,0,0], [1,1,1] ) , axis = [0,0,1] @@ -1318,9 +1318,9 @@ describe("verb.geom.ExtrudedSurface",function(){ }); -describe("verb.geom.ExtrudedSurface.point",function(){ +describe("verb.geom.ExtrudedSurface.point", () => { - it('evaluates correctly for middle of surface', function(){ + it('evaluates correctly for middle of surface', () => { var profile = new verb.geom.Line( [0,0,0], [1,1,0] ) , axis = [0,0,3]; @@ -1339,9 +1339,9 @@ describe("verb.geom.ExtrudedSurface.point",function(){ }); -describe("verb.geom.ExtrudedSurface.derivatives",function(){ +describe("verb.geom.ExtrudedSurface.derivatives", () => { - it('gives expected result for middle of surface', function(){ + it('gives expected result for middle of surface', () => { var profile = new verb.geom.Line( [0,0,0], [1,1,0] ) , axis = [0,0,3]; @@ -1369,9 +1369,9 @@ describe("verb.geom.ExtrudedSurface.derivatives",function(){ }); -describe("verb.geom.ExtrudedSurface.tessellate",function(){ +describe("verb.geom.ExtrudedSurface.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var profile = new verb.geom.Line( [0,0,0], [1,1,0] ) , axis = [0,0,3]; @@ -1397,9 +1397,9 @@ describe("verb.geom.ExtrudedSurface.tessellate",function(){ }); -describe("verb.geom.RevolvedSurface.constructor",function(){ +describe("verb.geom.RevolvedSurface.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var base = [0,0,0] , axis = [0,0,1] @@ -1414,9 +1414,9 @@ describe("verb.geom.RevolvedSurface.constructor",function(){ }); -describe("verb.geom.RevolvedSurface.point",function(){ +describe("verb.geom.RevolvedSurface.point", () => { - it('evaluates correctly for middle of surface', function(){ + it('evaluates correctly for middle of surface', () => { var base = [0,0,0] , axis = [0,0,1] @@ -1437,9 +1437,9 @@ describe("verb.geom.RevolvedSurface.point",function(){ }); -describe("verb.geom.RevolvedSurface.derivatives",function(){ +describe("verb.geom.RevolvedSurface.derivatives", () => { - it('gives expected result for middle of surface', function(){ + it('gives expected result for middle of surface', () => { var base = [0,0,0] , axis = [0,0,1] @@ -1471,9 +1471,9 @@ describe("verb.geom.RevolvedSurface.derivatives",function(){ }); -describe("verb.geom.RevolvedSurface.tessellate",function(){ +describe("verb.geom.RevolvedSurface.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var base = [0,0,0] , axis = [0,0,1] @@ -1501,9 +1501,9 @@ describe("verb.geom.RevolvedSurface.tessellate",function(){ }); -describe("verb.geom.SphericalSurface.constructor",function(){ +describe("verb.geom.SphericalSurface.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var center = [0,0,0] , radius = 5; @@ -1519,9 +1519,9 @@ describe("verb.geom.SphericalSurface.constructor",function(){ }); -describe("verb.geom.SphericalSurface.point",function(){ +describe("verb.geom.SphericalSurface.point", () => { - it('evaluates correctly for middle of surface', function(){ + it('evaluates correctly for middle of surface', () => { var center = [0,0,0] , radius = 5; @@ -1540,9 +1540,9 @@ describe("verb.geom.SphericalSurface.point",function(){ }); -describe("verb.geom.SphericalSurface.derivatives",function(){ +describe("verb.geom.SphericalSurface.derivatives", () => { - it('gives expected result for middle of surface', function(){ + it('gives expected result for middle of surface', () => { var center = [0,0,0] , radius = 5; @@ -1573,9 +1573,9 @@ describe("verb.geom.SphericalSurface.derivatives",function(){ }); -describe("verb.geom.SphericalSurface.tessellate",function(){ +describe("verb.geom.SphericalSurface.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var center = [0,0,0] , radius = 5; @@ -1601,9 +1601,9 @@ describe("verb.geom.SphericalSurface.tessellate",function(){ }); -describe("verb.geom.CylindricalSurface.constructor",function(){ +describe("verb.geom.CylindricalSurface.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1625,9 +1625,9 @@ describe("verb.geom.CylindricalSurface.constructor",function(){ }); -describe("verb.geom.CylindricalSurface.point",function(){ +describe("verb.geom.CylindricalSurface.point", () => { - it('evaluates correctly for middle of surface', function(){ + it('evaluates correctly for middle of surface', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1651,9 +1651,9 @@ describe("verb.geom.CylindricalSurface.point",function(){ }); -describe("verb.geom.CylindricalSurface.derivatives",function(){ +describe("verb.geom.CylindricalSurface.derivatives", () => { - it('gives expected result for middle of surface', function(){ + it('gives expected result for middle of surface', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1685,9 +1685,9 @@ describe("verb.geom.CylindricalSurface.derivatives",function(){ }); -describe("verb.geom.CylindricalSurface.tessellate",function(){ +describe("verb.geom.CylindricalSurface.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1716,9 +1716,9 @@ describe("verb.geom.CylindricalSurface.tessellate",function(){ }); -describe("verb.geom.NurbsSurface.byCorners",function(){ +describe("verb.geom.NurbsSurface.byCorners", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var p1 = [0,0,1] , p2 = [1,0,0] @@ -1733,9 +1733,9 @@ describe("verb.geom.NurbsSurface.byCorners",function(){ }); -describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.point",function(){ +describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.point", () => { - it('evaluates correctly for hypar', function(){ + it('evaluates correctly for hypar', () => { var p1 = [0,0,1] , p2 = [1,0,0] @@ -1756,9 +1756,9 @@ describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.point",func }); -describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.derivatives",function(){ +describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.derivatives", () => { - it('gives nice result', function(){ + it('gives nice result', () => { var p1 = [0,0,1] , p2 = [1,0,0] @@ -1779,9 +1779,9 @@ describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.derivatives }); -describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.tessellate",function(){ +describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var p1 = [0,0,1] , p2 = [1,0,0] @@ -1810,9 +1810,9 @@ describe("verb.geom.NurbsSurface.byCorners -> verb.geom.NurbsSurface.tessellate" }); -describe("verb.geom.ConicalSurface.constructor",function(){ +describe("verb.geom.ConicalSurface.constructor", () => { - it('can create an instance', function(){ + it('can create an instance', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1834,9 +1834,9 @@ describe("verb.geom.ConicalSurface.constructor",function(){ }); -describe("verb.geom.ConicalSurface.point",function(){ +describe("verb.geom.ConicalSurface.point", () => { - it('evaluates correctly for middle of surface', function(){ + it('evaluates correctly for middle of surface', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1858,9 +1858,9 @@ describe("verb.geom.ConicalSurface.point",function(){ }); -describe("verb.geom.ConicalSurface.derivatives",function(){ +describe("verb.geom.ConicalSurface.derivatives", () => { - it('gives expected result for middle of surface', function(){ + it('gives expected result for middle of surface', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1893,9 +1893,9 @@ describe("verb.geom.ConicalSurface.derivatives",function(){ }); -describe("verb.geom.ConicalSurface.tessellate",function(){ +describe("verb.geom.ConicalSurface.tessellate", () => { - it('gives mesh result', function(){ + it('gives mesh result', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1924,12 +1924,12 @@ describe("verb.geom.ConicalSurface.tessellate",function(){ }); -describe("verb.geom.Intersect.curves",function(){ +describe("verb.geom.Intersect.curves", () => { var curve1 = new verb.geom.BezierCurve( [[0,0,0], [0.5,0.1,0], [2,0,0]] ), curve2 = new verb.geom.BezierCurve( [[0.5,0.5,0], [0.7,0,0], [0.5,-1.5,0]] ); - it('gives valid result for 2 planar degree 2 beziers', function(){ + it('gives valid result for 2 planar degree 2 beziers', () => { var res = verb.geom.Intersect.curves( curve1, curve2, verb.core.Constants.TOLERANCE ); @@ -1954,7 +1954,7 @@ describe("verb.geom.Intersect.curves",function(){ }); -describe("verb.geom.Intersect.curveAndSurface",function(){ +describe("verb.geom.Intersect.curveAndSurface", () => { // build planar surface in the xy plane var homo_controlPoints_srf = [ [ [0,0,0,1], [0,10,0,1] ], [[20,0,0,1], [20,10,0,1] ] ] @@ -1972,7 +1972,7 @@ describe("verb.geom.Intersect.curveAndSurface",function(){ , curveData = new verb.core.NurbsCurveData( degree_crv, knots_crv, homo_controlPoints_crv ) , curve = new verb.geom.NurbsCurve( curveData ); - it('gives valid result for planar surface and degree 2 bezier', function(){ + it('gives valid result for planar surface and degree 2 bezier', () => { var res = verb.geom.Intersect.curveAndSurface( curve, surface, verb.core.Constants.TOLERANCE ); res.length.should.be.equal( 1 ); @@ -1995,9 +1995,9 @@ describe("verb.geom.Intersect.curveAndSurface",function(){ }); }); -describe("verb.geom.NurbsCurve.reverse",function(){ +describe("verb.geom.NurbsCurve.reverse", () => { - it('is correct', function(){ + it('is correct', () => { var cd = new verb.core.NurbsCurveData( 2, [0,0,0,0.24,1,1,1], [ [0,0,0,1], [1,0,0,1], [0.5,1,0,1], [2,0,0,1] ] ); var c = new verb.geom.NurbsCurve( cd ); @@ -2012,7 +2012,7 @@ describe("verb.geom.NurbsCurve.reverse",function(){ sameCurve( c.asNurbs(), crr.asNurbs() ); }); - it('is correct for 90 degree arc', function(){ + it('is correct for 90 degree arc', () => { var c = new verb.geom.Arc([0,0,0], [1,0,0], [0,1,0], 5, 0, Math.PI/ 2 ); var cr = c.reverse(); // returns a reversed copy var crr = cr.reverse(); // returns the original @@ -2033,7 +2033,7 @@ describe("verb.geom.NurbsCurve.reverse",function(){ }); -describe("verb.geom.NurbsSurface.reverse",function(){ +describe("verb.geom.NurbsSurface.reverse", () => { var degreeU = 3 , degreeV = 3 @@ -2045,7 +2045,7 @@ describe("verb.geom.NurbsSurface.reverse",function(){ [ [0, -20, 0], [10, -20, 0], [20, -20, 0], [25, -20, 0], [30, -20, 0] ], [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [25, -30, 0], [30, -30, 0] ] ]; - it('is correct for u direction', function(){ + it('is correct for u direction', () => { var s = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints ); var sr = s.reverse( true ); @@ -2066,8 +2066,8 @@ describe("verb.geom.NurbsSurface.reverse",function(){ }); }); -describe("verb.geom.Deserializer",function(){ - it('foo', function(){ +describe("verb.geom.Deserializer", () => { + it('foo', () => { var rail = new verb.geom.BezierCurve( [[0,0,0], [1,0.5,1], [2,1,1]] ); var prof = new verb.geom.BezierCurve( [[0,0,0], [2,0,0]] ); @@ -2076,9 +2076,9 @@ describe("verb.geom.Deserializer",function(){ }); -describe("verb.geom.SweptSurface",function(){ +describe("verb.geom.SweptSurface", () => { - it('provides expected result for linear profile, curved rail', function(){ + it('provides expected result for linear profile, curved rail', () => { var rail = new verb.geom.BezierCurve( [[0,0,0], [1,0.5,1], [2,1,1], [2,1,1]] ); var prof = new verb.geom.BezierCurve( [[0,0,0], [2,0,0]] ); @@ -2093,7 +2093,7 @@ describe("verb.geom.SweptSurface",function(){ }); }); -describe("verb.geom.NurbsSurface.isocurve",function(){ +describe("verb.geom.NurbsSurface.isocurve", () => { var degreeU = 3 , degreeV = 3 , knotsU = [0, 0, 0, 0, 1, 1, 1, 1] @@ -2104,7 +2104,7 @@ describe("verb.geom.NurbsSurface.isocurve",function(){ [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] , bezier = verb.geom.NurbsSurface.byKnotsControlPointsWeights( degreeU, degreeV, knotsU, knotsV, controlPoints ); - it('provides isocurves at expected location in u direction', function(){ + it('provides isocurves at expected location in u direction', () => { var i = 0.5; var res = bezier.isocurve( i, false ); diff --git a/todo b/todo index c9f292ee..4f721307 100644 --- a/todo +++ b/todo @@ -1,13 +1,24 @@ -Documentation generation - docco no longer works, always sucked anyways -Update website +Complete forward differencing algorithm -Split + - degenerate cases (e.g. no interior points, cylinder) + - make UVS + - approximate normals + - exact normals + - tests (spheres, circles) + - rationalBezierSurfaceStepLength + * supports degree2? + * + + + +BRep Split Holes are not recognized +BRep Bool + Not complete + SweptSurface -More efficient representation for surface tessellation, don't use 2d arrays More exact srf-srf intersection -Marching surface-Surface intersection SurfaceClosestPoint occasionally fails when point is far from surface - need to check for wild derivatives Curve interpolation with sparse matrices Curve approximation diff --git a/vscode-project.hxml b/vscode-project.hxml new file mode 100644 index 00000000..b1dbc573 --- /dev/null +++ b/vscode-project.hxml @@ -0,0 +1,3 @@ +#automatically generated do not edit +#@date Wed Jun 08 2016 21:05:59 GMT-0400 (EDT) +-cp /var/folders/64/k10py5tj6r72zsmq16t6zy3r0000gn/T/5e129455671f34c07ff1bc07b1424b4e47da1be2 \ No newline at end of file