From f82f6dc533e14deacd378601218bf338615028f3 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Sun, 25 Oct 2015 15:37:15 -0400 Subject: [PATCH 01/25] Use mutating vector methods throughout Eval, provide new regular sampling methods --- benchmark/regularCurveSampling.js | 22 ++ benchmark/regularSurfaceDerivatives.js | 56 ++++ benchmark/regularSurfaceSampling.js | 56 ++++ benchmark/tessellate.js | 60 ---- build/js/verb.js | 344 ++++++++++++++++++-- build/js/verb.min.js | 12 +- build/js/verbHaxe.js | 343 +++++++++++++++++++- src/support/header.js | 1 - src/verb/core/Vec.hx | 26 ++ src/verb/eval/Eval.hx | 423 +++++++++++++++++++++++-- test/testCore.js | 1 + test/testEval.js | 80 +++++ 12 files changed, 1293 insertions(+), 131 deletions(-) create mode 100644 benchmark/regularCurveSampling.js create mode 100644 benchmark/regularSurfaceDerivatives.js create mode 100644 benchmark/regularSurfaceSampling.js delete mode 100644 benchmark/tessellate.js diff --git a/benchmark/regularCurveSampling.js b/benchmark/regularCurveSampling.js new file mode 100644 index 00000000..e24c75d2 --- /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: { + 'curveRegularSamplePoints (100)': function() { + var p = verb.eval.Eval.curveRegularSamplePoints( crv, 100 ); + }, + 'direct evaluation (100)': function() { + var p = []; + var sp = 1 / 100; + + for (var i = 0; i < 101; 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..726c3443 --- /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..cee3edb7 --- /dev/null +++ b/benchmark/regularSurfaceSampling.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 sampling', + tests: { + 'surfaceRegularSample (80 x 80)': function() { + verb.eval.Eval.surfaceRegularSamplePoints( 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/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 5e5464b8..5bd2a054 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -3,7 +3,6 @@ (function(f){ if(typeof exports==="object"&&typeof module!=="undefined"){ - console.log("OK"); module.exports=f() } else if(typeof define==="function"&&define.amd){ define([],f) @@ -3468,6 +3467,47 @@ 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.norm = function(a) { var norm2 = verb_core_Vec.normSquared(a); if(norm2 != 0.0) return Math.sqrt(norm2); else return norm2; @@ -4075,21 +4115,21 @@ 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.subMutate(v1,verb_core_Vec.mul(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.subMutate(v1,verb_core_Vec.mul(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.addMutate(v2,verb_core_Vec.mul(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.subMutate(v1,verb_core_Vec.mul(verb_core_Binomial.get(k,i),v2)); } SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],v1)); } @@ -4116,7 +4156,7 @@ 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)); } @@ -4162,7 +4202,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; @@ -4176,7 +4216,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]); } } } @@ -4213,12 +4253,280 @@ 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]); + } + verb_core_Vec.addMulMutate(position,v_basis_vals[l],temp); + } + return position; +}; +verb_eval_Eval.curveRegularSamplePoints = function(crv,divs) { + var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); + var t = 1.0 / divs; + var temp = t * t; + var f = derivs[0]; + var fd = verb_core_Vec.mul(t,derivs[1]); + var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); + var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); + var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); + var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); + var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); + var pts = []; + var _g1 = 0; + var _g = divs + 1; + while(_g1 < _g) { + var i = _g1++; + pts.push(verb_eval_Eval.dehomogenize(f)); + verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); + verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); + verb_core_Vec.addAllMutate([fdd,fddd]); + verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); + } + return pts; +}; +verb_eval_Eval.curveRegularSamplePoints2 = function(crv,divs) { + var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); + var t = 1.0 / divs; + var temp = t * t; + var f = derivs[0]; + var fd = verb_core_Vec.mul(t,derivs[1]); + var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); + var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); + var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); + var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); + var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); + var pts = []; + var _g1 = 0; + var _g = divs + 1; + while(_g1 < _g) { + var i = _g1++; + pts.push(verb_eval_Eval.dehomogenize(f)); + verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); + verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); + verb_core_Vec.addAllMutate([fdd,fddd]); + verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); + } + return pts; +}; +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); + } + SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],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.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Eval.surfaceRegularSamplePoints(surface,divsU,divsV)); +}; +verb_eval_Eval.surfaceRegularSamplePoints = 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_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]); } - position = verb_core_Vec.add(position,verb_core_Vec.mul(v_basis_vals[l],temp)); + 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); @@ -4244,7 +4552,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; @@ -4271,7 +4579,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; }; @@ -4317,11 +4625,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; }; @@ -4331,7 +4639,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); @@ -4342,8 +4650,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) { diff --git a/build/js/verb.min.js b/build/js/verb.min.js index c1523a80..37029498 100644 --- a/build/js/verb.min.js +++ b/build/js/verb.min.js @@ -1,6 +1,6 @@ -/*! verb 2015-10-19 */ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)console.log("OK"),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&&(console.log("making web worker"),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__=db++);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 B.__string_rec(this,"")},i=function(){};g.HxOverrides=i,i.__name__=["HxOverrides"],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,q=null;null!=o;){var r;q=o[0],o=o[1],r=q,this.serialize(r)}this.buf.b+="h";break;case Date:var v=a;this.buf.b+="v",this.buf.add(v.getTime());break;case w:this.buf.b+="b";for(var y=a,z=y.keys();z.hasNext();){var C=z.next();this.serializeString(C),this.serialize(null!=kb[C]?y.getReserved(C):y.h[C])}this.buf.b+="h";break;case t:this.buf.b+="q";for(var D=a,E=D.keys();E.hasNext();){var F=E.next();this.buf.b+=":",null==F?this.buf.b+="null":this.buf.b+=""+F,this.serialize(D.h[F])}this.buf.b+="h";break;case u: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 x:for(var K=a,L=0,M=K.length-2,N=new n,O=s.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(p.getClassName(e)),this.useCache&&this.cache.push(a),a.hxSerialize(this),this.buf.b+="g"):(this.buf.b+="c",this.serializeString(p.getClassName(e)),this.useCache&&this.cache.push(a),this.serializeFields(a))}break;case 4:if(B.__instanceof(a,ib)){var W=p.getClassName(a);this.buf.b+="A",this.serializeString(W)}else if(B.__instanceof(a,jb))this.buf.b+="B",this.serializeString(p.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(p.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 A("Cannot serialize function");default:throw new A("Cannot serialize "+m.string(a))}},__class__:s};var t=function(){this.h={}};g["haxe.ds.IntMap"]=t,t.__name__=["haxe","ds","IntMap"],t.__interfaces__=[q],t.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__:t};var u=function(){};g["haxe.ds.ObjectMap"]=u,u.__name__=["haxe","ds","ObjectMap"],u.__interfaces__=[q],u.prototype={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__:u};var v=g["haxe.ds.Option"]={__ename__:["haxe","ds","Option"],__constructs__:["Some","None"]};v.Some=function(a){var b=["Some",0,a];return b.__enum__=v,b.toString=h,b},v.None=["None",1],v.None.toString=h,v.None.__enum__=v;var w=function(){};g["haxe.ds.StringMap"]=w,w.__name__=["haxe","ds","StringMap"],w.__interfaces__=[q],w.prototype={set:function(a,b){null!=kb[a]?this.setReserved(a,b):this.h[a]=b},get:function(a){return null!=kb[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__:w};var x=function(){};g["haxe.io.Bytes"]=x,x.__name__=["haxe","io","Bytes"],x.prototype={get:function(a){return this.b[a]},__class__:x};var y=g["haxe.io.Error"]={__ename__:["haxe","io","Error"],__constructs__:["Blocked","Overflow","OutsideBounds","Custom"]};y.Blocked=["Blocked",0],y.Blocked.toString=h,y.Blocked.__enum__=y,y.Overflow=["Overflow",1],y.Overflow.toString=h,y.Overflow.__enum__=y,y.OutsideBounds=["OutsideBounds",2],y.OutsideBounds.toString=h,y.OutsideBounds.__enum__=y,y.Custom=function(a){var b=["Custom",3,a];return b.__enum__=y,b.toString=h,b};var z=function(){};g["haxe.io.FPHelper"]=z,z.__name__=["haxe","io","FPHelper"],z.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)},z.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},z.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)},z.doubleToI64=function(a){var b=z.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 A=function(a){Error.call(this),this.val=a,this.message=String(a),Error.captureStackTrace&&Error.captureStackTrace(this,A)};g["js._Boot.HaxeError"]=A,A.__name__=["js","_Boot","HaxeError"],A.__super__=Error,A.prototype=d(Error.prototype,{__class__:A});var B=function(){};g["js.Boot"]=B,B.__name__=["js","Boot"],B.getClass=function(a){if(a instanceof Array&&null==a.__enum__)return Array;var b=a.__class__;if(null!=b)return b;var c=B.__nativeClassName(a);return null!=c?B.__resolveNativeClass(c):null},B.__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?","+B.__string_rec(a[g],b):B.__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?",":"")+B.__string_rec(a[k],b)}return i+="]"}var l;try{l=a.toString}catch(m){return m instanceof A&&(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+" : "+B.__string_rec(a[o],b));return b=b.substring(1),p+="\n"+b+"}";case"function":return"";case"string":return a;default:return String(a)}},B.__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||B.__interfLoop(g,b))return!0}return B.__interfLoop(a.__super__,b)},B.__instanceof=function(a,b){if(null==b)return!1;switch(b){case eb:return(0|a)===a;case gb:return"number"==typeof a;case hb:return"boolean"==typeof a;case String:return"string"==typeof a;case Array:return a instanceof Array&&null==a.__enum__;case fb:return!0;default:if(null==a)return!1;if("function"==typeof b){if(a instanceof b)return!0;if(B.__interfLoop(B.getClass(a),b))return!0}else if("object"==typeof b&&B.__isNativeObj(b)&&a instanceof b)return!0;return b==ib&&null!=a.__name__?!0:b==jb&&null!=a.__ename__?!0:a.__enum__==b}},B.__nativeClassName=function(a){var b=B.__toStr.call(a).slice(8,-1);return"Object"==b||"Function"==b||"Math"==b||"JSON"==b?null:b},B.__isNativeObj=function(a){return null!=B.__nativeClassName(a)},B.__resolveNativeClass=function(a){return c[a]};var C=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"]=C,C.__name__=["js","html","compat","ArrayBuffer"],C.sliceImpl=function(a,b){var c=new mb(this,a,null==b?null:b-a),d=new lb(c.byteLength),e=new mb(d);return e.set(c),d},C.prototype={slice:function(a,b){return new C(this.a.slice(a,b))},__class__:C};var D=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 A(y.OutsideBounds)};g["js.html.compat.DataView"]=D,D.__name__=["js","html","compat","DataView"],D.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 z.i32ToFloat(this.getInt32(a,b))},getFloat64:function(a,b){var c=this.getInt32(a,b),d=this.getInt32(a+4,b);return z.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,z.floatToI32(b),c)},setFloat64:function(a,b,c){var d=z.doubleToI64(b);c?(this.setUint32(a,d.low),this.setUint32(a,d.high)):(this.setUint32(a,d.high),this.setUint32(a,d.low))},__class__:D};var E=function(){};g["js.html.compat.Uint8Array"]=E,E.__name__=["js","html","compat","Uint8Array"],E._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 C(d)}else if(B.__instanceof(a,C)){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 A("TODO "+m.string(a));d=a.slice(),d.byteLength=d.length,d.byteOffset=0,d.buffer=new C(d)}return d.subarray=E._subarray,d.set=E._set,d},E._set=function(a,b){var c=this;if(B.__instanceof(a.buffer,C)){var d=a;if(a.byteLength+b>c.byteLength)throw new A("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 A("TODO");var h=a;if(h.length+b>c.byteLength)throw new A("set() outside of range");for(var i=0,j=h.length;j>i;){var k=i++;c[k+b]=h[k]}}},E._subarray=function(a,b){var c=this,d=E._new(c.slice(a,b));return d.byteOffset=a,d};var F=function(a){this._resolved=!1,this._pending=!1,this._errorPending=!1,this._fulfilled=!1,this._update=[],this._error=[],this._errored=!1,null!=a&&F.link(a,this,function(a){return a})};g["promhx.base.AsyncBase"]=F,F.__name__=["promhx","base","AsyncBase"],F.link=function(a,b,c){a._update.push({async:b,linkf:function(a){b.handleResolve(c(a))}}),F.immediateLinkUpdate(a,b,c)},F.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 A&&(d=d.val),b.handleError(d)}},F.linkAll=function(a,b){for(var c=function(c,d,f){if(0==c.length||F.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)})}F.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))},F.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)}),F.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 A&&(g=g.val),b.handleError(g)}},F.allResolved=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._resolved)return!1}return!0},F.allFulfilled=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._fulfilled)return!1}return!0},F.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?K.enqueue(function(a,b){return function(){a(b)}}(f(this,this._resolve),a)):(this._resolved=!0,this._pending=!0,K.queue.add(function(){b._val=a;for(var c=0,d=b._update;c0)for(var c=0,d=b._error;c0))throw new A(a);for(var f=0,g=b._update;f0&&null!=(b=K.queue.pop());)b();return K.queue.isEmpty()},K.clear=function(){K.queue=new k},K.f=function(){var a=K.queue.pop();null!=a&&a(),K.queue.isEmpty()||K.continueOnNextLoop()},K.continueOnNextLoop=function(){null!=K.nextLoop?K.nextLoop(K.f):setImmediate(K.f)};var L=g["promhx.error.PromiseError"]={__ename__:["promhx","error","PromiseError"],__constructs__:["AlreadyResolved","DownstreamNotFullfilled"]};L.AlreadyResolved=function(a){var b=["AlreadyResolved",0,a];return b.__enum__=L,b.toString=h,b},L.DownstreamNotFullfilled=function(a){var b=["DownstreamNotFullfilled",1,a];return b.__enum__=L,b.toString=h,b};var M=function(){};g["verb.Verb"]=M,M.__name__=["verb","Verb"],M.main=function(){a.log("verb 2.0.0")};var N=function(){};g["verb.core.ArrayExtensions"]=N,N.__name__=["verb","core","ArrayExtensions"],N.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),O.memo_exists(a,b))return O.get_memo(a,b);for(var c=1,d=a,e=1,f=b+1;f>e;){var g=e++;O.memo_exists(d,g)?(a--,c=O.get_memo(d,g)):(c*=a--,c/=g,O.memoize(d,g,c))}return c},O.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},O.memo_exists=function(a,b){return O.memo.h.hasOwnProperty(a)&&O.memo.h[a].h.hasOwnProperty(b)},O.get_memo=function(a,b){return O.memo.h[a].h[b]},O.memoize=function(a,b,c){O.memo.h.hasOwnProperty(a)||O.memo.set(a,new t),O.memo.h[a].h[b]=c};var P=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"]=P,P.__name__=["verb","core","BoundingBox"],P.intervalsOverlap=function(a,b,c,d,e){null==e&&(e=-1);var f;f=-.5>e?Q.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},P.prototype={fromPoint:function(a){return new P([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 P([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(!P.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 P([h,g])},__class__:P};var Q=b.core.Constants=function(){};g["verb.core.Constants"]=Q,Q.__name__=["verb","core","Constants"];var R=b.core.Plane=function(a,b){this.origin=a,this.normal=b};g["verb.core.Plane"]=R,R.__name__=["verb","core","Plane"],R.prototype={__class__:R};var S=b.core.Ray=function(a,b){this.origin=a,this.dir=b};g["verb.core.Ray"]=S,S.__name__=["verb","core","Ray"],S.prototype={__class__:S};var T=b.core.NurbsCurveData=function(a,b,c){this.degree=a,this.controlPoints=c,this.knots=b};g["verb.core.NurbsCurveData"]=T,T.__name__=["verb","core","NurbsCurveData"],T.prototype={__class__:T};var U=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"]=U,U.__name__=["verb","core","NurbsSurfaceData"],U.prototype={__class__:U};var V=b.core.MeshData=function(a,b,c,d){this.faces=a,this.points=b,this.normals=c,this.uvs=d};g["verb.core.MeshData"]=V,V.__name__=["verb","core","MeshData"],V.empty=function(){return new V([],[],[],[])},V.prototype={__class__:V};var W=b.core.PolylineData=function(a,b){this.points=a,this.params=b};g["verb.core.PolylineData"]=W,W.__name__=["verb","core","PolylineData"],W.prototype={__class__:W};var X=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"]=X,X.__name__=["verb","core","VolumeData"],X.prototype={__class__:X};var Y=b.core.Pair=function(a,b){this.item0=a,this.item1=b};g["verb.core.Pair"]=Y,Y.__name__=["verb","core","Pair"],Y.prototype={__class__:Y};var Z=b.core.Interval=function(a,b){this.min=a,this.max=b};g["verb.core.Interval"]=Z,Z.__name__=["verb","core","Interval"],Z.prototype={__class__:Z};var $=b.core.CurveCurveIntersection=function(a,b,c,d){this.point0=a,this.point1=b,this.u0=c,this.u1=d};g["verb.core.CurveCurveIntersection"]=$,$.__name__=["verb","core","CurveCurveIntersection"],$.prototype={__class__:$};var _=b.core.CurveSurfaceIntersection=function(a,b,c,d){this.u=a,this.uv=b,this.curvePoint=c,this.surfacePoint=d};g["verb.core.CurveSurfaceIntersection"]=_,_.__name__=["verb","core","CurveSurfaceIntersection"],_.prototype={__class__:_};var aa=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"]=aa,aa.__name__=["verb","core","MeshIntersectionPoint"],aa.prototype={__class__:aa};var ba=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"]=ba,ba.__name__=["verb","core","PolylineMeshIntersection"],ba.prototype={__class__:ba};var ca=b.core.SurfaceSurfaceIntersectionPoint=function(a,b,c,d){this.uv0=a,this.uv1=b,this.point=c,this.dist=d};g["verb.core.SurfaceSurfaceIntersectionPoint"]=ca,ca.__name__=["verb","core","SurfaceSurfaceIntersectionPoint"],ca.prototype={__class__:ca};var da=b.core.TriSegmentIntersection=function(a,b,c,d){this.point=a,this.s=b,this.t=c,this.p=d};g["verb.core.TriSegmentIntersection"]=da,da.__name__=["verb","core","TriSegmentIntersection"],da.prototype={__class__:da};var ea=b.core.CurveTriPoint=function(a,b,c){this.u=a,this.point=b,this.uv=c};g["verb.core.CurveTriPoint"]=ea,ea.__name__=["verb","core","CurveTriPoint"],ea.prototype={__class__:ea};var fa=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"]=fa,fa.__name__=["verb","core","SurfacePoint"],fa.fromUv=function(a,b){return new fa(null,null,[a,b])},fa.prototype={__class__:fa};var ga=b.core.CurvePoint=function(a,b){this.u=a,this.pt=b};g["verb.core.CurvePoint"]=ga,ga.__name__=["verb","core","CurvePoint"],ga.prototype={__class__:ga};var ha=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"]=ha,ha.__name__=["verb","core","KdTree"],ha.prototype={buildTree:function(a,b,c){var d,e,f=b%this.dim;return 0==a.length?null:1==a.length?new ka(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 ka(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 ia(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 Y(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 Y(null,c))}d(this.root);for(var i=[],j=0;b>j;){var k=j++;null!=f.content[k].item0&&i.push(new Y(f.content[k].item0.kdPoint,f.content[k].item1))}return i},__class__:ha};var ia=function(a){this.content=[],this.scoreFunction=a};g["verb.core.BinaryHeap"]=ia,ia.__name__=["verb","core","BinaryHeap"],ia.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__:ia};var ja=b.core.KdPoint=function(a,b){this.point=a,this.obj=b};g["verb.core.KdPoint"]=ja,ja.__name__=["verb","core","KdPoint"],ja.prototype={__class__:ja};var ka=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"]=ka,ka.__name__=["verb","core","KdNode"],ka.prototype={__class__:ka};var la=function(){};g["verb.eval.IBoundingBoxTree"]=la,la.__name__=["verb","eval","IBoundingBoxTree"],la.prototype={__class__:la};var ma=function(a,b){this._boundingBox=null,this._curve=a,null==b&&(b=xa.domain(this._curve.knots)/64),this._knotTol=b};g["verb.core.LazyCurveBoundingBoxTree"]=ma,ma.__name__=["verb","core","LazyCurveBoundingBoxTree"],ma.__interfaces__=[la],ma.prototype={split:function(){var a=N.first(this._curve.knots),b=N.last(this._curve.knots),c=b-a,d=Ba.curveSplit(this._curve,(b+a)/2+.1*c*Math.random());return new Y(new ma(d[0],this._knotTol),new ma(d[1],this._knotTol))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=new P(Da.dehomogenize1d(this._curve.controlPoints))),this._boundingBox},"yield":function(){return this._curve},indivisible:function(a){return xa.domain(this._curve.knots)d;){var f=d++;c.push(f)}b=c}this._faceIndices=b};g["verb.core.LazyMeshBoundingBoxTree"]=na,na.__name__=["verb","core","LazyMeshBoundingBoxTree"],na.__interfaces__=[la],na.prototype={split:function(){var a=sa.sortTrianglesOnLongestAxis(this.boundingBox(),this._mesh,this._faceIndices),b=N.left(a),c=N.right(a);return new Y(new na(this._mesh,b),new na(this._mesh,c))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=sa.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__:na};var oa=function(a,b){this._boundingBox=null,this._polyline=a,null==b&&(b=new Z(0,0!=a.points.length?a.points.length-1:0)),this._interval=b};g["verb.core.LazyPolylineBoundingBoxTree"]=oa,oa.__name__=["verb","core","LazyPolylineBoundingBoxTree"],oa.__interfaces__=[la],oa.prototype={split:function(){var a=this._interval.min,b=this._interval.max,c=a+Math.ceil((b-a)/2),d=new Z(a,c),e=new Z(c,b);return new Y(new oa(this._polyline,d),new oa(this._polyline,e))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=new P(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__:oa};var pa=function(a,b,c,d){null==b&&(b=!1),this._boundingBox=null,this._surface=a,this._splitV=b,null==c&&(c=xa.domain(a.knotsU)/16),null==d&&(d=xa.domain(a.knotsV)/16),this._knotTolU=c,this._knotTolV=d};g["verb.core.LazySurfaceBoundingBoxTree"]=pa,pa.__name__=["verb","core","LazySurfaceBoundingBoxTree"],pa.__interfaces__=[la],pa.prototype={split:function(){var a,b;this._splitV?(a=N.first(this._surface.knotsV),b=N.last(this._surface.knotsV)):(a=N.first(this._surface.knotsU),b=N.last(this._surface.knotsU));var c=(a+b)/2,d=Ba.surfaceSplit(this._surface,c,this._splitV);return new Y(new pa(d[0],!this._splitV,this._knotTolU,this._knotTolV),new pa(d[1],!this._splitV,this._knotTolU,this._knotTolV))},boundingBox:function(){if(null==this._boundingBox){this._boundingBox=new P;for(var a=0,b=this._surface.controlPoints;ad;){var f=d++;c.push(xa.mul(a,b[f]))}return c},qa.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},qa.add=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(xa.add(a[f],b[f]))}return c},qa.div=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(xa.div(a[f],b))}return c},qa.sub=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(xa.sub(a[f],b[f]))}return c},qa.dot=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(xa.dot(a[f],b))}return c},qa.identity=function(a){for(var b=xa.zeros2d(a,a),c=0;a>c;){var d=c++;b[d][d]=1}return b},qa.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},qa.solve=function(a,b){return qa.LUsolve(qa.LU(a),b)},qa.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},qa.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 ra(a,q)};var ra=function(a,b){this.LU=a,this.P=b};g["verb.core._Mat.LUDecomp"]=ra,ra.__name__=["verb","core","_Mat","LUDecomp"],ra.prototype={__class__:ra};var sa=b.core.Mesh=function(){};g["verb.core.Mesh"]=sa,sa.__name__=["verb","core","Mesh"],sa.getTriangleNorm=function(a,b){var c=a[b[0]],d=a[b[1]],e=a[b[2]],f=xa.sub(d,c),g=xa.sub(e,c),h=xa.cross(f,g);return xa.mul(1/xa.norm(h),h)},sa.makeMeshAabb=function(a,b){for(var c=new P,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},sa.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},sa.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},sa.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=xa.sub(e,c),l=xa.sub(f,c),m=xa.sub(g,c),n=xa.norm(xa.cross(xa.sub(e,f),xa.sub(e,g))),o=xa.norm(xa.cross(l,m))/n,p=xa.norm(xa.cross(m,k))/n,q=xa.norm(xa.cross(k,l))/n;return xa.add(xa.mul(o,h),xa.add(xa.mul(p,i),xa.mul(q,j)))};var ta=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=sa.makeMeshAabb(a,b),b.length<1)return void(this._empty=!0);if(b.length<2)return void(this._face=b[0]);var g=sa.sortTrianglesOnLongestAxis(this._boundingBox,a,b),h=N.left(g),i=N.right(g);this._children=new Y(new ta(a,h),new ta(a,i))};g["verb.core.MeshBoundingBoxTree"]=ta,ta.__name__=["verb","core","MeshBoundingBoxTree"],ta.__interfaces__=[la],ta.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__:ta};var ua=b.core.Minimizer=function(){};g["verb.core.Minimizer"]=ua,ua.__name__=["verb","core","Minimizer"],ua.uncmin=function(a,b,c,d,e){null==c&&(c=1e-8),null==d&&(d=function(b){return ua.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 A("uncmin: f(x0) is a NaN!");c=Math.max(c,Q.EPSILON);var j,k,l,m,n,o,p,q,r,s=qa.identity(g),t=0,u=[],v="";for(k=d(b);e>t;){if(!xa.all(xa.finite(k))){v="Gradient has Infinity or NaN";break}if(j=xa.neg(qa.dot(s,k)),!xa.all(xa.finite(j))){v="Search direction has Infinity or NaN";break}if(r=xa.norm(j),c>r){v="Newton step smaller than tol";break}for(q=1,f=xa.dot(k,j),m=b;e>t&&!(c>q*r)&&(u=xa.mul(q,j),m=xa.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=xa.sub(l,k),p=xa.dot(n,u),o=qa.dot(s,n),s=qa.sub(qa.add(s,qa.mul((p+xa.dot(n,o))/(p*p),ua.tensor(u,u))),qa.div(qa.add(ua.tensor(o,u),ua.tensor(u,o)),p)),b=m,h=i,k=l,++t}return new va(b,h,k,s,t,v)},ua.numericalGradient=function(a,b){var c=b.length,d=a(b);if(NaN==d)throw new A("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 A("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=xa.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(xa.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},ua.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 va=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"]=va,va.__name__=["verb","core","MinimizationResult"],va.prototype={__class__:va};var wa=b.core.Trig=function(){};g["verb.core.Trig"]=wa,wa.__name__=["verb","core","Trig"],wa.isPointInPlane=function(a,b,c){return Math.abs(xa.dot(xa.sub(a,b.origin),b.normal))h},wa.segmentClosestPoint=function(a,b,c,d,e){var f=xa.sub(c,b),g=xa.norm(f);if(gk?{u:d,pt:b}:k>g?{u:e,pt:c}:{u:d+(e-d)*k/g,pt:xa.add(h,xa.mul(k,i))}};var xa=b.core.Vec=function(){};g["verb.core.Vec"]=xa,xa.__name__=["verb","core","Vec"],xa.angleBetween=function(a,b){return Math.acos(xa.dot(a,b)/(xa.norm(a)*xa.norm(b)))},xa.positiveAngleBetween=function(a,b,c){var d=xa.cross(a,b),e=xa.norm(a),f=xa.norm(b),g=e*f,h=xa.dot(a,b),i=xa.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=xa.dot(c,d);return Math.abs(l)0?k:-k},xa.signedAngleBetween=function(a,b,c){var d=xa.cross(a,b),e=xa.norm(a),f=xa.norm(b),g=e*f,h=xa.dot(a,b),i=xa.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=xa.dot(c,d);return l>0?k:2*Math.PI-k},xa.angleBetweenNormalized2d=function(a,b){var c=a[0]*b[1]-a[1]*b[0];return Math.atan2(c,xa.dot(a,b))},xa.domain=function(a){return N.last(a)-N.first(a)},xa.range=function(a){for(var b=[],c=0,d=0;a>d;){d++;b.push(c),c+=1}return b},xa.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},xa.neg=function(a){return a.map(function(a){return-a})},xa.min=function(a){return j.fold(a,function(a,b){return Math.min(a,b)},1/0)},xa.max=function(a){return j.fold(a,function(a,b){return Math.max(a,b)},-(1/0))},xa.all=function(a){return j.fold(a,function(a,b){return b&&a},!0)},xa.finite=function(a){return a.map(function(a){return isFinite(a)})},xa.onRay=function(a,b,c){return xa.add(a,xa.mul(c,b))},xa.lerp=function(a,b,c){return xa.add(xa.mul(a,b),xa.mul(1-a,c))},xa.normalized=function(a){return xa.div(a,xa.norm(a))},xa.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]]},xa.dist=function(a,b){return xa.norm(xa.sub(a,b))},xa.distSquared=function(a,b){return xa.normSquared(xa.sub(a,b))},xa.sum=function(a){return j.fold(a,function(a,b){return b+a},0)},xa.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 xa.add(b,a)},xa.rep(c,0))},xa.norm=function(a){var b=xa.normSquared(a);return 0!=b?Math.sqrt(b):b},xa.normSquared=function(a){return j.fold(a,function(a,b){return b+a*a},0)},xa.rep=function(a,b){for(var c=[],d=0;a>d;){d++;c.push(b)}return c},xa.zeros1d=function(a){for(var b=[],c=0;a>c;){c++;b.push(0)}return b},xa.zeros2d=function(a,b){for(var c=[],d=0;a>d;){d++;c.push(xa.zeros1d(b))}return c},xa.zeros3d=function(a,b,c){for(var d=[],e=0;a>e;){e++;d.push(xa.zeros2d(b,c))}return d},xa.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},xa.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},xa.mul=function(a,b){for(var c=[],d=0,e=b.length;e>d;){var f=d++;c.push(a*b[f])}return c},xa.div=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(a[f]/b)}return c},xa.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},xa.isZero=function(a){for(var b=0,c=a.length;c>b;){var d=b++;if(Math.abs(a[d])>Q.TOLERANCE)return!1}return!0},xa.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},xa.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])Q.EPSILON&&(c=new za(e,0),b.push(c)),c.inc()}return b},ya.isRationalSurfaceClosed=function(a,b){null==b&&(b=!0);var c;c=b?a.controlPoints:qa.transpose(a.controlPoints);for(var d=0,e=c[0].length;e>d;){var f=d++,g=xa.dist(N.first(c)[f],N.last(c)[f])r;){var t=r++,u=p.points[t],v=xa.normSquared(xa.sub(b,u));q>v&&(q=v,e=p.uvs[t])}for(var w=function(b){return Da.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=xa.dot(d,c),k=xa.dot(e,c),l=[-j,-k],m=xa.dot(d,d)+xa.dot(f,c),n=xa.dot(d,e)+xa.dot(h,c),o=xa.dot(d,e)+xa.dot(i,c),p=xa.dot(e,e)+xa.dot(g,c),q=[[m,n],[o,p]],r=qa.solve(q,l);return xa.add(r,a)};f>g;){c=w(e),d=xa.sub(c[0][0],b);var y=xa.norm(d),z=xa.dot(c[1][0],d),A=xa.norm(c[1][0])*y,B=xa.dot(c[0][1],d),C=xa.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-Q.EPSILON,I[1]]),I[1]m&&(I=o?[I[0],l+(I[0]-m)]:[I[0],m-Q.EPSILON]);var J=xa.norm(xa.mul(I[0]-e[0],c[1][0])),K=xa.norm(xa.mul(I[1]-e[1],c[0][1]));if(h>J+K)return e;e=I,g++}return e},ya.rationalCurveClosestPoint=function(a,b){return Da.rationalCurvePoint(a,ya.rationalCurveClosestParam(a,b))},ya.rationalCurveClosestParam=function(a,b){for(var c=1/0,d=0,e=Ha.rationalCurveRegularSample(a,a.controlPoints.length*a.degree,!0),f=0,g=e.length-1;g>f;){var h=f++,i=e[h][0],j=e[h+1][0],k=e[h].slice(1),l=e[h+1].slice(1),m=wa.segmentClosestPoint(b,k,l,i,j),n=xa.norm(xa.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=N.last(a.knots),w=xa.normSquared(xa.sub(a.controlPoints[0],N.last(a.controlPoints)))r;){o=y(x),p=xa.sub(o[0],b);var A=xa.norm(p),B=xa.dot(o[1],p),C=xa.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=xa.norm(xa.mul(G-x,o[1]));if(s>H)return x;x=G,r++}return x},ya.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:ya.rationalBezierCurveArcLength(a),b>e)return N.last(a.knots);var f,g=a.knots[0],h=0,i=N.last(a.knots),j=e,k=0,l=0;for(f=null!=c?c:2*Q.TOLERANCE;j-h>f;)k=(g+i)/2,l=ya.rationalBezierCurveArcLength(a,k),l>b?(i=k,j=l):(g=k,h=l);return(g+i)/2},ya.rationalCurveArcLength=function(a,b,c){null==c&&(c=16),b=null==b?N.last(a.knots):b;for(var d=Ga.decomposeCurveIntoBeziers(a),e=0,f=d[0],g=0;ej;){var k=j++;e=g*ya.Tvalues[i][k]+g+a.knots[0],f=Da.rationalCurveDerivatives(a,e,1),h+=ya.Cvalues[i][k]*xa.norm(f[1])}return g*h};var za=b.eval.KnotMultiplicity=function(a,b){this.knot=a,this.mult=b};g["verb.eval.KnotMultiplicity"]=za,za.__name__=["verb","eval","KnotMultiplicity"],za.prototype={inc:function(){this.mult++},__class__:za};var Aa=b.eval.Check=function(){};g["verb.eval.Check"]=Aa,Aa.__name__=["verb","eval","Check"],Aa.isValidKnotVector=function(a,b){if(0==a.length)return!1;if(a.length<2*(b+1))return!1;for(var c=N.first(a),d=0,e=b+1;e>d;){var f=d++;if(Math.abs(a[f]-c)>Q.EPSILON)return!1}c=N.last(a);for(var g=a.length-b-1,h=a.length;h>g;){var i=g++;if(Math.abs(a[i]-c)>Q.EPSILON)return!1}return Aa.isNonDecreasing(a)},Aa.isNonDecreasing=function(a){for(var b=N.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=Da.knotSpan(e,b,d),n=null,o=0;og;){g++;f.push(b)}c=f;var i=Ga.curveKnotRefine(a,c),j=Da.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 T(d,k,m),new T(d,l,n)]},Ba.rationalCurveByEqualArcLength=function(a,b){var c=ya.rationalCurveArcLength(a),d=c/b;return Ba.rationalCurveByArcLength(a,d)},Ba.rationalCurveByArcLength=function(a,b){var c=Ga.decomposeCurveIntoBeziers(a),d=c.map(function(a){return ya.rationalBezierCurveArcLength(a)}),e=xa.sum(d),f=[new Ca(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++;p=xa.sub(p,xa.mul(O.get(o,s)*g[0][s],h[l][o-s]))}for(var t=1,u=l+1;u>t;){var v=t++;p=xa.sub(p,xa.mul(O.get(l,v)*g[v][0],h[l-v][o]));for(var w=xa.zeros1d(i),x=1,y=o+1;y>x;){var z=x++;w=xa.add(w,xa.mul(O.get(o,z)*g[v][z],h[l-v][o-z]))}p=xa.sub(p,xa.mul(O.get(l,v),w))}h[l].push(xa.mul(1/g[0][0],p))}}return h},Da.rationalSurfacePoint=function(a,b,c){return Da.dehomogenize(Da.surfacePoint(a,b,c))},Da.rationalCurveDerivatives=function(a,b,c){null==c&&(c=1);for(var d=Da.curveDerivatives(a,b,c),e=Da.rational1d(d),f=Da.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++;k=xa.sub(k,xa.mul(O.get(j,n)*f[n],g[j-n]))}g.push(xa.mul(1/f[0],k))}return g},Da.rationalCurvePoint=function(a,b){return Da.dehomogenize(Da.curvePoint(a,b))},Da.surfaceDerivatives=function(a,b,c,d){var e=a.knotsU.length-a.degreeU-2,f=a.knotsV.length-a.degreeV-2;return Da.surfaceDerivativesGivenNM(e,f,a,b,c,d)},Da.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(!Da.areValidRelations(g,i.length,j.length)||!Da.areValidRelations(h,i[0].length,k.length))throw new A("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=xa.zeros3d(l+1,n+1,m),p=Da.knotSpanGivenN(a,g,d,j),q=Da.knotSpanGivenN(b,h,e,k),r=Da.derivativeBasisFunctionsGivenNI(p,d,g,a,j),s=Da.derivativeBasisFunctionsGivenNI(q,e,h,b,k),t=xa.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 B=y++;t[B]=xa.zeros1d(m);for(var C=0,D=g+1;D>C;){var E=C++;t[B]=xa.add(t[B],xa.mul(r[x][E],i[p-g+E][q-h+B]))}}var F=f-x;u=n>F?F:n;for(var G=0,H=u+1;H>G;){var I=G++;o[x][I]=xa.zeros1d(m);for(var J=0,K=h+1;K>J;){var L=J++;o[x][I]=xa.add(o[x][I],xa.mul(s[I][L],t[L]))}}}return o},Da.surfacePoint=function(a,b,c){var d=a.knotsU.length-a.degreeU-2,e=a.knotsV.length-a.degreeV-2;return Da.surfacePointGivenNM(d,e,a,b,c)},Da.surfacePointGivenNM=function(a,b,c,d,e){var f=c.degreeU,g=c.degreeV,h=c.controlPoints,i=c.knotsU,j=c.knotsV;if(!Da.areValidRelations(f,h.length,i.length)||!Da.areValidRelations(g,h[0].length,j.length))throw new A("Invalid relations between control points, knot vector, and n");for(var k=h[0][0].length,l=Da.knotSpanGivenN(a,f,d,i),m=Da.knotSpanGivenN(b,g,e,j),n=Da.basisFunctionsGivenKnotSpanIndex(l,d,f,i),o=Da.basisFunctionsGivenKnotSpanIndex(m,e,g,j),p=l-f,q=m,r=xa.zeros1d(k),s=xa.zeros1d(k),t=0,u=g+1;u>t;){var v=t++;s=xa.zeros1d(k),q=m-g+v;for(var w=0,x=f+1;x>w;){var y=w++;s=xa.add(s,xa.mul(n[y],h[p+y][q]))}r=xa.add(r,xa.mul(o[v],s))}return r},Da.curveDerivatives=function(a,b,c){var d=a.knots.length-a.degree-2;return Da.curveDerivativesGivenN(d,a,b,c)},Da.curveDerivativesGivenN=function(a,b,c,d){var e=b.degree,f=b.controlPoints,g=b.knots;if(!Da.areValidRelations(e,f.length,g.length))throw new A("Invalid relations between control points, knot vector, and n");var h,i=f[0].length;h=e>d?d:e;for(var j=xa.zeros2d(h+1,i),k=Da.knotSpanGivenN(a,e,c,g),l=Da.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++;j[o]=xa.add(j[o],xa.mul(l[o][r],f[k-e+r]))}return j},Da.curvePoint=function(a,b){var c=a.knots.length-a.degree-2;return Da.curvePointGivenN(c,a,b)},Da.areValidRelations=function(a,b,c){return b+a+1-c==0},Da.curvePointGivenN=function(a,b,c){var d=b.degree,e=b.controlPoints,f=b.knots;if(!Da.areValidRelations(d,e.length,f.length))throw new A("Invalid relations between control points, knot Array, and n");for(var g=Da.knotSpanGivenN(a,d,c,f),h=Da.basisFunctionsGivenKnotSpanIndex(g,c,d,f),i=xa.zeros1d(e[0].length),j=0,k=d+1;k>j;){var l=j++;i=xa.add(i,xa.mul(h[l],e[g-d+l]))}return i},Da.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 Da.volumePointGivenNML(a,e,f,g,b,c,d)},Da.volumePointGivenNML=function(a,b,c,d,e,f,g){if(!Da.areValidRelations(a.degreeU,a.controlPoints.length,a.knotsU.length)||!Da.areValidRelations(a.degreeV,a.controlPoints[0].length,a.knotsV.length)||!Da.areValidRelations(a.degreeW,a.controlPoints[0][0].length,a.knotsW.length))throw new A("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=Da.knotSpanGivenN(b,i,e,l),q=Da.knotSpanGivenN(c,j,f,m),r=Da.knotSpanGivenN(d,k,g,n),s=Da.basisFunctionsGivenKnotSpanIndex(p,e,i,l),t=Da.basisFunctionsGivenKnotSpanIndex(q,f,j,m),u=Da.basisFunctionsGivenKnotSpanIndex(r,g,k,n),v=p-i,w=xa.zeros1d(o),x=xa.zeros1d(o),y=xa.zeros1d(o),z=0,B=k+1;B>z;){var C=z++;y=xa.zeros1d(o);for(var D=r-k+C,E=0,F=j+1;F>E;){ -var G=E++;x=xa.zeros1d(o);for(var H=q-j+G,I=0,J=i+1;J>I;){var K=I++;x=xa.add(x,xa.mul(s[K],h[v+K][H][D]))}y=xa.add(y,xa.mul(t[G],x))}w=xa.add(w,xa.mul(u[C],y))}return w},Da.derivativeBasisFunctions=function(a,b,c){var d=Da.knotSpan(b,a,c),e=c.length-1,f=e-b-1;return Da.derivativeBasisFunctionsGivenNI(d,a,b,f,c)},Da.derivativeBasisFunctionsGivenNI=function(a,b,c,d,e){var f=xa.zeros2d(c+1,c+1),g=xa.zeros1d(c+1),h=xa.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=xa.zeros2d(d+1,c+1),q=xa.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},Da.basisFunctions=function(a,b,c){var d=Da.knotSpan(b,a,c);return Da.basisFunctionsGivenKnotSpanIndex(d,a,b,c)},Da.basisFunctionsGivenKnotSpanIndex=function(a,b,c,d){var e=xa.zeros1d(c+1),f=xa.zeros1d(c+1),g=xa.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},Da.knotSpan=function(a,b,c){return Da.knotSpanGivenN(c.length-a-2,a,b,c)},Da.knotSpanGivenN=function(a,b,c,d){if(c>d[a+1]-Q.EPSILON)return a;if(c=d[g+1];)cf;){var g=f++;c.push(a[g]/d)}return c},Da.rational1d=function(a){var b=a[0].length-1;return a.map(function(a){return a.slice(0,b)})},Da.rational2d=function(a){return a.map(Da.rational1d)},Da.weight1d=function(a){var b=a[0].length-1;return a.map(function(a){return a[b]})},Da.weight2d=function(a){return a.map(Da.weight1d)},Da.dehomogenize1d=function(a){return a.map(Da.dehomogenize)},Da.dehomogenize2d=function(a){return a.map(Da.dehomogenize1d)},Da.homogenize1d=function(a,b){var c,d=a.length,e=a[0].length,f=[],g=0,h=[];c=null!=b?b:xa.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},Da.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(xa.rep(a[0].length,1))}c=f}for(var h=0;d>h;){var i=h++;e.push(Da.homogenize1d(a[i],c[i]))}return e};var Ea=b.eval.Intersect=function(){};g["verb.eval.Intersect"]=Ea,Ea.__name__=["verb","eval","Intersect"],Ea.meshSlices=function(a,b,c,d){for(var e=new ta(a),f=e.boundingBox(),g=f.min[0],h=f.min[1],i=f.max[0],j=f.max[1],k=xa.span(b,c,d),l=[],m=0;mr)break;var u=xa.normalized(xa.cross(h,n)),v=xa.dot(u,g),w=Ea.threePlanes(h,k,n,q,u,v);if(null==w)throw new A("panic!");var x=xa.sub(w,g),y=xa.sub(w,m),z=xa.cross(i,h),B=xa.cross(j,h),C=xa.cross(o,n),D=xa.cross(p,n),E=xa.dot(B,x)/xa.dot(B,i),F=xa.dot(z,x)/xa.dot(z,j),G=xa.dot(D,y)/xa.dot(D,o),H=xa.dot(C,y)/xa.dot(C,p);c=xa.add([E,F],c),d=xa.add([G,H],d),t++}while(s>t);return new ca(c,d,g,r)},Ea.meshes=function(a,b,c,d){null==c&&(c=new na(a)),null==d&&(d=new na(b));var e=Ea.boundingBoxTrees(c,d,0),f=N.unique(e.map(function(c){return Ea.triangles(a,c.item0,b,c.item1)}).filter(function(a){return null!=a}).filter(function(a){return xa.distSquared(a.min.point,a.max.point)>Q.EPSILON}),function(a,b){var c=xa.sub(a.min.uv0,b.min.uv0),d=xa.dot(c,c),e=xa.sub(a.max.uv0,b.max.uv0),f=xa.dot(e,e),g=xa.sub(a.min.uv0,b.max.uv0),h=xa.dot(g,g),i=xa.sub(a.max.uv0,b.min.uv0),j=xa.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 Y(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},Ea.curves=function(a,b,c){var d=Ea.boundingBoxTrees(new ma(a),new ma(b),0);return N.unique(d.map(function(d){return Ea.curvesWithEstimate(a,b,N.first(d.item0.knots),N.first(d.item1.knots),c)}).filter(function(a){return xa.distSquared(a.point0,a.point1)m;){var n=m++,o=e[n],p=i[n],q=Ea.rays(o,p,a.origin,a.dir);if(null!=q){var r=q.u0,s=q.u1;r<-Q.EPSILON||r>j[n]+Q.EPSILON||((null==k||sl.u)&&(l=new ea(s,xa.onRay(a.origin,a.dir,s),xa.onRay(f[n],g[n],r/j[n]))))}}return null==l||null==k?null:new Z(k,l)},Ea.mergeTriangleClipIntervals=function(a,b,c,d,e,f){if(b.min.u>a.max.u+Q.EPSILON||a.min.u>b.max.u+Q.EPSILON)return null;var g;g=a.min.u>b.min.u?new Y(a.min,0):new Y(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=-xa.dot(a,b),p=-xa.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 S(n,xa.normalized(e))},Ea.threePlanes=function(a,b,c,d,e,f){var g=xa.cross(c,e),h=xa.dot(a,g);if(Math.abs(h)q)return new $(o,p,m,n)}return null},Ea.rays=function(a,b,c,d){var e=xa.dot(b,d),f=xa.dot(b,c),g=xa.dot(b,a),h=xa.dot(d,c),i=xa.dot(d,a),j=xa.dot(b,b),k=xa.dot(d,d),l=j*k-e*e;if(Math.abs(l)o||o>1)return null;var p=xa.add(a,xa.mul(o,k)),q=xa.dot(h,i),r=xa.dot(h,h),s=xa.dot(i,i),t=xa.sub(p,e),u=xa.dot(t,h),v=xa.dot(t,i),w=q*q-r*s;if(Math.abs(w)1+Q.EPSILON||y>1+Q.EPSILON||y<-Q.EPSILON||x<-Q.EPSILON||x+y>1+Q.EPSILON?null:new da(p,x,y,o)},Ea.segmentAndPlane=function(a,b,c,d){var e=xa.dot(d,xa.sub(b,a));if(Math.abs(e)1+Q.EPSILON||g<-Q.EPSILON?null:{p:g}};var Fa=b.eval.Make=function(){};g["verb.eval.Make"]=Fa,Fa.__name__=["verb","eval","Make"],Fa.rationalTranslationalSurface=function(a,b){for(var c=Da.rationalCurvePoint(b,N.first(b.knots)),d=N.first(b.knots),e=N.last(b.knots),f=2*b.controlPoints.length,g=(e-d)/(f-1),h=[],i=0;f>i;){var j=i++,k=xa.sub(Da.rationalCurvePoint(b,d+j*g),c),l=Ga.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 Fa.loftedSurface(h)},Fa.surfaceBoundaryCurves=function(a){var b=Fa.surfaceIsocurve(a,N.first(a.knotsU),!1),c=Fa.surfaceIsocurve(a,N.last(a.knotsU),!1),d=Fa.surfaceIsocurve(a,N.first(a.knotsV),!0),e=Fa.surfaceIsocurve(a,N.last(a.knotsV),!0);return[b,c,d,e]},Fa.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=ya.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?Ga.surfaceKnotRefine(a,xa.rep(k,b),c):a;var m=Da.knotSpan(e,b,d);return Math.abs(b-N.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=Fa.rationalInterpCurve(j,b,!0);f.push(k.controlPoints),e=k.knots}return new U(c,b,d,e,f)},Fa.clonedCurve=function(a){return new T(a.degree,a.knots.slice(),a.controlPoints.map(function(a){return a.slice()}))},Fa.rationalBezierCurve=function(a,b){for(var c=a.length-1,d=[],e=0,f=c+1;f>e;){e++;d.push(0)}for(var g=0,h=c+1;h>g;){g++;d.push(1)}return null==b&&(b=xa.rep(a.length,1)),new T(c,d,Da.homogenize1d(a,b))},Fa.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=xa.lerp(o,a,b),q=xa.lerp(o,d,c),r=xa.lerp(1-n/f,p,q);r.push(1),k.push(r)}g.push(k)}var s=xa.rep(e+1,0),t=xa.rep(e+1,1);return new U(e,e,s.concat(t),s.concat(t),g)},Fa.ellipseArc=function(a,b,c,d,e){var f=xa.norm(b),g=xa.norm(c);b=xa.normalized(b),c=xa.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=xa.add(a,xa.add(xa.mul(f*Math.cos(d),b),xa.mul(g*Math.sin(d),c))),m=xa.sub(xa.mul(Math.cos(d),c),xa.mul(Math.sin(d),b)),n=[],o=xa.zeros1d(2*i+3),p=0,q=d,r=xa.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=xa.add(a,xa.add(xa.mul(f*Math.cos(q),b),xa.mul(g*Math.sin(q),c)));r[p+2]=1,n[p+2]=v;var w=xa.sub(xa.mul(Math.cos(q),c),xa.mul(Math.sin(q),b)),x=Ea.rays(l,xa.mul(1/xa.norm(m),m),v,xa.mul(1/xa.norm(w),w)),y=xa.add(l,xa.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 T(2,o,Da.homogenize1d(n,r))},Fa.arc=function(a,b,c,d,e,f){return Fa.ellipseArc(a,xa.mul(d,xa.normalized(b)),xa.mul(d,xa.normalized(c)),e,f)},Fa.polyline=function(a){for(var b=[0,0],c=0,d=0,e=a.length-1;e>d;){var f=d++;c+=xa.dist(a[f],a[f+1]),b.push(c)}b.push(c),b=xa.mul(1/c,b);for(var g,h=[],i=0,j=a.length;j>i;){i++;h.push(1)}return g=h,new T(1,b,Da.homogenize1d(a.slice(0),g))},Fa.extrudedSurface=function(a,b,c){for(var d=[[],[],[]],e=[[],[],[]],f=Da.dehomogenize1d(c.controlPoints),g=Da.weight1d(c.controlPoints),h=xa.mul(b,a),i=xa.mul(.5*b,a),j=0,k=f.length;k>j;){var l=j++;d[2][l]=f[l],d[1][l]=xa.add(i,f[l]),d[0][l]=xa.add(h,f[l]),e[0][l]=g[l],e[1][l]=g[l],e[2][l]=g[l]}return new U(2,c.degree,[0,0,0,1,1,1],c.knots,Da.homogenize2d(d,e))},Fa.cylindricalSurface=function(a,b,c,d,e){var f=xa.cross(a,b),g=(2*Math.PI,Fa.arc(c,b,f,e,0,2*Math.PI));return Fa.extrudedSurface(a,d,g)},Fa.revolvedSurface=function(a,b,c,d){var e,f,g=Da.dehomogenize1d(a.controlPoints),h=Da.weight1d(a.controlPoints);d<=Math.PI/2?(e=1,f=xa.zeros1d(6+2*(e-1))):d<=Math.PI?(e=2,f=xa.zeros1d(6+2*(e-1)),f[3]=f[4]=.5):d<=3*Math.PI/2?(e=3,f=xa.zeros1d(6+2*(e-1)),f[3]=f[4]=.3333333333333333,f[5]=f[6]=.6666666666666666):(e=4,f=xa.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=xa.zeros1d(e+1),p=xa.zeros1d(e+1),q=xa.zeros3d(2*e+1,g.length,3),r=xa.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=wa.rayClosestPoint(g[x],b,c),z=xa.sub(g[x],y),A=xa.norm(z),B=xa.cross(c,z);A>Q.EPSILON&&(z=xa.mul(1/A,z),B=xa.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:xa.add(y,xa.add(xa.mul(A*p[I],z),xa.mul(A*o[I],B))),q[E+2][x]=H,r[E+2][x]=h[x];var J=xa.sub(xa.mul(p[I],B),xa.mul(o[I],z));if(0==A)q[E+1][x]=y;else{var K=Ea.rays(C,xa.mul(1/xa.norm(D),D),H,xa.mul(1/xa.norm(J),J)),L=xa.add(C,xa.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 U(2,a.degree,f,a.knots,Da.homogenize2d(q,r))},Fa.sphericalSurface=function(a,b,c,d){var e=Fa.arc(a,xa.mul(-1,b),c,d,0,Math.PI);return Fa.revolvedSurface(e,a,b,2*Math.PI)},Fa.conicalSurface=function(a,b,c,d,e){var f=2*Math.PI,g=1,h=[xa.add(c,xa.mul(d,a)),xa.add(c,xa.mul(e,b))],i=[0,0,1,1],j=[1,1],k=new T(g,i,Da.homogenize1d(h,j));return Fa.revolvedSurface(k,c,a,f)},Fa.rationalInterpCurve=function(a,b,c,d,e){if(null==c&&(c=!1),null==b&&(b=3),a.lengthg;){var i=g++,j=xa.norm(xa.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=xa.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(xa.rep(b+1,1)),B=[];y=r?a.length+1:a.length-1;var C;C=r?1:0;var D;D=r?a.length-(b-1):a.length-(b+1);for(var E=0;EU;){var V,W=[U++];if(r){V=[a[0][W[0]]],V.push(S*d[W[0]]);for(var X=1,Y=a.length-1;Y>X;){var Z=X++;V.push(a[Z][W[0]])}V.push(R*e[W[0]]),V.push(N.last(a)[W[0]])}else V=a.map(function(a){return function(b){return b[a[0]]}}(W));var $=qa.solve(B,V);Q.push($)}var _=qa.transpose(Q);if(!c){var aa=xa.rep(_.length,1);_=Da.homogenize1d(_,aa)}return new T(b,z,_)};var Ga=b.eval.Modify=function(){};g["verb.eval.Modify"]=Ga,Ga.__name__=["verb","eval","Modify"],Ga.curveReverse=function(a){return new T(a.degree,Ga.knotsReverse(a.knots),N.reversed(a.controlPoints))},Ga.surfaceReverse=function(a,b){return null==b&&(b=!1),b?new U(a.degreeU,a.degreeV,a.knotsU,Ga.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},Ga.unifyCurveKnotVectors=function(a){a=a.map(Fa.clonedCurve);for(var b=j.fold(a,function(a,b){return Ga.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 xa.sortedSetUnion(a.knots,b)},[]),v=0,w=a.length;w>v;){var x=v++,y=xa.sortedSetSub(u,a[x].knots);0==y.length&&(a[x]=a[x]),a[x]=Ga.curveKnotRefine(a[x],y)}return a},Ga.imin=function(a,b){return b>a?a:b},Ga.imax=function(a,b){return a>b?a:b},Ga.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=xa.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/O.get(o,u),w=Ga.imin(e,u),x=Ga.imax(0,u-h),y=w+1;y>x;){var z=x++;j[u][z]=v*O.get(e,z)*O.get(h,u-z)}for(var A=p+1;o>A;)for(var B=A++,C=Ga.imin(e,B),D=Ga.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,P=o+1;P>N;){var Q=N++;r[Q]=M}for(var R=0,S=e+1;S>R;){var U=R++;k[U]=g[U]}for(;n>K;){for(var V=K;n>K&&f[K]==f[K+1];)K+=1;var W=K-V+1,X=f[K],Y=I;I=e-W;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>W;)aa[ba-W-1]=_/(f[J+ba]-M),ba--;for(var ca=1,da=I+1;da>ca;){for(var ea=ca++,fa=I-ea,ga=W+ea,ha=e;ha>=ga;)k[ha]=xa.add(xa.mul(aa[ha-ga],k[ha]),xa.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]=xa.zeros1d(i);for(var la=Ga.imin(e,ka),ma=Ga.imax(0,ka-h),na=la+1;na>ma;){var oa=ma++;l[ka]=xa.add(l[ka],xa.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,ya=wa-H+1;wa-va>ua;){if(L>va){var za=(X-r[va])/(M-r[va]);q[va]=xa.lerp(za,q[va],q[va-1])}if(wa>=Z){if(H-o+Y>=wa-ua){var Aa=(X-r[wa-ua])/ra;l[ya]=xa.lerp(Aa,l[ya],l[ya+1])}}else l[ya]=xa.lerp(sa,l[ya],l[ya+1]);va+=1,wa-=1,ya-=1}pa-=1,qa+=1}if(J!=e)for(var Ba=0,Ca=o-Y;Ca>Ba;){Ba++;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 Ha=0;I>Ha;){var Ia=Ha++;k[Ia]=m[Ia]}for(var Ja=I,Ka=e+1;Ka>Ja;){var La=Ja++;k[La]=g[K-e+La]}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 T(b,r,q)},Ga.rationalSurfaceTransform=function(a,b){for(var c=Da.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]=qa.dot(b,j).slice(0,j.length-1)}return new U(a.degreeU,a.degreeV,a.knotsU.slice(),a.knotsV.slice(),Da.homogenize2d(c,Da.weight2d(a.controlPoints)))},Ga.rationalCurveTransform=function(a,b){for(var c=Da.dehomogenize1d(a.controlPoints),d=0,e=c.length;e>d;){var f=d++,g=c[f];g.push(1),c[f]=qa.dot(b,g).slice(0,g.length-1)}return new T(a.degree,a.knots.slice(),Da.homogenize1d(c,Da.weight1d(a.controlPoints)))},Ga.surfaceKnotRefine=function(a,b,c){var d,e,f,g=[];c?(f=a.controlPoints,d=a.knotsV,e=a.degreeV):(f=qa.transpose(a.controlPoints),d=a.knotsU,e=a.degreeU);for(var h=null,i=0;im;){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]=xa.add(xa.mul(E,j[K+1]),xa.mul(1-E,j[K]))}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 T(d,k,l)};var Ha=b.eval.Tess=function(){};g["verb.eval.Tess"]=Ha,Ha.__name__=["verb","eval","Tess"],Ha.rationalCurveRegularSample=function(a,b,c){return Ha.rationalCurveRegularSampleRange(a,a.knots[0],N.last(a.knots),b,c)},Ha.rationalCurveRegularSampleRange=function(a,b,c,d,e){1>d&&(d=2);for(var f=[],g=(c-b)/(d-1),h=0,i=0;d>i;){var j=i++;h=b+g*j,e?f.push([h].concat(Da.rationalCurvePoint(a,h))):f.push(Da.rationalCurvePoint(a,h))}return f},Ha.rationalCurveAdaptiveSample=function(a,b,c){if(null==c&&(c=!1),null==b&&(b=1e-6),1==a.degree){if(c){for(var d=[],e=0,f=a.controlPoints.length;f>e;){var g=e++;d.push([a.knots[g+1]].concat(Da.dehomogenize(a.controlPoints[g])))}return d}return a.controlPoints.map(Da.dehomogenize)}return Ha.rationalCurveAdaptiveSampleRange(a,a.knots[0],N.last(a.knots),b,c)},Ha.rationalCurveAdaptiveSampleRange=function(a,b,c,d,e){var f=Da.rationalCurvePoint(a,b),g=Da.rationalCurvePoint(a,c),h=.5+.2*Math.random(),i=b+(c-b)*h,j=Da.rationalCurvePoint(a,i),k=xa.sub(f,g),l=xa.sub(f,j);if(xa.dot(k,k)d||!wa.threePointsAreFlat(f,j,g,d)){var m=b+.5*(c-b),n=Ha.rationalCurveAdaptiveSampleRange(a,b,m,d,e),o=Ha.rationalCurveAdaptiveSampleRange(a,m,c,d,e);return n.slice(0,-1).concat(o)}return e?[[b].concat(f),[c].concat(g)]:[f,g]},Ha.rationalSurfaceNaive=function(a,b,c){1>b&&(b=1),1>c&&(c=1);for(var d=(a.degreeU,a.degreeV,a.controlPoints,a.knotsU),e=a.knotsV,f=N.last(d)-d[0],g=N.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=o*h,t=r*i;k.push([s,t]);var u=Da.rationalSurfaceDerivatives(a,s,t,1),v=u[0][0];j.push(v);var w=xa.normalized(xa.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 V(x,j,l,k)},Ha.divideRationalSurfaceAdaptive=function(a,b){null==b&&(b=new Ia),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=N.last(a.knotsU),h=a.knotsU[0],i=N.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=Da.rationalSurfaceDerivatives(a,v,w,1),y=xa.normalized(xa.cross(x[0][1],x[1][0]));r.push(new fa(x[0][0],y,[v,w],-1,xa.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 Ja(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=Ha.north(I,F,H,c,f,m),K=Ha.east(I,F,H,c,f,m),L=Ha.south(I,F,H,c,f,m),M=Ha.west(I,F,H,c,f,m);m[I].neighbors=[L,K,J,M],m[I].divide(b)}return m},Ha.north=function(a,b,c,d,e,f){return 0==b?null:f[a-d]},Ha.south=function(a,b,c,d,e,f){return b==e-1?null:f[a+d]},Ha.east=function(a,b,c,d,e,f){return c==d-1?null:f[a+1]},Ha.west=function(a,b,c,d,e,f){return 0==c?null:f[a-1]},Ha.triangulateAdaptiveRefinementNodeTree=function(a){for(var b=V.empty(),c=0;ca;){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=Da.rationalSurfaceDerivatives(this.srf,a,b,1),e=d[0][0],f=xa.cross(d[0][1],d[1][0]),g=xa.isZero(f);return g||(f=xa.normalized(f)),null!=c?(c.degen=g,c.point=e,c.normal=f,c):new fa(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=Q.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=xa.normSquared(xa.sub(this.corners[0].normal,this.corners[1].normal))>a.normTol||xa.normSquared(xa.sub(this.corners[2].normal,this.corners[3].normal))>a.normTol,this.splitHoriz=xa.normSquared(xa.sub(this.corners[1].normal,this.corners[2].normal))>a.normTol||xa.normSquared(xa.sub(this.corners[3].normal,this.corners[0].normal))>a.normTol,this.splitVert||this.splitHoriz)return!0;var c=this.center();return xa.normSquared(xa.sub(c.normal,this.corners[0].normal))>a.normTol||xa.normSquared(xa.sub(c.normal,this.corners[1].normal))>a.normTol||xa.normSquared(xa.sub(c.normal,this.corners[2].normal))>a.normTol||xa.normSquared(xa.sub(c.normal,this.corners[3].normal))>a.normTol},divide:function(a){null==a&&(a=new Ia),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 Ja(this.srf,d),new Ja(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 Ja(this.srf,f),new Ja(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(La.basePath+b)}catch(e){e instanceof A&&(e=e.val),d=new Worker(La.basePath+b.substring(0,-3)+".min.js")}this._pool.push(d)}};g["verb.exe.WorkerPool"]=La,La.__name__=["verb","exe","WorkerPool"],La.prototype={addWork:function(a,b,c,d){var e=new Ma(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 A&&(f=f.val),a.log(f)}b.processQueue()}}(e,d),e[0].postMessage(c)}},__class__:La};var Ma=function(a,b,c){this.className=a,this.methodName=b,this.args=c,this.id=Ma.uuid++};g["verb.exe._WorkerPool.Work"]=Ma,Ma.__name__=["verb","exe","_WorkerPool","Work"],Ma.prototype={__class__:Ma};var Na=function(){};g["verb.geom.ICurve"]=Na,Na.__name__=["verb","geom","ICurve"],Na.prototype={__class__:Na};var Oa=b.geom.NurbsCurve=function(a){this._data=Aa.isValidNurbsCurveData(a)};g["verb.geom.NurbsCurve"]=Oa,Oa.__name__=["verb","geom","NurbsCurve"],Oa.__interfaces__=[Na],Oa.byKnotsControlPointsWeights=function(a,b,c,d){return new Oa(new T(a,b.slice(),Da.homogenize1d(c,d)))},Oa.byPoints=function(a,b){return null==b&&(b=3),new Oa(Fa.rationalInterpCurve(a,b))},Oa.prototype={degree:function(){return this._data.degree},knots:function(){return this._data.knots.slice(0)},controlPoints:function(){return Da.dehomogenize1d(this._data.controlPoints)},weights:function(){return Da.weight1d(this._data.controlPoints)},asNurbs:function(){return new T(this.degree(),this.knots(),Da.homogenize1d(this.controlPoints(),this.weights()))},clone:function(){return new Oa(this._data)},domain:function(){return new Z(N.first(this._data.knots),N.last(this._data.knots))},transform:function(a){return new Oa(Ga.rationalCurveTransform(this._data,a))},transformAsync:function(a){return Ka.dispatchMethod(Ga,"rationalCurveTransform",[this._data,a]).then(function(a){return new Oa(a)})},point:function(a){return Da.rationalCurvePoint(this._data,a)},pointAsync:function(a){return Ka.dispatchMethod(Da,"rationalCurvePoint",[this._data,a])},tangent:function(a){return Da.rationalCurveTangent(this._data,a)},tangentAsync:function(a){return Ka.dispatchMethod(Da,"rationalCurveTangent",[this._data,a])},derivatives:function(a,b){return null==b&&(b=1),Da.rationalCurveDerivatives(this._data,a,b)},derivativesAsync:function(a,b){return null==b&&(b=1),Ka.dispatchMethod(Da,"rationalCurveDerivatives",[this._data,a,b])},closestPoint:function(a){return ya.rationalCurveClosestPoint(this._data,a)},closestPointAsync:function(a){return Ka.dispatchMethod(ya,"rationalCurveClosestPoint",[this._data,a])},closestParam:function(a){return ya.rationalCurveClosestParam(this._data,a)},closestParamAsync:function(a){return Ka.dispatchMethod(ya,"rationalCurveClosestParam",[this._data,a])},length:function(){return ya.rationalCurveArcLength(this._data)},lengthAsync:function(){return Ka.dispatchMethod(ya,"rationalCurveArcLength",[this._data])},lengthAtParam:function(a){return ya.rationalCurveArcLength(this._data,a)},lengthAtParamAsync:function(){return Ka.dispatchMethod(ya,"rationalCurveArcLength",[this._data])},paramAtLength:function(a,b){return ya.rationalCurveParamAtArcLength(this._data,a,b)},paramAtLengthAsync:function(a,b){return Ka.dispatchMethod(ya,"rationalCurveParamAtArcLength",[this._data,a,b])},divideByEqualArcLength:function(a){return Ba.rationalCurveByEqualArcLength(this._data,a)},divideByEqualArcLengthAsync:function(a){return Ka.dispatchMethod(Ba,"rationalCurveByEqualArcLength",[this._data,a])},divideByArcLength:function(a){return Ba.rationalCurveByArcLength(this._data,a)},divideByArcLengthAsync:function(a){return Ka.dispatchMethod(Ba,"rationalCurveByArcLength",[this._data,a])},split:function(a){return Ba.curveSplit(this._data,a).map(function(a){return new Oa(a)})},splitAsync:function(a){return Ka.dispatchMethod(Ba,"curveSplit",[this._data,a]).then(function(a){return a.map(function(a){return new Oa(a)})})},reverse:function(){return new Oa(Ga.curveReverse(this._data))},reverseAsync:function(){return Ka.dispatchMethod(Ga,"curveReverse",[this._data]).then(function(a){return new Oa(a)})},tessellate:function(a){return Ha.rationalCurveAdaptiveSample(this._data,a,!1)},tessellateAsync:function(a){return Ka.dispatchMethod(Ha,"rationalCurveAdaptiveSample",[this._data,a,!1])},__class__:Oa};var Pa=b.geom.Arc=function(a,b,c,d,e,f){Oa.call(this,Fa.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"]=Pa,Pa.__name__=["verb","geom","Arc"],Pa.__super__=Oa,Pa.prototype=d(Oa.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},hxSerialize:function(a){a.serialize(this._center),a.serialize(this._xaxis),a.serialize(this._yaxis),a.serialize(this._radius),a.serialize(this._minAngle),a.serialize(this._maxAngle)},__class__:Pa});var Qa=b.geom.BezierCurve=function(a,b){Oa.call(this,Fa.rationalBezierCurve(a,b))};g["verb.geom.BezierCurve"]=Qa,Qa.__name__=["verb","geom","BezierCurve"],Qa.__super__=Oa,Qa.prototype=d(Oa.prototype,{__class__:Qa});var Ra=b.geom.Circle=function(a,b,c,d){Pa.call(this,a,b,c,d,0,2*Math.PI)};g["verb.geom.Circle"]=Ra,Ra.__name__=["verb","geom","Circle"],Ra.__super__=Pa,Ra.prototype=d(Pa.prototype,{__class__:Ra});var Sa=function(){};g["verb.geom.ISurface"]=Sa,Sa.__name__=["verb","geom","ISurface"],Sa.prototype={__class__:Sa};var Ta=b.geom.NurbsSurface=function(a){this._data=Aa.isValidNurbsSurfaceData(a)};g["verb.geom.NurbsSurface"]=Ta,Ta.__name__=["verb","geom","NurbsSurface"],Ta.__interfaces__=[Sa],Ta.byKnotsControlPointsWeights=function(a,b,c,d,e,f){return new Ta(new U(a,b,c,d,Da.homogenize2d(e,f)))},Ta.byCorners=function(a,b,c,d){return new Ta(Fa.fourPointSurface(a,b,c,d))},Ta.byLoftingCurves=function(a,b){return new Ta(Fa.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 kb={},lb=c.ArrayBuffer||C;null==lb.prototype.slice&&(lb.prototype.slice=C.sliceImpl);var mb=(c.DataView||D,c.Uint8Array||E._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")()),s.BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:",z.i64tmp=function(a){var b,c=new r(0,0);return b=c}(this),B.__toStr={}.toString,E.BYTES_PER_ELEMENT=1,K.queue=new k,O.memo=new t,Q.TOLERANCE=1e-6,Q.EPSILON=1e-10,Q.VERSION="2.0.0",ya.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]],ya.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]], -Ka.THREADS=1,Ka._init=!1,La.basePath="",Ma.uuid=0,M.main()}("undefined"!=typeof console?console:{log:function(){}},"undefined"!=typeof c?c:exports,"undefined"!=typeof c?c:"undefined"!=typeof b?b:"undefined"!=typeof self?self:this),a}); \ No newline at end of file +/*! verb 2015-10-25 */ +!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__=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);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!=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;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,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;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!=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=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 jb:return(0|a)===a;case lb:return"number"==typeof a;case mb:return"boolean"==typeof a;case String:return"string"==typeof a;case Array:return a instanceof Array&&null==a.__enum__;case kb: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==nb&&null!=a.__name__?!0:b==ob&&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 rb(this,a,null==b?null:b-a),d=new qb(c.byteLength),e=new rb(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.0.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.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=Ma.rationalCurveRegularSample(a,a.controlPoints.length*a.degree,!0),f=0,g=e.length-1;g>f;){var h=f++,i=e[h][0],j=e[h+1][0],k=e[h].slice(1),l=e[h+1].slice(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++;p=Ca.sub(p,Ca.mul(Q.get(o,s)*g[0][s],h[l][o-s]))}for(var t=1,u=l+1;u>t;){var v=t++;p=Ca.sub(p,Ca.mul(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++;w=Ca.add(w,Ca.mul(Q.get(o,z)*g[v][z],h[l-v][o-z]))}p=Ca.sub(p,Ca.mul(Q.get(l,v),w))}h[l].push(Ca.mul(1/g[0][0],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++;k=Ca.sub(k,Ca.mul(Q.get(j,n)*f[n],g[j-n]))}g.push(Ca.mul(1/f[0],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++;t[A]=Ca.add(t[A],Ca.mul(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++;o[x][I]=Ca.add(o[x][I],Ca.mul(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++;s=Ca.add(s,Ca.mul(n[y],h[p+y][q]))}r=Ca.add(r,Ca.mul(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++;y=Ca.sub(y,Ca.mul(Q.get(x,B)*q[0][B],r[u][x-B]))}for(var C=1,D=u+1;D>C;){var E=C++;y=Ca.sub(y,Ca.mul(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++;F=Ca.add(F,Ca.mul(Q.get(x,I)*q[E][I],r[u-E][x-I]))}y=Ca.sub(y,Ca.mul(Q.get(u,E),F))}r[u].push(Ca.mul(1/q[0][0],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.rationalSurfaceRegularSample=function(a,b,c){return Ia.dehomogenize2d(Ia.surfaceRegularSample(a,b,c))},Ia.surfaceRegularSample=function(a,b,c){for(var d=a.degreeU,e=a.degreeV,f=a.controlPoints,g=a.knotsU,h=a.knotsV,i=f[0][0].length,j=((P.last(g)-g[0])/b,(P.last(h)-h[0])/c,Ia.regularlySpacedBasisFunctions(d,g,b)),k=j.item0,l=j.item1,m=Ia.regularlySpacedBasisFunctions(e,h,c),n=m.item0,o=m.item1,p=[],q=b+1,r=c+1,s=0;q>s;){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},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.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++;i=Ca.add(i,Ca.mul(f[r],c[k+r][l]))}l++,j=Ca.add(j,Ca.mul(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++;n[u]=Ca.add(n[u],Ca.mul(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++;m[r][B]=Ca.add(m[r][B],Ca.mul(g[B][E],n[E]))}}}return m},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.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++;j[o]=Ca.add(j[o],Ca.mul(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++;i=Ca.add(i,Ca.mul(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++;x=Ca.add(x,Ca.mul(s[K],h[v+K][H][D]))}y=Ca.add(y,Ca.mul(t[G],x))}w=Ca.add(w,Ca.mul(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=Ma.rationalSurfaceAdaptive(a),e=Ma.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.rationalBezierCurve=function(a,b){for(var c=a.length-1,d=[],e=0,f=c+1;f>e;){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){var d,e,f,g=[];c?(f=a.controlPoints,d=a.knotsV,e=a.degreeV):(f=ta.transpose(a.controlPoints),d=a.knotsU,e=a.degreeU);for(var h=null,i=0;im;){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(E,j[K+1]),Ca.mul(1-E,j[K]))}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=b.eval.Tess=function(){};g["verb.eval.Tess"]=Ma,Ma.__name__=["verb","eval","Tess"],Ma.rationalCurveRegularSample=function(a,b,c){return Ma.rationalCurveRegularSampleRange(a,a.knots[0],P.last(a.knots),b,c)},Ma.rationalCurveRegularSampleRange=function(a,b,c,d,e){1>d&&(d=2);for(var f=[],g=(c-b)/(d-1),h=0,i=0;d>i;){var j=i++;h=b+g*j,e?f.push([h].concat(Ia.rationalCurvePoint(a,h))):f.push(Ia.rationalCurvePoint(a,h))}return f},Ma.rationalCurveAdaptiveSample=function(a,b,c){if(null==c&&(c=!1),null==b&&(b=1e-6),1==a.degree){if(c){for(var d=[],e=0,f=a.controlPoints.length;f>e;){var g=e++;d.push([a.knots[g+1]].concat(Ia.dehomogenize(a.controlPoints[g])))}return d}return a.controlPoints.map(Ia.dehomogenize)}return Ma.rationalCurveAdaptiveSampleRange(a,a.knots[0],P.last(a.knots),b,c)},Ma.rationalCurveAdaptiveSampleRange=function(a,b,c,d,e){var f=Ia.rationalCurvePoint(a,b),g=Ia.rationalCurvePoint(a,c),h=.5+.2*Math.random(),i=b+(c-b)*h,j=Ia.rationalCurvePoint(a,i),k=Ca.sub(f,g),l=Ca.sub(f,j);if(Ca.dot(k,k)d||!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){1>b&&(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=o*h,t=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)},Ma.divideRationalSurfaceAdaptive=function(a,b){null==b&&(b=new Na),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 Oa(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=Ma.north(I,F,H,c,f,m),K=Ma.east(I,F,H,c,f,m),L=Ma.south(I,F,H,c,f,m),M=Ma.west(I,F,H,c,f,m);m[I].neighbors=[L,K,J,M],m[I].divide(b)}return m},Ma.north=function(a,b,c,d,e,f){return 0==b?null:f[a-d]},Ma.south=function(a,b,c,d,e,f){return b==e-1?null:f[a+d]},Ma.east=function(a,b,c,d,e,f){return c==d-1?null:f[a+1]},Ma.west=function(a,b,c,d,e,f){return 0==c?null:f[a-1]},Ma.triangulateAdaptiveRefinementNodeTree=function(a){for(var b=Y.empty(),c=0;ca;){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 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;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(Qa.basePath+b)}catch(e){e instanceof C&&(e=e.val),d=new Worker(Qa.basePath+b.substring(0,-3)+".min.js")}this._pool.push(d)}};g["verb.exe.WorkerPool"]=Qa,Qa.__name__=["verb","exe","WorkerPool"],Qa.prototype={addWork:function(a,b,c,d){var e=new Ra(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__: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;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 pb={},qb=c.ArrayBuffer||E;null==qb.prototype.slice&&(qb.prototype.slice=E.sliceImpl);var rb=(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]],Pa.THREADS=1,Pa._init=!1,Qa.basePath="",Ra.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}); \ No newline at end of file diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index c2e517b2..fa446e6a 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -3398,6 +3398,47 @@ 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.norm = function(a) { var norm2 = verb_core_Vec.normSquared(a); if(norm2 != 0.0) return Math.sqrt(norm2); else return norm2; @@ -4005,21 +4046,21 @@ 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.subMutate(v1,verb_core_Vec.mul(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.subMutate(v1,verb_core_Vec.mul(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.addMutate(v2,verb_core_Vec.mul(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.subMutate(v1,verb_core_Vec.mul(verb_core_Binomial.get(k,i),v2)); } SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],v1)); } @@ -4046,7 +4087,7 @@ 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)); } @@ -4092,7 +4133,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; @@ -4106,7 +4147,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]); } } } @@ -4143,12 +4184,280 @@ 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]); + } + verb_core_Vec.addMulMutate(position,v_basis_vals[l],temp); + } + return position; +}; +verb_eval_Eval.curveRegularSamplePoints = function(crv,divs) { + var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); + var t = 1.0 / divs; + var temp = t * t; + var f = derivs[0]; + var fd = verb_core_Vec.mul(t,derivs[1]); + var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); + var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); + var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); + var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); + var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); + var pts = []; + var _g1 = 0; + var _g = divs + 1; + while(_g1 < _g) { + var i = _g1++; + pts.push(verb_eval_Eval.dehomogenize(f)); + verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); + verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); + verb_core_Vec.addAllMutate([fdd,fddd]); + verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); + } + return pts; +}; +verb_eval_Eval.curveRegularSamplePoints2 = function(crv,divs) { + var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); + var t = 1.0 / divs; + var temp = t * t; + var f = derivs[0]; + var fd = verb_core_Vec.mul(t,derivs[1]); + var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); + var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); + var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); + var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); + var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); + var pts = []; + var _g1 = 0; + var _g = divs + 1; + while(_g1 < _g) { + var i = _g1++; + pts.push(verb_eval_Eval.dehomogenize(f)); + verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); + verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); + verb_core_Vec.addAllMutate([fdd,fddd]); + verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); + } + return pts; +}; +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); + } + SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],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.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Eval.surfaceRegularSamplePoints(surface,divsU,divsV)); +}; +verb_eval_Eval.surfaceRegularSamplePoints = 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_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]); } - position = verb_core_Vec.add(position,verb_core_Vec.mul(v_basis_vals[l],temp)); + 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); @@ -4174,7 +4483,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; @@ -4201,7 +4510,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; }; @@ -4247,11 +4556,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; }; @@ -4261,7 +4570,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); @@ -4272,8 +4581,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) { diff --git a/src/support/header.js b/src/support/header.js index 110feac4..0acfa6d1 100644 --- a/src/support/header.js +++ b/src/support/header.js @@ -3,7 +3,6 @@ (function(f){ if(typeof exports==="object"&&typeof module!=="undefined"){ - console.log("OK"); module.exports=f() } else if(typeof define==="function"&&define.amd){ define([],f) diff --git a/src/verb/core/Vec.hx b/src/verb/core/Vec.hx index 64740454..02987170 100644 --- a/src/verb/core/Vec.hx +++ b/src/verb/core/Vec.hx @@ -148,6 +148,32 @@ class Vec { return a.fold(function(x,a){ return add(a,x); }, rep(f, 0.0)); } + 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 norm(a : Iterable ) : Float { var norm2 = normSquared(a); return norm2 != 0.0 ? Math.sqrt( norm2 ) : norm2; diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 692712e4..7bd44c32 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -5,6 +5,8 @@ import verb.core.Vec; import verb.core.Binomial; import verb.core.Constants; +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. // @@ -80,20 +82,19 @@ class Eval { 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] ) ); + Vec.subMutate( v, Vec.mul( 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] ) ); + Vec.subMutate( v, Vec.mul( Binomial.get(k, i) * wders[i][0], SKL[k-i][l] ) ); 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] ) ); + Vec.addMutate( v2, Vec.mul( Binomial.get(l, j) * wders[i][j], SKL[k-i][l-j] ) ); } - v = Vec.sub( v, Vec.mul( Binomial.get(k, i), v2) ); - + Vec.subMutate( v, Vec.mul( Binomial.get(k, i), v2) ); } SKL[k].push( Vec.mul(1 / wders[0][0], v )); //demogenize @@ -149,7 +150,7 @@ class Eval { 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] ) ); + Vec.subMulMutate( v, Binomial.get(k, i) * wders[i], CK[k-i] ); } CK.push( Vec.mul(1/wders[0], v )); //demogenize } @@ -198,7 +199,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** @@ -248,8 +249,7 @@ class Eval { 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]) ); + Vec.addMulMutate( temp[s], uders[k][r], controlPoints[knotSpan_index_u-degreeU+r][knotSpan_index_v-degreeV+s]); } } @@ -260,7 +260,7 @@ class Eval { 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] ) ); + Vec.addMulMutate( SKL[k][l], vders[l][s], temp[s] ); } } } @@ -335,16 +335,385 @@ class Eval { //sample u isoline for (k in 0...degreeU + 1) { - temp = Vec.add( temp, Vec.mul( u_basis_vals[k], controlPoints[uind+k][vind]) ); + 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; + } + + public static function curveRegularSamplePoints( crv : NurbsCurveData, divs : Int ){ + + // initialize the derivative set + + var derivs = curveDerivatives( crv, crv.knots[0], crv.degree ); + + // expand the taylor series + + var t = 1.0 / divs; + var temp = t * t; + + var f = derivs[0]; + var fd = Vec.mul(t, derivs[1] ); + var fdd_per2 = Vec.mul( temp * 0.5, derivs[2] ); + var fddd_per2 = Vec.mul( temp * t * 0.5, derivs[3] ); + + var fdd = Vec.add( fdd_per2, fdd_per2 ); + var fddd = Vec.add( fddd_per2, fddd_per2 ); + var fddd_per6 = Vec.mul( 1/3, fddd_per2 ); + + // evaluate the points + var pts = []; + + for (i in 0...divs+1){ + + pts.push(dehomogenize(f)); + + Vec.addAllMutate([ f, fd, fdd_per2, fddd_per6 ]); + Vec.addAllMutate([ fd, fdd, fddd_per2 ]); + Vec.addAllMutate([ fdd, fddd ]); + Vec.addAllMutate([ fdd_per2, fddd_per2 ]); + } + + return pts; + + } + + public static function curveRegularSamplePoints2( crv : NurbsCurveData, divs : Int ){ + + // initialize the derivative set + + var derivs = curveDerivatives( crv, crv.knots[0], crv.degree ); + + // expand the taylor series + + var t = 1.0 / divs; + var temp = t * t; + + var f = derivs[0]; + var fd = Vec.mul(t, derivs[1] ); + var fdd_per2 = Vec.mul( temp * 0.5, derivs[2] ); + var fddd_per2 = Vec.mul( temp * t * 0.5, derivs[3] ); + + var fdd = Vec.add( fdd_per2, fdd_per2 ); + var fddd = Vec.add( fddd_per2, fddd_per2 ); + var fddd_per6 = Vec.mul( 1/3, fddd_per2 ); + + // evaluate the points + var pts = []; + + for (i in 0...divs+1){ + + pts.push(dehomogenize(f)); + + Vec.addAllMutate([ f, fd, fdd_per2, fddd_per6 ]); + Vec.addAllMutate([ fd, fdd, fddd_per2 ]); + Vec.addAllMutate([ fdd, fddd ]); + Vec.addAllMutate([ fdd_per2, fddd_per2 ]); + } + + return pts; + + } + + // 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 ); + + } + + SKL[k].push( Vec.mul(1 / wders[0][0], 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; + } + + // 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 rationalSurfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + return dehomogenize2d( surfaceRegularSamplePoints( 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 surfaceRegularSamplePoints( 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 = regularlySpacedBasisFunctions( degreeU, knotsU, divsU ) + , knotSpansU = knotSpansBasesU.item0 + , basesU = knotSpansBasesU.item1 + , knotSpansBasesV = 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( surfacePointGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim ) ); + } + } + + return pts; + } + + private 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 ); + } + + private 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 +730,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); } @@ -399,7 +767,7 @@ class Eval { 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 ] ) ); + Vec.addMulMutate( CK[k], nders[k][j], controlPoints[ knotSpan_index - degree + j ] ); } } return CK; @@ -467,9 +835,7 @@ class Eval { 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 ] ) ); + Vec.addMulMutate( position, basis_values[j], controlPoints[ knotSpan_index - degree + j ] ); } return position; @@ -554,22 +920,21 @@ class Eval { 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] )); + 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 ) ); + 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** // @@ -590,7 +955,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,7 +970,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 derivativeBasisFunctionsGivenNI( knotSpan_index : Int, u : Float, p : Int, + public static function derivativeBasisFunctionsGivenNI( knotIndex : Int, u : Float, p : Int, n : Int, knots : KnotArray ) : Array> { var ndu = Vec.zeros2d( p+1, p+1 ) @@ -617,8 +982,8 @@ 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; + left[j] = u - knots[knotIndex+1-j]; + right[j] = knots[knotIndex+j] - u; saved = 0.0; for (r in 0...j){ @@ -717,7 +1082,7 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctions( u : Float, degree : Int, knots : KnotArray) + 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 ); @@ -741,7 +1106,7 @@ class Eval { public static function basisFunctionsGivenKnotSpanIndex( knotSpan_index : Int, u : Float, degree : Int, - knots : KnotArray ) + knots : KnotArray ) : Array { var basisFunctions = Vec.zeros1d( degree + 1 ); var left = Vec.zeros1d( degree + 1 ); diff --git a/test/testCore.js b/test/testCore.js index fc2538cc..16ace2e5 100755 --- a/test/testCore.js +++ b/test/testCore.js @@ -5,6 +5,7 @@ var fs = require('fs'); var f = fs.readFileSync(process.cwd() + '/build/js/verb.js', 'utf8'); console.log( f.slice(-300, -1) ); + // necessary for multi-threading verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/"; diff --git a/test/testEval.js b/test/testEval.js index fb9f3202..8298d949 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,6 +20,8 @@ function last(a){ return a[a.length-1]; } + + describe("verb.eval.Eval.knotSpanGivenN",function(){ it('returns correct result', function(){ @@ -3857,3 +3859,81 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ }); + +describe("verb.eval.Eval.surfaceRegularSamplePoints",function(){ + + function getComplexSurface(){ + + var degree = 3 + , knots = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1] + , pts = [ [ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ], + [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ], + [ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ], + [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ], + [ [0, -50, 12], [10, -50, 0], [20, -50, 0], [30, -50, 0] , [50, -50, 0], [50, -50, -15] ], ] + , wts = [ [ 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1] ]; + + pts = verb.eval.Eval.homogenize2d(pts, wts); + + var srfObj = { + degreeU : degree, + degreeV : degree, + knotsU : knots, + knotsV : knots, + controlPoints : pts + }; + + return srfObj; + } + + it('returns correct result for simple surface', function(){ + + t0 = process.hrtime(); + + var p = verb.eval.Eval.surfaceRegularSamplePoints( getComplexSurface(), 10, 10 ); + + t1 = process.hrtime(t0); + + console.info("Execution time (hr): %ds %dms", t1[0], t1[1]/1000000); + + console.log( JSON.stringify( p[0].slice(0,5) )) + + + + }); +}); + +describe("verb.eval.Eval.curveRegularSample",function(){ + + it('returns correct result for simple surface', function(){ + + var crv = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1], [2,1,1], [3,1,0]] ); + + var divs = 10; + var p = verb.eval.Eval.curveRegularSamplePoints( crv, divs ); + + console.log(p); + + console.log("++++++++++++"); + + var sp = 1.0 / divs; + var pts = []; + + for (var i = 0; i < divs+1; i++){ + + pts.push( verb.eval.Eval.rationalCurvePoint(crv, i * sp) ) + + } + + console.log(pts); + + + }); +}); + From eaf39946c64ee413d888cb291639a750c4a8133a Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Tue, 27 Oct 2015 21:09:38 -0400 Subject: [PATCH 02/25] Proper forward differencing implementation for curves --- Gruntfile.js | 3 +- benchmark/regularCurveSampling.js | 13 ++-- build/js/verb.js | 104 +++++++++++++++++---------- build/js/verbHaxe.js | 104 +++++++++++++++++---------- src/verb/eval/Divide.hx | 2 +- src/verb/eval/Eval.hx | 110 ++++++++++++++++------------ src/verb/eval/Modify.hx | 4 +- test/testEval.js | 114 ++++++++++++++++-------------- 8 files changed, 268 insertions(+), 186 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index c4f8a069..0c847989 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 index e24c75d2..df74e19f 100644 --- a/benchmark/regularCurveSampling.js +++ b/benchmark/regularCurveSampling.js @@ -6,14 +6,17 @@ 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: { - 'curveRegularSamplePoints (100)': function() { - var p = verb.eval.Eval.curveRegularSamplePoints( crv, 100 ); + 'rationalBezierCurveRegularSamplePoints (6560)': function() { + var p = verb.eval.Eval.rationalBezierCurveRegularSamplePoints( crv, 6560 ); }, - 'direct evaluation (100)': function() { + 'rationalCurveRegularSamplePoints (6560)': function() { + var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, 6560 ); + }, + 'direct evaluation (6560)': function() { var p = []; - var sp = 1 / 100; + var sp = 1 / 6560; - for (var i = 0; i < 101; i++){ + for (var i = 0; i < 6561; i++){ p.push( verb.eval.Eval.rationalCurvePoint( crv, i*sp ) ) } } diff --git a/build/js/verb.js b/build/js/verb.js index 5bd2a054..55e47c0b 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -4259,51 +4259,79 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { } return position; }; -verb_eval_Eval.curveRegularSamplePoints = function(crv,divs) { - var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); - var t = 1.0 / divs; - var temp = t * t; - var f = derivs[0]; - var fd = verb_core_Vec.mul(t,derivs[1]); - var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); - var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); - var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); - var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); - var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); +verb_eval_Eval.rationalBezierCurveRegularSamplePoints = function(crv,divs) { var pts = []; - var _g1 = 0; - var _g = divs + 1; - while(_g1 < _g) { - var i = _g1++; - pts.push(verb_eval_Eval.dehomogenize(f)); - verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); - verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); - verb_core_Vec.addAllMutate([fdd,fddd]); - verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); - } + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(crv,divs,pts); return pts; }; -verb_eval_Eval.curveRegularSamplePoints2 = function(crv,divs) { - var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); +verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs,pts) { var t = 1.0 / divs; - var temp = t * t; - var f = derivs[0]; - var fd = verb_core_Vec.mul(t,derivs[1]); - var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); - var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); - var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); - var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); - var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); + var its = []; + var ts = [its]; + var u = crv.knots[0]; + var degree1 = crv.degree + 1; + var _g = 0; + while(_g < degree1) { + var i = _g++; + its.push(verb_eval_Eval.curvePoint(crv,u)); + u += t; + } + var prev; + var _g1 = 1; + while(_g1 < degree1) { + var i1 = _g1++; + its = []; + ts.push(its); + prev = ts[i1 - 1]; + var _g2 = 1; + var _g11 = prev.length; + while(_g2 < _g11) { + var j = _g2++; + 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 _g21 = 0; + var _g14 = divs + 1 - degree1; + while(_g21 < _g14) { + var i2 = _g21++; + var _g41 = 0; + var _g31 = front.length - 1; + while(_g41 < _g31) { + var j1 = _g41++; + k = front.length - 2 - j1; + verb_core_Vec.addMutate(front[k],front[k + 1]); + } + pts.push(verb_eval_Eval.dehomogenize(front[0])); + } + return pts; +}; +verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { + var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); var pts = []; var _g1 = 0; - var _g = divs + 1; + var _g = beziers.length; while(_g1 < _g) { var i = _g1++; - pts.push(verb_eval_Eval.dehomogenize(f)); - verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); - verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); - verb_core_Vec.addAllMutate([fdd,fddd]); - verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],divs,pts); + if(i == beziers.length - 1) continue; + pts.pop(); } return pts; }; @@ -6347,7 +6375,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]; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index fa446e6a..0836b5b8 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -4190,51 +4190,79 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { } return position; }; -verb_eval_Eval.curveRegularSamplePoints = function(crv,divs) { - var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); - var t = 1.0 / divs; - var temp = t * t; - var f = derivs[0]; - var fd = verb_core_Vec.mul(t,derivs[1]); - var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); - var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); - var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); - var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); - var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); +verb_eval_Eval.rationalBezierCurveRegularSamplePoints = function(crv,divs) { var pts = []; - var _g1 = 0; - var _g = divs + 1; - while(_g1 < _g) { - var i = _g1++; - pts.push(verb_eval_Eval.dehomogenize(f)); - verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); - verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); - verb_core_Vec.addAllMutate([fdd,fddd]); - verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); - } + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(crv,divs,pts); return pts; }; -verb_eval_Eval.curveRegularSamplePoints2 = function(crv,divs) { - var derivs = verb_eval_Eval.curveDerivatives(crv,crv.knots[0],crv.degree); +verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs,pts) { var t = 1.0 / divs; - var temp = t * t; - var f = derivs[0]; - var fd = verb_core_Vec.mul(t,derivs[1]); - var fdd_per2 = verb_core_Vec.mul(temp * 0.5,derivs[2]); - var fddd_per2 = verb_core_Vec.mul(temp * t * 0.5,derivs[3]); - var fdd = verb_core_Vec.add(fdd_per2,fdd_per2); - var fddd = verb_core_Vec.add(fddd_per2,fddd_per2); - var fddd_per6 = verb_core_Vec.mul(0.333333333333333315,fddd_per2); + var its = []; + var ts = [its]; + var u = crv.knots[0]; + var degree1 = crv.degree + 1; + var _g = 0; + while(_g < degree1) { + var i = _g++; + its.push(verb_eval_Eval.curvePoint(crv,u)); + u += t; + } + var prev; + var _g1 = 1; + while(_g1 < degree1) { + var i1 = _g1++; + its = []; + ts.push(its); + prev = ts[i1 - 1]; + var _g2 = 1; + var _g11 = prev.length; + while(_g2 < _g11) { + var j = _g2++; + 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 _g21 = 0; + var _g14 = divs + 1 - degree1; + while(_g21 < _g14) { + var i2 = _g21++; + var _g41 = 0; + var _g31 = front.length - 1; + while(_g41 < _g31) { + var j1 = _g41++; + k = front.length - 2 - j1; + verb_core_Vec.addMutate(front[k],front[k + 1]); + } + pts.push(verb_eval_Eval.dehomogenize(front[0])); + } + return pts; +}; +verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { + var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); var pts = []; var _g1 = 0; - var _g = divs + 1; + var _g = beziers.length; while(_g1 < _g) { var i = _g1++; - pts.push(verb_eval_Eval.dehomogenize(f)); - verb_core_Vec.addAllMutate([f,fd,fdd_per2,fddd_per6]); - verb_core_Vec.addAllMutate([fd,fdd,fddd_per2]); - verb_core_Vec.addAllMutate([fdd,fddd]); - verb_core_Vec.addAllMutate([fdd_per2,fddd_per2]); + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],divs,pts); + if(i == beziers.length - 1) continue; + pts.pop(); } return pts; }; @@ -6278,7 +6306,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]; diff --git a/src/verb/eval/Divide.hx b/src/verb/eval/Divide.hx index 8031465d..73186774 100644 --- a/src/verb/eval/Divide.hx +++ b/src/verb/eval/Divide.hx @@ -68,7 +68,7 @@ class Divide { //v dir return [ new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots0, newpts0 ), - new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots1, newpts1 ) ]; + new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots1, newpts1 ) ]; } //Split a NURBS curve into two parts at a given parameter diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 7bd44c32..20d182e0 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -289,7 +289,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** @@ -345,78 +345,94 @@ class Eval { return position; } - public static function curveRegularSamplePoints( crv : NurbsCurveData, divs : Int ){ + // Compute a regularly spaced sequence of points on a non-uniform, rational, bezier 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 representing the curve + //* number of divisions + // + //**returns** + // + //* an array of (divs+1) points - // initialize the derivative set + public static function rationalBezierCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { + var pts = []; + rationalBezierCurveRegularSamplePointsMutate( crv, divs, pts ); + return pts; + } - var derivs = curveDerivatives( crv, crv.knots[0], crv.degree ); + private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, divs : Int, pts : Array ) { - // expand the taylor series + // get the step size - var t = 1.0 / divs; - var temp = t * t; + var t = ( crv.knots.last() - crv.knots[0] ) / divs; - var f = derivs[0]; - var fd = Vec.mul(t, derivs[1] ); - var fdd_per2 = Vec.mul( temp * 0.5, derivs[2] ); - var fddd_per2 = Vec.mul( temp * t * 0.5, derivs[3] ); + // initialize forward differencing - var fdd = Vec.add( fdd_per2, fdd_per2 ); - var fddd = Vec.add( fddd_per2, fddd_per2 ); - var fddd_per6 = Vec.mul( 1/3, fddd_per2 ); + var its = [], ts = [its], u = crv.knots[0], degree1 = crv.degree+1; - // evaluate the points - var pts = []; + for (i in 0...degree1){ + its.push( curvePoint( crv, u ) ); + u += t; + } - for (i in 0...divs+1){ + // compute the differences - pts.push(dehomogenize(f)); + var prev; - Vec.addAllMutate([ f, fd, fdd_per2, fddd_per6 ]); - Vec.addAllMutate([ fd, fdd, fddd_per2 ]); - Vec.addAllMutate([ fdd, fddd ]); - Vec.addAllMutate([ fdd_per2, fddd_per2 ]); + 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] ) ); + } } - return pts; - - } + // evaluate the points - public static function curveRegularSamplePoints2( crv : NurbsCurveData, divs : Int ){ + for (pt in ts[0]){ + pts.push( dehomogenize(pt) ); + } - // initialize the derivative set + var front = [ for (r in ts) r.last() ], k; - var derivs = curveDerivatives( crv, crv.knots[0], crv.degree ); + for (i in 0...divs+1-degree1){ - // expand the taylor series + // Rright = R + Rdown - var t = 1.0 / divs; - var temp = t * t; + // compute the new forward difference front - var f = derivs[0]; - var fd = Vec.mul(t, derivs[1] ); - var fdd_per2 = Vec.mul( temp * 0.5, derivs[2] ); - var fddd_per2 = Vec.mul( temp * t * 0.5, derivs[3] ); + for (j in 0...front.length-1){ + k = front.length - 2 - j; // invert + Vec.addMutate(front[k], front[k+1]); + } - var fdd = Vec.add( fdd_per2, fdd_per2 ); - var fddd = Vec.add( fddd_per2, fddd_per2 ); - var fddd_per6 = Vec.mul( 1/3, fddd_per2 ); + // add the new pt + pts.push(dehomogenize( front[0] )); + } - // evaluate the points - var pts = []; + return pts; + } - for (i in 0...divs+1){ + public static function rationalCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { - pts.push(dehomogenize(f)); + var range = crv.knots.last() - crv.knots.length; + var beziers = Modify.decomposeCurveIntoBeziers( crv ); + var pts = []; - Vec.addAllMutate([ f, fd, fdd_per2, fddd_per6 ]); - Vec.addAllMutate([ fd, fdd, fddd_per2 ]); - Vec.addAllMutate([ fdd, fddd ]); - Vec.addAllMutate([ fdd_per2, fddd_per2 ]); + for (i in 0...beziers.length){ + rationalBezierCurveRegularSamplePointsMutate( beziers[i], divs, pts ); + if (i == beziers.length-1) + continue; + pts.pop(); } return pts; - } // Compute a regularly spaced grid of derivatives on a non-uniform, rational, B spline surface. Generally, this algorithm diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index cd1ab1a5..8b6169b3 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -664,8 +664,8 @@ class Modify { 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] ) ); } diff --git a/test/testEval.js b/test/testEval.js index 8298d949..e0a11bbd 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,8 +20,6 @@ function last(a){ return a[a.length-1]; } - - describe("verb.eval.Eval.knotSpanGivenN",function(){ it('returns correct result', function(){ @@ -3862,78 +3860,86 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ describe("verb.eval.Eval.surfaceRegularSamplePoints",function(){ - function getComplexSurface(){ + 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] ]; + 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); + pts = verb.eval.Eval.homogenize2d(pts, wts); - var srfObj = { - degreeU : degree, - degreeV : degree, - knotsU : knots, - knotsV : knots, - controlPoints : pts - }; + var srfObj = { + degreeU : degree, + degreeV : degree, + knotsU : knots, + knotsV : knots, + controlPoints : pts + }; - return srfObj; - } + return srfObj; + } - it('returns correct result for simple surface', function(){ + var complexSurface = getComplexSurface(); - t0 = process.hrtime(); + it('returns correct result for complex surface', function(){ - var p = verb.eval.Eval.surfaceRegularSamplePoints( getComplexSurface(), 10, 10 ); + var p = verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 10, 10 ); - t1 = process.hrtime(t0); + var ar = []; + var sp = 1 / 10; - console.info("Execution time (hr): %ds %dms", t1[0], t1[1]/1000000); + var i, j; - console.log( JSON.stringify( p[0].slice(0,5) )) + 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.Eval.curveRegularSample",function(){ - - it('returns correct result for simple surface', function(){ - +describe("verb.eval.Eval.rationalBezierCurveRegularSample",function(){ + it('returns correct result for basic bezier curve', function(){ var crv = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1], [2,1,1], [3,1,0]] ); - var divs = 10; - var p = verb.eval.Eval.curveRegularSamplePoints( crv, divs ); - - console.log(p); - - console.log("++++++++++++"); - - var sp = 1.0 / divs; - var pts = []; - - for (var i = 0; i < divs+1; i++){ - - pts.push( verb.eval.Eval.rationalCurvePoint(crv, i * sp) ) + var divs = 200; + var p = verb.eval.Eval.rationalBezierCurveRegularSamplePoints( crv, divs ); - } + var p2 = []; + var sp = 1 / divs; - console.log(pts); + 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] ); + } }); -}); - +}); \ No newline at end of file From 74226a5669e06f1d69f50fbc8f1402cb64487e32 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Wed, 28 Oct 2015 15:31:02 -0400 Subject: [PATCH 03/25] Using arrow syntax in tests, further work on rationalCurveSampleRegularPoints --- Gruntfile.js | 4 +- benchmark/regularCurveSampling.js | 3 - build/js/verb.js | 67 +++- build/js/verbHaxe.js | 67 +++- src/verb/eval/Eval.hx | 51 ++- src/verb/eval/Modify.hx | 2 +- test/testCore.js | 160 ++++---- test/testEval.js | 603 ++++++++++++++++-------------- test/testGeom.js | 308 +++++++-------- 9 files changed, 701 insertions(+), 564 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 0c847989..f00c8f5b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -43,8 +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/testEval.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 index df74e19f..075c154e 100644 --- a/benchmark/regularCurveSampling.js +++ b/benchmark/regularCurveSampling.js @@ -6,9 +6,6 @@ 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: { - 'rationalBezierCurveRegularSamplePoints (6560)': function() { - var p = verb.eval.Eval.rationalBezierCurveRegularSamplePoints( crv, 6560 ); - }, 'rationalCurveRegularSamplePoints (6560)': function() { var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, 6560 ); }, diff --git a/build/js/verb.js b/build/js/verb.js index 55e47c0b..36a8cbcf 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -324,6 +324,12 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; +var haxe_Log = function() { }; +$hxClasses["haxe.Log"] = haxe_Log; +haxe_Log.__name__ = ["haxe","Log"]; +haxe_Log.trace = function(v,infos) { + js_Boot.__trace(v,infos); +}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -1058,6 +1064,25 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; +js_Boot.__unhtml = function(s) { + return s.split("&").join("&").split("<").join("<").split(">").join(">"); +}; +js_Boot.__trace = function(v,i) { + var msg; + if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; + msg += js_Boot.__string_rec(v,""); + if(i != null && i.customParams != null) { + var _g = 0; + var _g1 = i.customParams; + while(_g < _g1.length) { + var v1 = _g1[_g]; + ++_g; + msg += "," + js_Boot.__string_rec(v1,""); + } + } + var d; + if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); +}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1933,7 +1958,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"); + haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -4259,13 +4284,36 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { } return position; }; +verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var brange; + var fraction; + haxe_Log.trace(beziers.map(function(x) { + return x.knots; + }),{ fileName : "Eval.hx", lineNumber : 369, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); + var _g1 = 0; + var _g = beziers.length; + while(_g1 < _g) { + var i = _g1++; + brange = verb_core_ArrayExtensions.last(beziers[i].knots) - beziers[i].knots[0]; + haxe_Log.trace(brange,{ fileName : "Eval.hx", lineNumber : 376, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints", customParams : [range]}); + fraction = Math.ceil(brange / range * divs); + haxe_Log.trace(fraction,{ fileName : "Eval.hx", lineNumber : 378, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],fraction,pts); + if(i == beziers.length - 1) continue; + pts.pop(); + } + return pts; +}; verb_eval_Eval.rationalBezierCurveRegularSamplePoints = function(crv,divs) { var pts = []; verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(crv,divs,pts); return pts; }; verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs,pts) { - var t = 1.0 / divs; + var t = (verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]) / divs; var its = []; var ts = [its]; var u = crv.knots[0]; @@ -4322,19 +4370,6 @@ verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs, } return pts; }; -verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { - var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); - var pts = []; - var _g1 = 0; - var _g = beziers.length; - while(_g1 < _g) { - var i = _g1++; - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],divs,pts); - if(i == beziers.length - 1) continue; - pts.pop(); - } - return pts; -}; verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); var allratders = []; @@ -6902,7 +6937,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - console.log(error); + haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 82, className : "verb.exe.WorkerPool", methodName : "processQueue"}); } _g.processQueue(); }; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 0836b5b8..1d2dc1ed 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -255,6 +255,12 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; +var haxe_Log = function() { }; +$hxClasses["haxe.Log"] = haxe_Log; +haxe_Log.__name__ = ["haxe","Log"]; +haxe_Log.trace = function(v,infos) { + js_Boot.__trace(v,infos); +}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -989,6 +995,25 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; +js_Boot.__unhtml = function(s) { + return s.split("&").join("&").split("<").join("<").split(">").join(">"); +}; +js_Boot.__trace = function(v,i) { + var msg; + if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; + msg += js_Boot.__string_rec(v,""); + if(i != null && i.customParams != null) { + var _g = 0; + var _g1 = i.customParams; + while(_g < _g1.length) { + var v1 = _g1[_g]; + ++_g; + msg += "," + js_Boot.__string_rec(v1,""); + } + } + var d; + if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); +}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1864,7 +1889,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"); + haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -4190,13 +4215,36 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { } return position; }; +verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + var pts = []; + var brange; + var fraction; + haxe_Log.trace(beziers.map(function(x) { + return x.knots; + }),{ fileName : "Eval.hx", lineNumber : 369, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); + var _g1 = 0; + var _g = beziers.length; + while(_g1 < _g) { + var i = _g1++; + brange = verb_core_ArrayExtensions.last(beziers[i].knots) - beziers[i].knots[0]; + haxe_Log.trace(brange,{ fileName : "Eval.hx", lineNumber : 376, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints", customParams : [range]}); + fraction = Math.ceil(brange / range * divs); + haxe_Log.trace(fraction,{ fileName : "Eval.hx", lineNumber : 378, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],fraction,pts); + if(i == beziers.length - 1) continue; + pts.pop(); + } + return pts; +}; verb_eval_Eval.rationalBezierCurveRegularSamplePoints = function(crv,divs) { var pts = []; verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(crv,divs,pts); return pts; }; verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs,pts) { - var t = 1.0 / divs; + var t = (verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]) / divs; var its = []; var ts = [its]; var u = crv.knots[0]; @@ -4253,19 +4301,6 @@ verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs, } return pts; }; -verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { - var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); - var pts = []; - var _g1 = 0; - var _g = beziers.length; - while(_g1 < _g) { - var i = _g1++; - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],divs,pts); - if(i == beziers.length - 1) continue; - pts.pop(); - } - return pts; -}; verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); var allratders = []; @@ -6833,7 +6868,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - console.log(error); + haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 82, className : "verb.exe.WorkerPool", methodName : "processQueue"}); } _g.processQueue(); }; diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 20d182e0..e2b59ba8 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -345,7 +345,7 @@ class Eval { return position; } - // Compute a regularly spaced sequence of points on a non-uniform, rational, bezier curve. Generally, this algorithm + // 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) @@ -359,10 +359,41 @@ class Eval { // //* an array of (divs+1) points - public static function rationalBezierCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { + public static function rationalCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { + + var range = crv.knots.last() - crv.knots[0]; + var beziers = Modify.decomposeCurveIntoBeziers( crv ); + var pts = []; + var brange, fraction; + + trace(beziers.map(function(x){return x.knots;})); + + for (i in 0...beziers.length){ + + // get the fraction of samples that should be performed in this bezier + brange = beziers[i].knots.last() - beziers[i].knots[0]; + + trace(brange, range); + fraction = Math.ceil( ( brange / range ) * divs ); + trace( fraction ); + + rationalBezierCurveRegularSamplePointsMutate( beziers[i], fraction, pts ); + + if (i == beziers.length-1) + continue; + + pts.pop(); // remove the last point in the sequence as it will be duped by the next curve + } + + return pts; + } + + private static function rationalBezierCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { + var pts = []; rationalBezierCurveRegularSamplePointsMutate( crv, divs, pts ); return pts; + } private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, divs : Int, pts : Array ) { @@ -419,22 +450,6 @@ class Eval { return pts; } - public static function rationalCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { - - var range = crv.knots.last() - crv.knots.length; - var beziers = Modify.decomposeCurveIntoBeziers( crv ); - var pts = []; - - for (i in 0...beziers.length){ - rationalBezierCurveRegularSamplePointsMutate( beziers[i], divs, pts ); - if (i == beziers.length-1) - continue; - pts.pop(); - } - - return pts; - } - // 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 // diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index 8b6169b3..1efb4311 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -455,7 +455,7 @@ class Modify { var reqMult = degree + 1; //insert the knots - for (knotmult in knotmults) { // (var i = 0; i < mults.length; i++){ + for (knotmult in knotmults) { if ( knotmult.mult < reqMult ){ var knotsInsert = Vec.rep( reqMult - knotmult.mult, knotmult.knot ); diff --git a/test/testCore.js b/test/testCore.js index 16ace2e5..9bc4a3e9 100755 --- a/test/testCore.js +++ b/test/testCore.js @@ -25,9 +25,9 @@ function last(a){ 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]]); @@ -43,9 +43,9 @@ describe("verb.core.BoundingBox.init",function(){ }); -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] ]) @@ -59,9 +59,9 @@ describe("verb.core.BoundingBox.intersects",function(){ }); -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] ]) @@ -87,9 +87,9 @@ describe("verb.core.BoundingBox.intersect",function(){ }); -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 ); @@ -100,9 +100,9 @@ describe("verb.core.BoundingBox.intervalsOverlap",function(){ }); -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(); @@ -117,9 +117,9 @@ describe("verb.core.BoundingBox.contains",function(){ }); -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(); @@ -128,9 +128,9 @@ describe("verb.core.BoundingBox.contains",function(){ }); }); -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 ); @@ -141,9 +141,9 @@ describe("verb.core.BoundingBox.getAxisLength",function(){ }); -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 ); @@ -152,9 +152,9 @@ describe("verb.core.BoundingBox.getLongestAxis",function(){ }); -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 ); @@ -166,9 +166,9 @@ describe("verb.core.BoundingBox.getAxisLength",function(){ }); -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 ); @@ -180,9 +180,9 @@ describe("verb.core.BoundingBox.getAxisLength",function(){ }); -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(); @@ -220,9 +220,9 @@ function getFlatSurface(){ } -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() ); @@ -238,9 +238,9 @@ describe("verb.core.AdaptiveRefinementNode.constructor",function(){ 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()); @@ -251,7 +251,7 @@ describe("verb.core.AdaptiveRefinementNode.getEdgeCorners",function(){ }); - it('returns expected result for node with children', function(){ + it('returns expected result for node with children', () => { var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); @@ -267,7 +267,7 @@ describe("verb.core.AdaptiveRefinementNode.getEdgeCorners",function(){ }); - 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()); @@ -285,9 +285,9 @@ describe("verb.core.AdaptiveRefinementNode.getEdgeCorners",function(){ }); -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()); @@ -302,7 +302,7 @@ describe("verb.core.AdaptiveRefinementNode.getAllCorners",function(){ }); - 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()); @@ -318,25 +318,25 @@ describe("verb.core.AdaptiveRefinementNode.getAllCorners",function(){ }); -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()); @@ -347,7 +347,7 @@ describe("verb.core.AdaptiveRefinementNode.divide",function(){ }); - it('can be called with no options provided', function(){ + it('can be called with no options provided', () => { var f = new verb.core.AdaptiveRefinementNode(getFlatSurface()); @@ -360,9 +360,9 @@ describe("verb.core.AdaptiveRefinementNode.divide",function(){ }); -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 ); @@ -370,9 +370,9 @@ describe("verb.core.Trig.distToSegment",function(){ }); -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()); @@ -395,7 +395,7 @@ describe("verb.core.AdaptiveRefinementNode.evalSrf",function(){ }); -describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ +describe("verb.core.AdaptiveRefinementNode.triangulate", () => { function getWarpedSurface(){ @@ -424,7 +424,7 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ } - 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(); @@ -439,7 +439,7 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ }); - it('can triangulate a warped surface with no options defined', function(){ + it('can triangulate a warped surface with no options defined', () => { var srf = getWarpedSurface(); @@ -456,7 +456,7 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ }); - it('can triangulate a node with children', function(){ + it('can triangulate a node with children', () => { var srf = getFlatSurface(); @@ -473,7 +473,7 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ }); - 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(); @@ -492,7 +492,7 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ }); - 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(); @@ -510,7 +510,7 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ }); - 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(); @@ -530,9 +530,9 @@ describe("verb.core.AdaptiveRefinementNode.triangulate",function(){ }); -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); @@ -571,7 +571,7 @@ describe("verb.core.Mat.solve",function(){ } - it('can solve complex case', function(){ + it('can solve complex case', () => { var n = 5; var A = rand2d(n); @@ -590,9 +590,9 @@ describe("verb.core.Mat.solve",function(){ }); -describe("verb.core.Mesh.makeMeshAabb",function(){ +describe("verb.core.Mesh.makeMeshAabb", () => { - it('should return correct result for planar mesh', function(){ + it('should return correct result for planar mesh', () => { // // 0 - 1 @@ -617,7 +617,7 @@ describe("verb.core.Mesh.makeMeshAabb",function(){ }); - it('makeMeshAabb should return correct result for non-planar mesh', function(){ + it('makeMeshAabb should return correct result for non-planar mesh', () => { // // 0 - 1 @@ -644,9 +644,9 @@ describe("verb.core.Mesh.makeMeshAabb",function(){ }); -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] @@ -658,7 +658,7 @@ describe("verb.core.Mesh.getTriangleCentroid",function(){ }); - 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] @@ -672,9 +672,9 @@ describe("verb.core.Mesh.getTriangleCentroid",function(){ }); -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] @@ -689,9 +689,9 @@ describe("verb.eval.Eval.getMinCoordOnAxis",function(){ }); }); -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 @@ -712,7 +712,7 @@ describe("verb.core.Mesh.sortTrianglesOnLongestAxis",function(){ }); - 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]] @@ -726,7 +726,7 @@ describe("verb.core.Mesh.sortTrianglesOnLongestAxis",function(){ }); -describe("verb.core.KdTree",function(){ +describe("verb.core.KdTree", () => { var pts = [ new verb.core.KdPoint( [0,1,1], "a" ), @@ -734,7 +734,7 @@ describe("verb.core.KdTree",function(){ 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 ); @@ -743,7 +743,7 @@ describe("verb.core.KdTree",function(){ }); - 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 ); @@ -755,9 +755,9 @@ describe("verb.core.KdTree",function(){ }); -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] ]; @@ -773,21 +773,21 @@ describe("verb.core.Mesh.triangleUVFromPoint",function(){ }); }); -describe("verb.core.Vec.sortedSetUnion",function(){ - it('can merge two empty arrays', function(){ +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', function(){ + 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', function(){ + 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', function(){ + 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]); @@ -795,21 +795,21 @@ describe("verb.core.Vec.sortedSetUnion",function(){ }); }); -describe("verb.core.Vec.sortedSetSub",function(){ +describe("verb.core.Vec.sortedSetSub", () => { - it('can handle two empty arrays', function(){ + it('can handle two empty arrays', () => { verb.core.Vec.sortedSetSub([],[]).should.be.eql([]); }); - it('can subtract empty array from non-empty array', function(){ + 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(){ + 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(){ + 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]); @@ -819,8 +819,8 @@ describe("verb.core.Vec.sortedSetSub",function(){ }); -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 e0a11bbd..f6f4938d 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,9 +20,10 @@ function last(a){ return a[a.length-1]; } -describe("verb.eval.Eval.knotSpanGivenN",function(){ - it('returns correct result', function(){ +describe("verb.eval.Eval.knotSpanGivenN",() => { + + it('returns correct result', () => { var n = 7 , degree = 2 @@ -41,9 +42,9 @@ describe("verb.eval.Eval.knotSpanGivenN",function(){ }); -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]; @@ -60,9 +61,9 @@ describe("verb.eval.Eval.knotSpan",function(){ }); -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 @@ -84,9 +85,9 @@ describe("verb.eval.Eval.basisFunctions, basisFunctionsGivenKnotSpanIndex",funct }); -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 @@ -113,9 +114,9 @@ describe("verb.eval.Eval.curvePoint",function(){ }); -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 @@ -138,9 +139,9 @@ describe("verb.eval.Eval.curvePointGivenN",function(){ }); }); -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 ) ); @@ -148,9 +149,9 @@ describe("verb.eval.Eval.areValidRelations",function(){ }); }); -describe("verb.eval.Eval.derivativeBasisFunctionsGivenNI",function(){ +describe("verb.eval.Eval.derivativeBasisFunctionsGivenNI",() => { - it('returns correct results', function(){ + it('returns correct results', () => { // This needs to be tested better var degree = 2 @@ -180,9 +181,9 @@ describe("verb.eval.Eval.derivativeBasisFunctionsGivenNI",function(){ }); -describe("verb.eval.Eval.curveDerivativesGivenN",function(){ +describe("verb.eval.Eval.curveDerivativesGivenN",() => { - it('returns correct result for simple curve', function(){ + it('returns correct result for simple curve', () => { var degree = 3 , n = 3 @@ -202,9 +203,9 @@ describe("verb.eval.Eval.curveDerivativesGivenN",function(){ }); -describe("verb.eval.Eval.curveDerivatives",function(){ +describe("verb.eval.Eval.curveDerivatives",() => { - it('returns correct result for simple curve', function(){ + it('returns correct result for simple curve', () => { // This needs to be tested better var degree = 3 @@ -225,9 +226,9 @@ describe("verb.eval.Eval.curveDerivatives",function(){ }); -describe("verb.eval.Eval.surfacePointGivenNM",function(){ +describe("verb.eval.Eval.surfacePointGivenNM",() => { - it('returns correct result for simple surface', function(){ + it('returns correct result for simple surface', () => { // This needs to be tested better var degreeU = 3 @@ -258,9 +259,9 @@ describe("verb.eval.Eval.surfacePointGivenNM",function(){ }); -describe("verb.eval.Eval.surfacePoint",function(){ +describe("verb.eval.Eval.surfacePoint",() => { - it('returns correct result for simple surface', function(){ + it('returns correct result for simple surface', () => { // This needs to be tested better var degreeU = 3 @@ -287,7 +288,7 @@ describe("verb.eval.Eval.surfacePoint",function(){ }); - it('returns correct result for another simple surface', function(){ + it('returns correct result for another simple surface', () => { var degreeU = 1 , degreeV = 3 @@ -307,9 +308,9 @@ describe("verb.eval.Eval.surfacePoint",function(){ }); -describe("verb.eval.Eval.surfaceDerivativesGivenNM",function(){ +describe("verb.eval.Eval.surfaceDerivativesGivenNM",() => { - it('returns correct derivatives for simple surface', function(){ + it('returns correct derivatives for simple surface', () => { var degreeU = 3 , degreeV = 3 @@ -350,9 +351,9 @@ describe("verb.eval.Eval.surfaceDerivativesGivenNM",function(){ }); }); -describe("verb.eval.Eval.surfaceDerivatives",function(){ +describe("verb.eval.Eval.surfaceDerivatives",() => { - it('returns correct derivatives for simple surface', function(){ + it('returns correct derivatives for simple surface', () => { var degreeU = 3 , degreeV = 3 @@ -394,9 +395,9 @@ describe("verb.eval.Eval.surfaceDerivatives",function(){ }); -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] ] @@ -425,9 +426,9 @@ describe("verb.eval.Eval.homogenize1d",function(){ }); -describe("verb.eval.Eval.homogenize2d",function(){ +describe("verb.eval.Eval.homogenize2d",() => { - it('homogenize2d', function(){ + it('homogenize2d', () => { var weights = [ [ 1, -2, 3, 5 ], [ 2, 1, 5, 2 ], @@ -455,9 +456,9 @@ describe("verb.eval.Eval.homogenize2d",function(){ }); -describe("verb.eval.Eval.dehomogenize",function(){ +describe("verb.eval.Eval.dehomogenize",() => { - it('returns correct result', function(){ + it('returns correct result', () => { var weights = [ [ 1, -2, 3, 5 ], [ 2, 1, 5, 2 ], @@ -487,9 +488,9 @@ describe("verb.eval.Eval.dehomogenize",function(){ }); -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 @@ -516,9 +517,9 @@ describe("verb.eval.Eval.rationalCurvePoint",function(){ }); -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 @@ -550,9 +551,9 @@ describe("verb.eval.Eval.rationalSurfacePoint",function(){ }); }); -describe("verb.eval.Eval.rationalCurveDerivatives",function(){ +describe("verb.eval.Eval.rationalCurveDerivatives",() => { - it('returns expected results', function(){ + it('returns expected results', () => { // this represents a single quarter arc, using a rational bezier curve var degree = 2 @@ -586,9 +587,9 @@ describe("verb.eval.Eval.rationalCurveDerivatives",function(){ }); -describe("verb.eval.Eval.rationalSurfaceDerivatives",function(){ +describe("verb.eval.Eval.rationalSurfaceDerivatives",() => { - it('returns expected results', function(){ + it('returns expected results', () => { // quarter cylinder patch, axis aligned with x axis, radius: 1 var degreeU = 1 @@ -631,9 +632,9 @@ describe("verb.eval.Eval.rationalSurfaceDerivatives",function(){ }); }); -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] @@ -656,9 +657,9 @@ describe("verb.eval.Eval.rationalCurvePoint",function(){ }); -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 @@ -691,7 +692,7 @@ describe("verb.eval.Modify.curveKnotInsert",function(){ }); - 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 @@ -720,7 +721,7 @@ describe("verb.eval.Modify.curveKnotInsert",function(){ }); - 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 @@ -748,7 +749,7 @@ describe("verb.eval.Modify.curveKnotInsert",function(){ }); - 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 @@ -777,7 +778,7 @@ describe("verb.eval.Modify.curveKnotInsert",function(){ }); }); -describe("verb.eval.Eval.curveKnotRefine",function(){ +describe("verb.eval.Eval.curveKnotRefine",() => { function cubicInsert(u, r){ @@ -810,7 +811,7 @@ describe("verb.eval.Eval.curveKnotRefine",function(){ } - it('returns expected results when inserting multiple knots in the middle of a non-rational, cubic b-spline', function(){ + 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); @@ -829,7 +830,7 @@ describe("verb.eval.Eval.curveKnotRefine",function(){ }); -describe("verb.eval.Divide.curveSplit",function(){ +describe("verb.eval.Divide.curveSplit",() => { function cubicSplit(u){ @@ -862,7 +863,7 @@ describe("verb.eval.Divide.curveSplit",function(){ } - it('returns expected results when splitting a non-rational, cubic b-spline', function(){ + it('returns expected results when splitting a non-rational, cubic b-spline', () => { cubicSplit( 0.5 ); cubicSplit( 3.5 ); @@ -871,9 +872,9 @@ describe("verb.eval.Divide.curveSplit",function(){ }); -describe("verb.eval.Analyze.knotMultiplicities",function(){ +describe("verb.eval.Analyze.knotMultiplicities",() => { - it('is correct for a basic example', function(){ + it('is correct for a basic example', () => { var res = verb.eval.Analyze.knotMultiplicities( [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3] ); @@ -897,50 +898,19 @@ describe("verb.eval.Analyze.knotMultiplicities",function(){ }); }); -describe("verb.eval.Modify.decomposeCurveIntoBeziers",function(){ - - it('is correct for a basic example', function(){ - - var degree = 3 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]; - - var controlPoints = []; - for (var i = 0; i < 8; i++) { - controlPoints.push([i, 0, 0]); - } - - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var res = verb.eval.Modify.decomposeCurveIntoBeziers( crv ); - - res.length.should.be.equal( 5 ); - - res.forEach(function(x){ - - var u0 = x.knots[0]; - - var pt0 = verb.eval.Eval.curvePoint( x, u0); - var pt1 = verb.eval.Eval.curvePoint( crv, u0); - - ( verb.core.Vec.norm(verb.core.Vec.sub(pt0, pt1))).should.be.approximately(0, verb.core.Constants.TOLERANCE ); - - }); - - }); -}); - -describe("verb.core.Mat.transpose",function(){ - it('is correct for a basic example', function(){ +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('is correct for empty array', function(){ + it('is correct for empty array', () => { verb.core.Mat.transpose([]).should.eql( [] ); }); }); -describe("verb.eval.Modify.surfaceKnotRefine",function(){ +describe("verb.eval.Modify.surfaceKnotRefine",() => { var degree = 3 , knotsV = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1] @@ -953,7 +923,7 @@ describe("verb.eval.Modify.surfaceKnotRefine",function(){ [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ] ] , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); - it('can add knots into a surface in the u direction', function(){ + it('can add knots into a surface in the u direction', () => { var r = 1; var u = 0.2; @@ -981,7 +951,7 @@ describe("verb.eval.Modify.surfaceKnotRefine",function(){ }); - it('can add knots into a surface in the v direction', function(){ + it('can add knots into a surface in the v direction', () => { var r = 1; var u = 0.2; @@ -1011,7 +981,7 @@ describe("verb.eval.Modify.surfaceKnotRefine",function(){ }); }); -describe("verb.eval.Divide.surfaceSplit", function(){ +describe("verb.eval.Divide.surfaceSplit", () => { var degree = 3 , knotsV = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1] @@ -1024,7 +994,7 @@ describe("verb.eval.Divide.surfaceSplit", function(){ [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ] ] , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); - it('can split a surface in the u direction', function(){ + it('can split a surface in the u direction', () => { var u = 0.2; @@ -1059,7 +1029,7 @@ describe("verb.eval.Divide.surfaceSplit", function(){ }); - it('can split a surface in the v direction', function(){ + it('can split a surface in the v direction', () => { var u = 0.2; @@ -1096,9 +1066,8 @@ describe("verb.eval.Divide.surfaceSplit", function(){ }); - -describe("verb.eval.Eval.rationalCurveRegularSample",function(){ - it('should return 10 samples when asked to', function(){ +describe("verb.eval.Eval.rationalCurveRegularSample",() => { + it('should return 10 samples when asked to', () => { var degree = 2 , knots = [0, 0, 0, 1, 1, 1 ] @@ -1115,9 +1084,9 @@ describe("verb.eval.Eval.rationalCurveRegularSample",function(){ }); }); -describe("verb.eval.Eval.threePointsAreFlat",function(){ +describe("verb.eval.Eval.threePointsAreFlat",() => { - it('should identify flat line by returning true', function(){ + it('should identify flat line by returning true', () => { // this represents a single quarter arc, using a rational bezier curve var p1 = [0,0,0], @@ -1130,9 +1099,9 @@ describe("verb.eval.Eval.threePointsAreFlat",function(){ }); -describe("verb.eval.Tess.rationalCurveAdaptiveSample",function(){ +describe("verb.eval.Tess.rationalCurveAdaptiveSample",() => { - it('returns two end points for a line', function(){ + it('returns two end points for a line', () => { var degree = 1 , knots = [0, 0, 1, 1] @@ -1148,7 +1117,7 @@ describe("verb.eval.Tess.rationalCurveAdaptiveSample",function(){ }); - it('returns all the control points for a degree 1 curve', function(){ + it('returns all the control points for a degree 1 curve', () => { var degree = 1 , knots = [0, 0, 0.25, 0.5, 0.75, 1, 1] @@ -1166,7 +1135,7 @@ describe("verb.eval.Tess.rationalCurveAdaptiveSample",function(){ }); - it('makes more points for an arc', function(){ + it('makes more points for an arc', () => { var degree = 2 , knots = [0, 0, 0, 1, 1, 1 ] @@ -1198,8 +1167,7 @@ describe("verb.eval.Tess.rationalCurveAdaptiveSample",function(){ }); - -describe("verb.eval.Tess.rationalSurfaceAdaptive",function(){ +describe("verb.eval.Tess.rationalSurfaceAdaptive",() => { function getComplexSurface(){ @@ -1231,7 +1199,7 @@ describe("verb.eval.Tess.rationalSurfaceAdaptive",function(){ return srfObj; } - it('produces a mesh from a divided surface', function(){ + it('produces a mesh from a divided surface', () => { var srf = getComplexSurface(); @@ -1245,9 +1213,9 @@ describe("verb.eval.Tess.rationalSurfaceAdaptive",function(){ }); }); -describe("verb.eval.Make.ellipseArc",function(){ +describe("verb.eval.Make.ellipseArc",() => { - it('returns correct result for unit arc from 0 to 90 deg', function(){ + it('returns correct result for unit arc from 0 to 90 deg', () => { var center = [0,0,0] , rx = 5 @@ -1283,7 +1251,7 @@ describe("verb.eval.Make.ellipseArc",function(){ }); - it('returns correct result for unit arc from 0 to 90 deg', function(){ + it('returns correct result for unit arc from 0 to 90 deg', () => { var center = [0,0,0] , rx = 5 @@ -1303,7 +1271,7 @@ describe("verb.eval.Make.ellipseArc",function(){ }); - it('returns correct result for unit arc from 45 to 135 deg', function(){ + it('returns correct result for unit arc from 45 to 135 deg', () => { var center = [0,0,0] , rx = 1 @@ -1327,7 +1295,7 @@ describe("verb.eval.Make.ellipseArc",function(){ }); - it('returns correct result for complete ellipse', function(){ + it('returns correct result for complete ellipse', () => { var center = [0,0,0] , rx = 1 @@ -1371,9 +1339,9 @@ describe("verb.eval.Make.ellipseArc",function(){ }); -describe("verb.eval.Make.extrudedSurface",function(){ +describe("verb.eval.Make.extrudedSurface",() => { - it('can extrude a line into a plane', function(){ + it('can extrude a line into a plane', () => { var axis = [0,0,1] , length = 5 @@ -1402,7 +1370,7 @@ describe("verb.eval.Make.extrudedSurface",function(){ }); - it('can extrude a 90 deg quadratic arc bezier curve', function(){ + it('can extrude a 90 deg quadratic arc bezier curve', () => { var axis = [0,0,1] , length = 5 @@ -1442,9 +1410,9 @@ describe("verb.eval.Make.extrudedSurface",function(){ }); -describe("verb.eval.Make.arc",function(){ +describe("verb.eval.Make.arc",() => { - it('returns correct result for unit arc from 0 to 90 deg', function(){ + it('returns correct result for unit arc from 0 to 90 deg', () => { var center = [0,0,0] , x = [1,0,0] @@ -1463,7 +1431,7 @@ describe("verb.eval.Make.arc",function(){ }); - it('returns correct result for unit arc from 0 to 45 deg', function(){ + it('returns correct result for unit arc from 0 to 45 deg', () => { var center = [0,0,0] , x = [1,0,0] @@ -1482,7 +1450,7 @@ describe("verb.eval.Make.arc",function(){ }); - it('returns correct result for unit arc from 45 to 135 deg', function(){ + it('returns correct result for unit arc from 45 to 135 deg', () => { var center = [0,0,0] , x = [1,0,0] @@ -1501,7 +1469,7 @@ describe("verb.eval.Make.arc",function(){ }); - it('returns correct result for unit circle', function(){ + it('returns correct result for unit circle', () => { var center = [0,0,0] , x = [1,0,0] @@ -1520,7 +1488,7 @@ describe("verb.eval.Make.arc",function(){ }); - it('returns correct result for unit circle', function(){ + it('returns correct result for unit circle', () => { var center = [0,0,0] , x = [1,0,0] @@ -1541,9 +1509,9 @@ describe("verb.eval.Make.arc",function(){ }); -describe("verb.eval.Make.polyline",function(){ +describe("verb.eval.Make.polyline",() => { - it('can create a polyline with correct structure', function(){ + it('can create a polyline with correct structure', () => { var degree = 1 , knots = [0, 0, 0.25, 0.5, 0.75, 1, 1] @@ -1564,9 +1532,9 @@ describe("verb.eval.Make.polyline",function(){ }); -describe("verb.eval.Make.cylindricalSurface",function(){ +describe("verb.eval.Make.cylindricalSurface",() => { - it('can create a cylinder', function(){ + it('can create a cylinder', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1614,9 +1582,9 @@ describe("verb.eval.Make.cylindricalSurface",function(){ }); -describe("verb.eval.Make.revolvedSurface",function(){ +describe("verb.eval.Make.revolvedSurface",() => { - it('creates a 90 degree cone with the given line for a profile', function(){ + it('creates a 90 degree cone with the given line for a profile', () => { var axis = [0,0,1] , center = [0,0,0] @@ -1649,7 +1617,7 @@ describe("verb.eval.Make.revolvedSurface",function(){ }); - it('creates a 180 degree cone with the given line for a profile', function(){ + it('creates a 180 degree cone with the given line for a profile', () => { var axis = [0,0,1] , center = [0,0,0] @@ -1683,7 +1651,7 @@ describe("verb.eval.Make.revolvedSurface",function(){ }); - it('creates a 360 degree cone with the given line for a profile', function(){ + it('creates a 360 degree cone with the given line for a profile', () => { var axis = [0,0,1] , center = [0,0,0] @@ -1718,9 +1686,9 @@ describe("verb.eval.Make.revolvedSurface",function(){ }); -describe("verb.core.Trig.rayClosestPoint",function(){ +describe("verb.core.Trig.rayClosestPoint",() => { - it('returns correct result for xaxis and 3d pt', function(){ + it('returns correct result for xaxis and 3d pt', () => { var r = [1,0,0] , o = [0,0,0] @@ -1736,9 +1704,9 @@ describe("verb.core.Trig.rayClosestPoint",function(){ }); -describe("verb.core.Trig.distToRay",function(){ +describe("verb.core.Trig.distToRay",() => { - it('returns correct result for xaxis and 3d pt', function(){ + it('returns correct result for xaxis and 3d pt', () => { var r = [1,0,0] , o = [0,0,0] @@ -1752,9 +1720,9 @@ describe("verb.core.Trig.distToRay",function(){ }); -describe("verb.eval.Make.conicalSurface",function(){ +describe("verb.eval.Make.conicalSurface",() => { - it('can create a cone', function(){ + it('can create a cone', () => { var axis = [0,0,1] , xaxis = [1,0,0] @@ -1803,9 +1771,9 @@ describe("verb.eval.Make.conicalSurface",function(){ }); -describe("verb.eval.Make.sphericalSurface",function(){ +describe("verb.eval.Make.sphericalSurface",() => { - it('can create a unit sphere', function(){ + it('can create a unit sphere', () => { var center = [0,0,0] , axis = [0,0,1] @@ -1831,9 +1799,9 @@ describe("verb.eval.Make.sphericalSurface",function(){ }); -describe("verb.eval.Analyze.rationalBezierCurveArcLength",function(){ +describe("verb.eval.Analyze.rationalBezierCurveArcLength",() => { - it('can compute entire arc length of straight cubic bezier parameterized from 0 to 1', function(){ + 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] @@ -1846,7 +1814,7 @@ describe("verb.eval.Analyze.rationalBezierCurveArcLength",function(){ }); - it('can compute entire arc length of straight cubic bezier parameterized from 1 to 4', function(){ + it('can compute entire arc length of straight cubic bezier parameterized from 1 to 4', () => { var degree = 3 , knots = [1,1,1,1,4,4,4,4] @@ -1861,9 +1829,9 @@ describe("verb.eval.Analyze.rationalBezierCurveArcLength",function(){ }); -describe("verb.eval.Analyze.rationalCurveArcLength",function(){ +describe("verb.eval.Analyze.rationalCurveArcLength",() => { - it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', function(){ + it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { var degree = 3 , knots = [0,0,0,0,0.5,2,2,2,2] @@ -1883,7 +1851,7 @@ describe("verb.eval.Analyze.rationalCurveArcLength",function(){ } }); - it('can compute entire arc length of curved nurbs curve parameterized from 0 to 1', function(){ + it('can compute entire arc length of curved nurbs curve parameterized from 0 to 1', () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -1903,7 +1871,7 @@ describe("verb.eval.Analyze.rationalCurveArcLength",function(){ }); - it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', function(){ + it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { var degree = 3 , knots = [0,0,0,0,0.5,2,2,2,2] @@ -1927,9 +1895,9 @@ describe("verb.eval.Analyze.rationalCurveArcLength",function(){ }); -describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",function(){ +describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",() => { - it('can compute parameter at arc length of straight bezier curve', function(){ + it('can compute parameter at arc length of straight bezier curve', () => { var degree = 3 , knots = [0,0,0,0,1,1,1,1] @@ -1953,7 +1921,7 @@ describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",function(){ }); - it('can compute parameter at arc length of curved bezier curve', function(){ + it('can compute parameter at arc length of curved bezier curve', () => { var degree = 3 , knots = [0,0,0,0,1,1,1,1] @@ -1979,9 +1947,9 @@ describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",function(){ }); -describe("verb.eval.Analyze.rationalCurveParamAtArcLength",function(){ +describe("verb.eval.Analyze.rationalCurveParamAtArcLength",() => { - it('can compute parameter at arc length of straight NURBS curve', function(){ + it('can compute parameter at arc length of straight NURBS curve', () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -2007,7 +1975,7 @@ describe("verb.eval.Analyze.rationalCurveParamAtArcLength",function(){ }); - it('can compute parameter at arc length of curved NURBS curve', function(){ + it('can compute parameter at arc length of curved NURBS curve', () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -2033,9 +2001,9 @@ describe("verb.eval.Analyze.rationalCurveParamAtArcLength",function(){ }); -describe("verb.eval.Divide.rationalCurveByArcLength",function(){ +describe("verb.eval.Divide.rationalCurveByArcLength",() => { - it('can divide a straight NURBS curve', function(){ + it('can divide a straight NURBS curve', () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -2059,9 +2027,9 @@ describe("verb.eval.Divide.rationalCurveByArcLength",function(){ }); -describe("verb.eval.Divide.rationalCurveByEqualArcLength",function(){ +describe("verb.eval.Divide.rationalCurveByEqualArcLength",() => { - it('can divide a straight NURBS curve', function(){ + it('can divide a straight NURBS curve', () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -2086,9 +2054,9 @@ describe("verb.eval.Divide.rationalCurveByEqualArcLength",function(){ }); -describe("verb.eval.Analyze.rationalCurveClosestParam",function(){ +describe("verb.eval.Analyze.rationalCurveClosestParam",() => { - it('can get closest point to a straight curve', function(){ + it('can get closest point to a straight curve', () => { var degree = 3 , knots = [0,0,0,0,0.5,1,1,1,1] @@ -2122,9 +2090,9 @@ describe("verb.eval.Analyze.rationalCurveClosestParam",function(){ }); -describe("verb.eval.Analyze.rationalSurfaceClosestParam",function(){ +describe("verb.eval.Analyze.rationalSurfaceClosestParam",() => { - it('can get closest point to flat bezier patch', function(){ + it('can get closest point to flat bezier patch', () => { var degreeU = 3 , degreeV = 3 @@ -2146,9 +2114,9 @@ describe("verb.eval.Analyze.rationalSurfaceClosestParam",function(){ }); -describe("verb.eval.Intersect.segmentWithTriangle",function(){ +describe("verb.eval.Intersect.segmentWithTriangle",() => { - it('gives correct result for intersecting axis aligned segment and triangle ', function(){ + it('gives correct result for intersecting axis aligned segment and triangle ', () => { // line from [5,5,5] to [5,5,-5] var p0 = [ 5,5,5 ] @@ -2172,7 +2140,7 @@ describe("verb.eval.Intersect.segmentWithTriangle",function(){ }); - it('gives correct result for intersecting axis aligned segment and planar triangle ', function(){ + it('gives correct result for intersecting axis aligned segment and planar triangle ', () => { // line from [5,5,5] to [5,5,-5] var p0 = [ 5,5,5 ] @@ -2194,7 +2162,7 @@ describe("verb.eval.Intersect.segmentWithTriangle",function(){ }); - it('gives null for non-intersecting segment and triangle', function(){ + it('gives null for non-intersecting segment and triangle', () => { // line from [5,5,5] to [5,5,-5] var p0 = [ 5,5,5 ] @@ -2213,9 +2181,9 @@ describe("verb.eval.Intersect.segmentWithTriangle",function(){ }); -describe("verb.eval.Make.fourPointSurface",function(){ +describe("verb.eval.Make.fourPointSurface",() => { - it('can create an inclined plane', function(){ + it('can create an inclined plane', () => { var p1 = [0,0,0] , p2 = [1,0,0] @@ -2238,7 +2206,7 @@ describe("verb.eval.Make.fourPointSurface",function(){ }); - it('can create a hypar', function(){ + it('can create a hypar', () => { var p1 = [0,0,1] , p2 = [1,0,0] @@ -2281,9 +2249,9 @@ describe("verb.eval.Make.fourPointSurface",function(){ }); -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] @@ -2303,7 +2271,7 @@ describe("verb.eval.Intersect.polylines",function(){ }); - 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] @@ -2325,7 +2293,7 @@ describe("verb.eval.Intersect.polylines",function(){ }); - 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] @@ -2354,7 +2322,7 @@ describe("verb.eval.Intersect.polylines",function(){ }); - 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] @@ -2370,9 +2338,9 @@ describe("verb.eval.Intersect.polylines",function(){ }); }); -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]; @@ -2386,7 +2354,7 @@ describe("verb.eval.Intersect.threePlanes",function(){ }); - 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]; @@ -2409,7 +2377,7 @@ describe("verb.eval.Intersect.threePlanes",function(){ }); - it('is null for repeat planes', function(){ + it('is null for repeat planes', () => { var d1 = 10; var n1 = [0,1,0]; @@ -2425,9 +2393,9 @@ describe("verb.eval.Intersect.threePlanes",function(){ }); -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]; @@ -2441,7 +2409,7 @@ describe("verb.eval.Intersect.planes",function(){ }); - 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]; @@ -2455,7 +2423,7 @@ describe("verb.eval.Intersect.planes",function(){ }); - 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]; @@ -2472,9 +2440,9 @@ describe("verb.eval.Intersect.planes",function(){ }); -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]; @@ -2499,7 +2467,7 @@ describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ }); - 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]; @@ -2522,7 +2490,7 @@ describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ }); - 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]; @@ -2545,7 +2513,7 @@ describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ }); - 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]; @@ -2568,7 +2536,7 @@ describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ }); - 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]; @@ -2591,7 +2559,7 @@ describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ }); - 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]; @@ -2616,9 +2584,9 @@ describe("verb.eval.Intersect.clipRayInCoplanarTriangle",function(){ }); -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]; @@ -2649,7 +2617,7 @@ describe("verb.eval.Intersect.mergeTriangleClipIntervals",function(){ }); - 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]; @@ -2682,9 +2650,9 @@ describe("verb.eval.Intersect.mergeTriangleClipIntervals",function(){ }); -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 ]]; @@ -2708,7 +2676,7 @@ describe("verb.eval.Intersect.triangles",function(){ }); - 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 ]]; @@ -2735,9 +2703,9 @@ describe("verb.eval.Intersect.triangles",function(){ }); -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], @@ -2757,7 +2725,7 @@ describe("verb.eval.Intersect.curves",function(){ }); - 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], @@ -2777,7 +2745,7 @@ describe("verb.eval.Intersect.curves",function(){ }); - 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], @@ -2797,7 +2765,7 @@ describe("verb.eval.Intersect.curves",function(){ }); - 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], @@ -2818,9 +2786,9 @@ describe("verb.eval.Intersect.curves",function(){ }); -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] ] ] @@ -2846,7 +2814,7 @@ describe("verb.eval.Intersect.curveAndSurface",function(){ }); - 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] ] ] @@ -2871,7 +2839,7 @@ describe("verb.eval.Intersect.curveAndSurface",function(){ }); - 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] ] ] @@ -2896,7 +2864,7 @@ describe("verb.eval.Intersect.curveAndSurface",function(){ }); - 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] ] ] @@ -2919,9 +2887,9 @@ describe("verb.eval.Intersect.curveAndSurface",function(){ }); -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 @@ -2948,7 +2916,7 @@ describe("verb.eval.Intersect.curveAndSurfaceWithEstimate",function(){ }); -describe("verb.eval.Intersect.lookupAdjacentSegment",function(){ +describe("verb.eval.Intersect.lookupAdjacentSegment",() => { var segs = [ new verb.core.Interval( @@ -2961,7 +2929,7 @@ describe("verb.eval.Intersect.lookupAdjacentSegment",function(){ 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; @@ -2972,7 +2940,7 @@ describe("verb.eval.Intersect.lookupAdjacentSegment",function(){ }); - 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 @@ -2985,9 +2953,9 @@ describe("verb.eval.Intersect.lookupAdjacentSegment",function(){ }); -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( @@ -3014,9 +2982,9 @@ describe("verb.eval.Intersect.makeMeshIntersectionPolylines ",function(){ }); -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( @@ -3037,9 +3005,9 @@ describe("verb.eval.Intersect.kdTreeFromSegments",function(){ }); -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 ]]; @@ -3058,7 +3026,7 @@ describe("verb.eval.Intersect.meshes",function(){ }); - 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 ]]; @@ -3076,7 +3044,7 @@ describe("verb.eval.Intersect.meshes",function(){ }); - 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] @@ -3103,9 +3071,9 @@ describe("verb.eval.Intersect.meshes",function(){ }); -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 ] @@ -3174,7 +3142,7 @@ function sameCurve( crvd0, crvd1 ){ } } -describe("verb.eval.Modify.curveElevateDegree",function(){ +describe("verb.eval.Modify.curveElevateDegree",() => { // line from [5,5,5] to [5,5,-5] var degree_crv = 2 @@ -3184,21 +3152,21 @@ describe("verb.eval.Modify.curveElevateDegree",function(){ 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(){ + 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 ); }); - it('can elevate degree 2 bezier to degree 4', function(){ + 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 ); }); - it('can elevate degree 1 line to degree 3', function(){ + it('can elevate degree 1 line to degree 3', () => { var curveData = verb.eval.Modify.curveElevateDegree( lineCurveData, 3 ); curveData.degree.should.be.equal( 3 ); @@ -3207,13 +3175,13 @@ describe("verb.eval.Modify.curveElevateDegree",function(){ }); -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] ] ); - it('can handle straight beziers', function(){ + it('can handle straight beziers', () => { var curves = [c0, c1, c2] var res = verb.eval.Modify.unifyCurveKnotVectors(curves); @@ -3226,13 +3194,13 @@ describe("verb.eval.Modify.unifyCurveKnotVectors",function(){ }); }); -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] ] ); - it('can handle straight beziers', function(){ + it('can handle straight beziers', () => { var curves = [c0, c1, c2]; var surface = verb.eval.Make.loftedSurface( curves ); @@ -3263,9 +3231,9 @@ describe("verb.eval.Make.loftedSurface",function(){ }); }); -describe("verb.eval.Check.isValidNurbsCurveData",function(){ +describe("verb.eval.Check.isValidNurbsCurveData",() => { - it('is correct for basic case', function(){ + 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); }); @@ -3312,7 +3280,7 @@ describe("verb.eval.Check.isValidNurbsCurveData",function(){ }); -describe("verb.eval.Check.isValidNurbsSurfaceData",function(){ +describe("verb.eval.Check.isValidNurbsSurfaceData",() => { var degreeU = 3 @@ -3324,7 +3292,7 @@ describe("verb.eval.Check.isValidNurbsSurfaceData",function(){ [ [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(){ + it('is correct for basic case', () => { var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); verb.eval.Check.isValidNurbsSurfaceData(c); }); @@ -3406,35 +3374,35 @@ describe("verb.eval.Check.isValidNurbsSurfaceData",function(){ }); -describe("verb.eval.Check.isValidKnotVector",function(){ +describe("verb.eval.Check.isValidKnotVector",() => { - it('detects correct knot vector', function(){ + 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(){ + 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(){ + 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(){ + 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(){ + 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(){ + 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(){ @@ -3499,21 +3467,21 @@ describe("verb.eval.Intersect.meshes",function(){ return [srf1,srf2]; } - it('detects all 4 polylines in nurbs surface plane intersection', function(){ + 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', function(){ + 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', function(){ + it('detects glancing intersection between cylinder and plane', () => { var srfs = glancingPlaneCylindricalSurface(); var res = verb.eval.Intersect.meshes( srfs[0].tessellate(), srfs[1].tessellate() ); @@ -3522,14 +3490,14 @@ describe("verb.eval.Intersect.meshes",function(){ }); -describe("verb.eval.Modify.knotsReverse",function(){ - it('can reverse basic knot array', function(){ +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(){ +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 ); @@ -3543,7 +3511,7 @@ describe("verb.eval.Modify.curveReverse",function(){ }); }); -describe("verb.eval.Modify.surfaceReverse",function(){ +describe("verb.eval.Modify.surfaceReverse",() => { var degreeU = 3 , degreeV = 3 @@ -3556,7 +3524,7 @@ describe("verb.eval.Modify.surfaceReverse",function(){ [ [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 ); @@ -3577,7 +3545,7 @@ describe("verb.eval.Modify.surfaceReverse",function(){ }); - it('is correct for v direction', function(){ + it('is correct for v direction', () => { var sr = verb.eval.Modify.surfaceReverse( s, false ); @@ -3599,9 +3567,9 @@ describe("verb.eval.Modify.surfaceReverse",function(){ }); }); -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(); @@ -3614,9 +3582,9 @@ describe("verb.eval.Intersect.sliceMeshes",function(){ }); -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 prof = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,0,0]] ); @@ -3630,7 +3598,7 @@ describe("verb.eval.Make.rationalTranslationalSurface",function(){ }); - 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]] ); @@ -3646,7 +3614,7 @@ describe("verb.eval.Make.rationalTranslationalSurface",function(){ }); -describe("verb.eval.Make.surfaceIsocurve",function(){ +describe("verb.eval.Make.surfaceIsocurve",() => { var degreeU = 3 , degreeV = 3 @@ -3659,7 +3627,7 @@ describe("verb.eval.Make.surfaceIsocurve",function(){ , 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 ); @@ -3673,7 +3641,7 @@ 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 ){ @@ -3692,9 +3660,9 @@ describe("verb.eval.Make.surfaceIsocurve",function(){ }); }); -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]; @@ -3726,8 +3694,8 @@ describe("verb.eval.Make.surfaceBoundaryCurves",function(){ }); -describe("verb.eval.Intersect.segmentAndPlane",function(){ - it('works for simple cases', function(){ +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 ); @@ -3737,7 +3705,7 @@ describe("verb.eval.Intersect.segmentAndPlane",function(){ }); -describe("verb.eval.Make.rationalInterpCurve",function(){ +describe("verb.eval.Make.rationalInterpCurve",() => { function shouldInterpPointsWithTangents(pts, degree, isHomo, start_tangent, end_tangent){ @@ -3789,7 +3757,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ return crv; } - it('can compute valid cubic interpolating curve for 4 points', function(){ + it('can compute valid cubic interpolating curve for 4 points', () => { var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; @@ -3798,7 +3766,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ }); - it('can compute valid degree 4 interpolating curve for 4 points', function(){ + 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] ]; @@ -3806,7 +3774,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ }); - it('can compute valid quadratic interpolating curve for 4 points', function(){ + 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] ]; @@ -3814,7 +3782,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ }); - it('can compute valid cubic interpolating curve for 100 points', function(){ + it('can compute valid cubic interpolating curve for 100 points', () => { var pts = []; for (var i = 0; i < 100; i++){ @@ -3829,7 +3797,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ }); - it('can compute valid cubic interpolating points and tangents', function(){ + 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] ]; @@ -3838,7 +3806,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ }); // this fails occasionally - don't know why - // it('can compute valid quadratic curve interpolating points and tangents', function(){ + // 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] ]; @@ -3846,7 +3814,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ // }); - // it('can compute valid quadratic curve interpolating points and tangents', function(){ + // 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] ]; @@ -3858,7 +3826,7 @@ describe("verb.eval.Make.rationalInterpCurve",function(){ -describe("verb.eval.Eval.surfaceRegularSamplePoints",function(){ +describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { function getComplexSurface(){ @@ -3892,7 +3860,7 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",function(){ var complexSurface = getComplexSurface(); - it('returns correct result for complex surface', function(){ + it('returns correct result for complex surface', () => { var p = verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 10, 10 ); @@ -3922,12 +3890,68 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",function(){ }); }); -describe("verb.eval.Eval.rationalBezierCurveRegularSample",function(){ - it('returns correct result for basic bezier curve', function(){ - var crv = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1], [2,1,1], [3,1,0]] ); + +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.Eval.rationalCurveRegularSamplePoints",() => { + + function evalAndCompare(crv){ var divs = 200; - var p = verb.eval.Eval.rationalBezierCurveRegularSamplePoints( crv, divs ); + var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, divs ); var p2 = []; var sp = 1 / divs; @@ -3936,10 +3960,41 @@ describe("verb.eval.Eval.rationalBezierCurveRegularSample",function(){ p2.push( verb.eval.Eval.rationalCurvePoint( crv, i*sp ) ) } - p.length.should.equal(p2.length); + p.length.should.equal( p2.length ); for (var i = 0; i < p.length; i++){ vecShouldBe( p[i], p2[i] ); } - }); -}); \ No newline at end of file + } + + 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); +// +// }); + +}); + diff --git a/test/testGeom.js b/test/testGeom.js index 62b9ca55..6d9b22a0 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); @@ -289,7 +289,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 ]; @@ -325,7 +325,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); @@ -341,7 +341,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] @@ -355,7 +355,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 ]); }); @@ -368,9 +368,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 ); @@ -387,9 +387,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); @@ -430,9 +430,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(); @@ -445,9 +445,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]; @@ -460,9 +460,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]; @@ -481,9 +481,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]; @@ -501,9 +501,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]; @@ -522,9 +522,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] @@ -539,9 +539,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] @@ -560,9 +560,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] @@ -582,9 +582,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] @@ -605,9 +605,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); @@ -617,9 +617,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); @@ -635,9 +635,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); @@ -660,9 +660,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); @@ -677,9 +677,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]); @@ -689,9 +689,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]); @@ -713,9 +713,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]); @@ -751,9 +751,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]); @@ -768,9 +768,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); @@ -780,9 +780,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); @@ -798,9 +798,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); @@ -823,9 +823,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); @@ -840,7 +840,7 @@ describe("verb.geom.EllipseArc.tessellate",function(){ }); -describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights",function(){ +describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights", () => { var degreeU = 3 , degreeV = 3 @@ -856,7 +856,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 ); @@ -869,7 +869,7 @@ describe("verb.geom.NurbsSurface.byKnotsControlPointsWeights",function(){ }); -describe("verb.geom.NurbsSurface.domainU",function(){ +describe("verb.geom.NurbsSurface.domainU", () => { var degreeU = 3 , degreeV = 3 @@ -885,7 +885,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 ); @@ -893,7 +893,7 @@ describe("verb.geom.NurbsSurface.domainU",function(){ }); }); -describe("verb.geom.NurbsSurface.domainV",function(){ +describe("verb.geom.NurbsSurface.domainV", () => { var degreeU = 3 , degreeV = 3 @@ -909,7 +909,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 ); @@ -917,7 +917,7 @@ describe("verb.geom.NurbsSurface.domainV",function(){ }); }); -describe("verb.geom.NurbsSurface.point",function(){ +describe("verb.geom.NurbsSurface.point", () => { var degreeU = 3 , degreeV = 3 @@ -933,7 +933,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) ); @@ -950,7 +950,7 @@ describe("verb.geom.NurbsSurface.point",function(){ }); -describe("verb.geom.NurbsSurface.normal",function(){ +describe("verb.geom.NurbsSurface.normal", () => { var degreeU = 3 , degreeV = 3 @@ -966,7 +966,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) ); }); @@ -981,7 +981,7 @@ describe("verb.geom.NurbsSurface.normal",function(){ }); -describe("verb.geom.NurbsSurface.derivatives",function(){ +describe("verb.geom.NurbsSurface.derivatives", () => { var degreeU = 3 , degreeV = 3 @@ -997,7 +997,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] ); @@ -1018,7 +1018,7 @@ describe("verb.geom.NurbsSurface.derivatives",function(){ }); -describe("verb.geom.NurbsSurface.closestParam",function(){ +describe("verb.geom.NurbsSurface.closestParam", () => { var degreeU = 3 , degreeV = 3 @@ -1034,7 +1034,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 ); }); @@ -1047,7 +1047,7 @@ describe("verb.geom.NurbsSurface.closestParam",function(){ }); }); -describe("verb.geom.NurbsSurface.closestPoint",function(){ +describe("verb.geom.NurbsSurface.closestPoint", () => { var degreeU = 3 , degreeV = 3 @@ -1063,7 +1063,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 ); }); @@ -1076,7 +1076,7 @@ describe("verb.geom.NurbsSurface.closestPoint",function(){ }); }); -describe("verb.geom.NurbsSurface.split",function(){ +describe("verb.geom.NurbsSurface.split", () => { var degreeU = 3 , degreeV = 3 @@ -1092,7 +1092,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); @@ -1108,7 +1108,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); @@ -1144,7 +1144,7 @@ describe("verb.geom.NurbsSurface.split",function(){ }); }); -describe("verb.geom.NurbsSurface.tessellate",function(){ +describe("verb.geom.NurbsSurface.tessellate", () => { var degreeU = 3 , degreeV = 3 @@ -1160,7 +1160,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 ); @@ -1184,7 +1184,7 @@ describe("verb.geom.NurbsSurface.tessellate",function(){ // }); }); -describe("verb.geom.NurbsSurface.transform",function(){ +describe("verb.geom.NurbsSurface.transform", () => { var degreeU = 3 , degreeV = 3 @@ -1205,7 +1205,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 ); @@ -1222,7 +1222,7 @@ describe("verb.geom.NurbsSurface.transform",function(){ }); }); -describe("verb.geom.NurbsCurve.byPoints",function(){ +describe("verb.geom.NurbsCurve.byPoints", () => { function shouldInterpPoints(curve, pts){ @@ -1251,15 +1251,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] @@ -1273,9 +1273,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]; @@ -1294,9 +1294,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]; @@ -1324,9 +1324,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]; @@ -1352,9 +1352,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] @@ -1369,9 +1369,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] @@ -1392,9 +1392,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] @@ -1426,9 +1426,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] @@ -1456,9 +1456,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; @@ -1474,9 +1474,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; @@ -1495,9 +1495,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; @@ -1528,9 +1528,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; @@ -1556,9 +1556,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] @@ -1580,9 +1580,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] @@ -1606,9 +1606,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] @@ -1640,9 +1640,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] @@ -1671,9 +1671,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] @@ -1688,9 +1688,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] @@ -1711,9 +1711,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] @@ -1734,9 +1734,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] @@ -1765,9 +1765,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] @@ -1789,9 +1789,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] @@ -1813,9 +1813,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] @@ -1848,9 +1848,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] @@ -1879,12 +1879,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 ); @@ -1909,7 +1909,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] ] ] @@ -1927,7 +1927,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 ); @@ -1950,9 +1950,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 ); @@ -1967,7 +1967,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 @@ -1988,7 +1988,7 @@ describe("verb.geom.NurbsCurve.reverse",function(){ }); -describe("verb.geom.NurbsSurface.reverse",function(){ +describe("verb.geom.NurbsSurface.reverse", () => { var degreeU = 3 , degreeV = 3 @@ -2000,7 +2000,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 ); @@ -2021,8 +2021,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]] ); @@ -2031,9 +2031,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]] ); @@ -2048,7 +2048,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] @@ -2059,7 +2059,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 ); From c96330696570a257f2f427f8c2824d99728e3df0 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Wed, 28 Oct 2015 19:44:45 -0400 Subject: [PATCH 04/25] Fixed bugs with rationalCurveRegularSamplePoints --- Gruntfile.js | 1 - build/js/verb.js | 106 +- build/js/verbHaxe.js | 106 +- src/verb/eval/Eval.hx | 65 +- test/testEval.js | 5023 ++++++++++++++++++++--------------------- 5 files changed, 2635 insertions(+), 2666 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index f00c8f5b..c4f8a069 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -44,7 +44,6 @@ module.exports = function(grunt) { quiet: false // Optionally suppress output to standard out (defaults to false) }, src: ['test/testCore.js', 'test/testEval.js', 'test/testGeom.js'] - //src: ['test/testEval.js'] } }, diff --git a/build/js/verb.js b/build/js/verb.js index 36a8cbcf..f6318eb4 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -324,12 +324,6 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; -var haxe_Log = function() { }; -$hxClasses["haxe.Log"] = haxe_Log; -haxe_Log.__name__ = ["haxe","Log"]; -haxe_Log.trace = function(v,infos) { - js_Boot.__trace(v,infos); -}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -1064,25 +1058,6 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; -js_Boot.__unhtml = function(s) { - return s.split("&").join("&").split("<").join("<").split(">").join(">"); -}; -js_Boot.__trace = function(v,i) { - var msg; - if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; - msg += js_Boot.__string_rec(v,""); - if(i != null && i.customParams != null) { - var _g = 0; - var _g1 = i.customParams; - while(_g < _g1.length) { - var v1 = _g1[_g]; - ++_g; - msg += "," + js_Boot.__string_rec(v1,""); - } - } - var d; - if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); -}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1958,7 +1933,7 @@ var verb_Verb = function() { }; $hxClasses["verb.Verb"] = verb_Verb; verb_Verb.__name__ = ["verb","Verb"]; verb_Verb.main = function() { - haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); + console.log("verb 2.0.0"); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -4290,51 +4265,58 @@ verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { var pts = []; var brange; var fraction; - haxe_Log.trace(beziers.map(function(x) { - return x.knots; - }),{ fileName : "Eval.hx", lineNumber : 369, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); + var currentU = crv.knots[0]; + var step = range / divs; + var brange1; + var bsteps; + var nextU; var _g1 = 0; var _g = beziers.length; while(_g1 < _g) { var i = _g1++; - brange = verb_core_ArrayExtensions.last(beziers[i].knots) - beziers[i].knots[0]; - haxe_Log.trace(brange,{ fileName : "Eval.hx", lineNumber : 376, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints", customParams : [range]}); - fraction = Math.ceil(brange / range * divs); - haxe_Log.trace(fraction,{ fileName : "Eval.hx", lineNumber : 378, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],fraction,pts); - if(i == beziers.length - 1) continue; - pts.pop(); + brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],pts,currentU,step,bsteps + 1); + currentU = nextU + step; } return pts; }; -verb_eval_Eval.rationalBezierCurveRegularSamplePoints = function(crv,divs) { - var pts = []; - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(crv,divs,pts); - return pts; -}; -verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs,pts) { - var t = (verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]) / divs; +verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps) { var its = []; var ts = [its]; - var u = crv.knots[0]; + var u = startU; var degree1 = crv.degree + 1; - var _g = 0; - while(_g < degree1) { - var i = _g++; - its.push(verb_eval_Eval.curvePoint(crv,u)); - u += t; + 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 prev; - var _g1 = 1; + 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[i1 - 1]; - var _g2 = 1; + prev = ts[i2 - 1]; + var _g21 = 1; var _g11 = prev.length; - while(_g2 < _g11) { - var j = _g2++; + while(_g21 < _g11) { + var j = _g21++; its.push(verb_core_Vec.sub(prev[j],prev[j - 1])); } } @@ -4355,20 +4337,20 @@ verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs, } front = _g4; var k; - var _g21 = 0; - var _g14 = divs + 1 - degree1; - while(_g21 < _g14) { - var i2 = _g21++; + 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 = front.length - 2 - j1; + k = frlen2 - j1; verb_core_Vec.addMutate(front[k],front[k + 1]); } pts.push(verb_eval_Eval.dehomogenize(front[0])); } - return pts; }; verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); @@ -6937,7 +6919,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 82, className : "verb.exe.WorkerPool", methodName : "processQueue"}); + console.log(error); } _g.processQueue(); }; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 1d2dc1ed..3ce583ed 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -255,12 +255,6 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; -var haxe_Log = function() { }; -$hxClasses["haxe.Log"] = haxe_Log; -haxe_Log.__name__ = ["haxe","Log"]; -haxe_Log.trace = function(v,infos) { - js_Boot.__trace(v,infos); -}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -995,25 +989,6 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; -js_Boot.__unhtml = function(s) { - return s.split("&").join("&").split("<").join("<").split(">").join(">"); -}; -js_Boot.__trace = function(v,i) { - var msg; - if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; - msg += js_Boot.__string_rec(v,""); - if(i != null && i.customParams != null) { - var _g = 0; - var _g1 = i.customParams; - while(_g < _g1.length) { - var v1 = _g1[_g]; - ++_g; - msg += "," + js_Boot.__string_rec(v1,""); - } - } - var d; - if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); -}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1889,7 +1864,7 @@ var verb_Verb = function() { }; $hxClasses["verb.Verb"] = verb_Verb; verb_Verb.__name__ = ["verb","Verb"]; verb_Verb.main = function() { - haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); + console.log("verb 2.0.0"); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -4221,51 +4196,58 @@ verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { var pts = []; var brange; var fraction; - haxe_Log.trace(beziers.map(function(x) { - return x.knots; - }),{ fileName : "Eval.hx", lineNumber : 369, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); + var currentU = crv.knots[0]; + var step = range / divs; + var brange1; + var bsteps; + var nextU; var _g1 = 0; var _g = beziers.length; while(_g1 < _g) { var i = _g1++; - brange = verb_core_ArrayExtensions.last(beziers[i].knots) - beziers[i].knots[0]; - haxe_Log.trace(brange,{ fileName : "Eval.hx", lineNumber : 376, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints", customParams : [range]}); - fraction = Math.ceil(brange / range * divs); - haxe_Log.trace(fraction,{ fileName : "Eval.hx", lineNumber : 378, className : "verb.eval.Eval", methodName : "rationalCurveRegularSamplePoints"}); - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],fraction,pts); - if(i == beziers.length - 1) continue; - pts.pop(); + brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],pts,currentU,step,bsteps + 1); + currentU = nextU + step; } return pts; }; -verb_eval_Eval.rationalBezierCurveRegularSamplePoints = function(crv,divs) { - var pts = []; - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(crv,divs,pts); - return pts; -}; -verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs,pts) { - var t = (verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]) / divs; +verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps) { var its = []; var ts = [its]; - var u = crv.knots[0]; + var u = startU; var degree1 = crv.degree + 1; - var _g = 0; - while(_g < degree1) { - var i = _g++; - its.push(verb_eval_Eval.curvePoint(crv,u)); - u += t; + 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 prev; - var _g1 = 1; + 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[i1 - 1]; - var _g2 = 1; + prev = ts[i2 - 1]; + var _g21 = 1; var _g11 = prev.length; - while(_g2 < _g11) { - var j = _g2++; + while(_g21 < _g11) { + var j = _g21++; its.push(verb_core_Vec.sub(prev[j],prev[j - 1])); } } @@ -4286,20 +4268,20 @@ verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,divs, } front = _g4; var k; - var _g21 = 0; - var _g14 = divs + 1 - degree1; - while(_g21 < _g14) { - var i2 = _g21++; + 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 = front.length - 2 - j1; + k = frlen2 - j1; verb_core_Vec.addMutate(front[k],front[k + 1]); } pts.push(verb_eval_Eval.dehomogenize(front[0])); } - return pts; }; verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); @@ -6868,7 +6850,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 82, className : "verb.exe.WorkerPool", methodName : "processQueue"}); + console.log(error); } _g.processQueue(); }; diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index e2b59ba8..0d2aac22 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -361,54 +361,57 @@ class Eval { public static function rationalCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { + // TODO if the number of steps is less than the degree+1, just evaluate and return as forward differencing won't work + var range = crv.knots.last() - crv.knots[0]; var beziers = Modify.decomposeCurveIntoBeziers( crv ); var pts = []; var brange, fraction; - trace(beziers.map(function(x){return x.knots;})); + var currentU = crv.knots[0]; + var step = range / divs; + var brange, bsteps, nextU; for (i in 0...beziers.length){ - // get the fraction of samples that should be performed in this bezier - brange = beziers[i].knots.last() - beziers[i].knots[0]; - - trace(brange, range); - fraction = Math.ceil( ( brange / range ) * divs ); - trace( fraction ); + brange = beziers[i].knots.last() - currentU; + bsteps = Math.ceil( brange / step ); // + nextU = currentU + bsteps * step; - rationalBezierCurveRegularSamplePointsMutate( beziers[i], fraction, pts ); + if (nextU > beziers[i].knots.last() + Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } - if (i == beziers.length-1) - continue; + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, currentU, step, bsteps + 1 ); - pts.pop(); // remove the last point in the sequence as it will be duped by the next curve + currentU = nextU + step; } return pts; } - private static function rationalBezierCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { - - var pts = []; - rationalBezierCurveRegularSamplePointsMutate( crv, divs, pts ); - return pts; - - } - - private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, divs : Int, pts : Array ) { + private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, + pts : Array, + startU : Float, + step : Float, + numSteps : Int ) { - // get the step size + var its = [], ts = [ its ], u = startU, degree1 = crv.degree+1; - var t = ( crv.knots.last() - crv.knots[0] ) / divs; + if ( numSteps <= crv.degree + 1 ){ + for (i in 0...numSteps){ + pts.push( rationalCurvePoint( crv, u ) ); + u += step; + } + return; + } // initialize forward differencing - var its = [], ts = [its], u = crv.knots[0], degree1 = crv.degree+1; - for (i in 0...degree1){ its.push( curvePoint( crv, u ) ); - u += t; + u += step; } // compute the differences @@ -419,27 +422,31 @@ class Eval { 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 points + // evaluate the intial points for (pt in ts[0]){ pts.push( 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...divs+1-degree1){ + for (i in 0...numSteps-degree1){ // Rright = R + Rdown // compute the new forward difference front for (j in 0...front.length-1){ - k = front.length - 2 - j; // invert + k = frlen2 - j; // invert Vec.addMutate(front[k], front[k+1]); } @@ -447,7 +454,7 @@ class Eval { pts.push(dehomogenize( front[0] )); } - return pts; + } // Compute a regularly spaced grid of derivatives on a non-uniform, rational, B spline surface. Generally, this algorithm diff --git a/test/testEval.js b/test/testEval.js index f6f4938d..fa904d10 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,3586 +7,3585 @@ 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",() => { - it('returns correct result', () => { + 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",() => { - it('returns correct result for degree 2 curve', () => { + 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",() => { - it('return correct results', () => { + 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",() => { - it('returns correct result for simple curve', () => { + 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",() => { - it('returns correct result for simple curve', () => { + 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",() => { - it('returns correct result for two cases', () => { + 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",() => { - it('returns correct results', () => { + it('returns correct results', () => { - // 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]; + // 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] ); + 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] ); + // 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 ); + // length + should.equal( n + 1, N1.length ); + should.equal( degree + 1, N1[0].length ); - }); + }); }); describe("verb.eval.Eval.curveDerivativesGivenN",() => { - it('returns correct result for simple curve', () => { + it('returns correct result for simple curve', () => { - 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 degree = 3 + , n = 3 + , u = 0 + , knots = [0, 0, 0, 0, 1, 1, 1, 1] + , controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ] + , num_derivs = 2 + , crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Eval.curveDerivativesGivenN( n, crv, u, num_derivs ) ; + 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 ); + should.equal( p[0][0], 10 ); + should.equal( p[0][1], 0 ); + should.equal( p[1][0] / p[1][1], 1 ); - }); + }); }); describe("verb.eval.Eval.curveDerivatives",() => { - it('returns correct result for simple curve', () => { + it('returns correct result for simple curve', () => { - // 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 ); + // This needs to be tested better + var degree = 3 + , u = 0 + , knots = [0, 0, 0, 0, 1, 1, 1, 1] + , controlPoints = [ [10, 0], [20, 10], [30, 20], [50, 50] ] + , num_derivs = 2 + , crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Eval.curveDerivatives( crv, u, num_derivs ) ; + var p = verb.eval.Eval.curveDerivatives( crv, u, num_derivs ) ; - should.equal( p[0][0], 10 ); - should.equal( p[0][1], 0 ); - should.equal( p[1][0] / p[1][1], 1 ); + 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",() => { - it('returns correct result for simple surface', () => { + it('returns correct result for simple surface', () => { - // 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; + // This needs to be tested better + var degreeU = 3 + , degreeV = 3 + , knotsU = [0, 0, 0, 0, 1, 1, 1, 1] + , knotsV = [0, 0, 0, 0, 1, 1, 1, 1] + , controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ) + , n = 3 + , m = 3; - var p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 0, 0 ); + var p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 0, 0 ); - should.equal( p[0], 0 ); - should.equal( p[1], 0 ); - should.equal( p[2], 50 ); + should.equal( p[0], 0 ); + should.equal( p[1], 0 ); + should.equal( p[2], 50 ); - p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 1, 1 ); + p = verb.eval.Eval.surfacePointGivenNM( n, m, surface, 1, 1 ); - should.equal( p[0], 30 ); - should.equal( p[1], -30 ); - should.equal( p[2], 0 ); + should.equal( p[0], 30 ); + should.equal( p[1], -30 ); + should.equal( p[2], 0 ); - }); + }); }); describe("verb.eval.Eval.surfacePoint",() => { - it('returns correct result for simple surface', () => { + it('returns correct result for simple surface', () => { - // 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 ); + // This needs to be tested better + var degreeU = 3 + , degreeV = 3 + , knotsU = [0, 0, 0, 0, 1, 1, 1, 1] + , knotsV = [0, 0, 0, 0, 1, 1, 1, 1] + , controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ], + [ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 0] ] ] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); + var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); - should.equal( p[0], 0 ); - should.equal( p[1], 0 ); - should.equal( p[2], 50 ); + should.equal( p[0], 0 ); + should.equal( p[1], 0 ); + should.equal( p[2], 50 ); - p = verb.eval.Eval.surfacePoint( surface, 1, 1 ); + p = verb.eval.Eval.surfacePoint( surface, 1, 1 ); - should.equal( p[0], 30 ); - should.equal( p[1], -30 ); - should.equal( p[2], 0 ); + should.equal( p[0], 30 ); + should.equal( p[1], -30 ); + should.equal( p[2], 0 ); - }); + }); - it('returns correct result for another simple surface', () => { + it('returns correct result for another simple surface', () => { - var degreeU = 1 - , degreeV = 3 - , knotsU = [0, 0, 1, 1 ] - , knotsV = [0, 0, 0, 0, 1, 1, 1, 1] - , controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], - [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ] ] - , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + var degreeU = 1 + , degreeV = 3 + , knotsU = [0, 0, 1, 1 ] + , knotsV = [0, 0, 0, 0, 1, 1, 1, 1] + , controlPoints = [ [ [0, 0, 50], [10, 0, 0], [20, 0, 0], [30, 0, 0] ], + [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] ] ] + , surface = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); - var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); + var p = verb.eval.Eval.surfacePoint( surface, 0, 0 ); - should.equal( p[0], 0 ); - should.equal( p[1], 0 ); - should.equal( p[2], 50 ); + should.equal( p[0], 0 ); + should.equal( p[1], 0 ); + should.equal( p[2], 50 ); - }); + }); }); 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 ); + 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 ); - var p = verb.eval.Eval.surfaceDerivativesGivenNM( n, m, surface, 0, 0, num_derivatives ); - - // 0th derivative with respect to u & v - should.equal( p[0][0][0], 0 ); - should.equal( p[0][0][1], 0 ); - should.equal( p[0][0][2], 0 ); - - // d/du - should.equal( p[0][1][0] / p[0][1][0], 1 ); - should.equal( p[0][1][2], 0 ); - - // d/dv - should.equal( p[1][0][0] , 0 ); - should.equal( p[1][0][1] , -30 ); - should.equal( p[1][0][2] , 0 ); - - // dd/dudv - should.equal( p[1][1][0] , 0 ); - should.equal( p[1][1][1] , 0 ); - should.equal( p[1][1][2] , 0 ); - - }); + }); }); describe("verb.eval.Eval.surfaceDerivatives",() => { - 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 ); + 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 ); - // 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",() => { - it('returns correct results', () => { + 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",() => { - 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] ); - } - } + 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",() => { - 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] ); - } - } + 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] ); + } + } - }); + }); }); describe("verb.eval.Eval.rationalCurvePoint",() => { - it('returns correct result for quarter circle', () => { + 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",() => { - it('returns correct result for cylinder patch', () => { + 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",() => { - it('returns expected results', () => { + it('returns expected results', () => { - // 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.rationalCurveDerivatives( crv, 0, 2); + var p = verb.eval.Eval.rationalCurveDerivatives( crv, 0, 2); - should.equal( p[0][0], 1 ); - should.equal( p[0][1], 0 ); + should.equal( p[0][0], 1 ); + should.equal( p[0][1], 0 ); - should.equal( p[1][0], 0 ); - should.equal( p[1][1], 2 ); + should.equal( p[1][0], 0 ); + should.equal( p[1][1], 2 ); - should.equal( p[2][0], -4 ); - should.equal( p[2][1], 0 ); + should.equal( p[2][0], -4 ); + should.equal( p[2][1], 0 ); - p = verb.eval.Eval.rationalCurveDerivatives( crv, 1, 2); + p = verb.eval.Eval.rationalCurveDerivatives( crv, 1, 2); - 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 ); - }); + }); }); describe("verb.eval.Eval.rationalSurfaceDerivatives",() => { - it('returns expected results', () => { + it('returns expected results', () => { - // 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 ); + // 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 ); - }); + }); }); describe("verb.eval.Eval.rationalCurvePoint",() => { - it('returns correct results for a line', () => { + 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",() => { - it('returns expected results when inserting 1 knot in the middle of a non-rational, cubic b-spline', () => { + 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', () => { + 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', () => { + 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', () => { + 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 cubicInsert(u, r){ + function cubicInsert(u, r){ - var degree = 3 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ] - , new_knots = []; + 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); - } + 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 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 ); + 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); }); + 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 multiple knots in the middle of a non-rational, cubic b-spline', () => { + 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(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(0.5, 1); + cubicInsert(0.5, 2); + cubicInsert(0.5, 3); + cubicInsert(0.5, 4); - cubicInsert(3, 1); - cubicInsert(3, 2); + cubicInsert(3, 1); + cubicInsert(3, 2); - }); + }); }); describe("verb.eval.Divide.curveSplit",() => { - function cubicSplit(u){ + function cubicSplit(u){ - var degree = 3 - , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]; + var degree = 3 + , knots = [ 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 ]; - var controlPoints = []; - for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0, 1]); + var controlPoints = []; + for (var i = 0; i < 8; i++) controlPoints.push([i, 0, 0, 1]); - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var after = verb.eval.Divide.curveSplit( crv, u ); + var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var after = verb.eval.Divide.curveSplit( crv, u ); - for (var i = 0; i < degree + 1; i++ ){ - var d = after[0].knots.length - (degree+1); - after[0].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE); - } + for (var i = 0; i < degree + 1; i++ ){ + var d = after[0].knots.length - (degree+1); + after[0].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE); + } - for (var i = 0; i < degree + 1; i++){ - var d = 0; - after[1].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE); - } + for (var i = 0; i < degree + 1; i++){ + var d = 0; + after[1].knots[d+i].should.be.approximately(u, verb.core.Constants.TOLERANCE); + } - // a point evaluated on each curve is the same - var p0 = verb.eval.Eval.curvePoint( after[0], after[0].knots[ after[0].knots.length-1] ); - var p1 = verb.eval.Eval.curvePoint( after[1], after[1].knots[ 0] ); + // 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 splitting a non-rational, cubic b-spline', () => { + it('returns expected results when splitting a non-rational, cubic b-spline', () => { - cubicSplit( 0.5 ); - cubicSplit( 3.5 ); + cubicSplit( 0.5 ); + cubicSplit( 3.5 ); - }); + }); }); describe("verb.eval.Analyze.knotMultiplicities",() => { - it('is correct for a basic example', () => { + it('is correct for a basic example', () => { - var res = verb.eval.Analyze.knotMultiplicities( [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3] ); + var res = verb.eval.Analyze.knotMultiplicities( [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3] ); - res.length.should.be.equal( 5 ); + res.length.should.be.equal( 5 ); - res[0].knot.should.be.equal( 0 ); - res[0].mult.should.be.equal( 4 ); + res[0].knot.should.be.equal( 0 ); + res[0].mult.should.be.equal( 4 ); - res[1].knot.should.be.equal( 1 ); - res[1].mult.should.be.equal( 2 ); + res[1].knot.should.be.equal( 1 ); + res[1].mult.should.be.equal( 2 ); - res[2].knot.should.be.equal( 2 ); - res[2].mult.should.be.equal( 3 ); + res[2].knot.should.be.equal( 2 ); + res[2].mult.should.be.equal( 3 ); - res[3].knot.should.be.equal( 3 ); - res[3].mult.should.be.equal( 1 ); + res[3].knot.should.be.equal( 3 ); + res[3].mult.should.be.equal( 1 ); - res[4].knot.should.be.equal( 3.3 ); - res[4].mult.should.be.equal( 1 ); + res[4].knot.should.be.equal( 3.3 ); + res[4].mult.should.be.equal( 1 ); - }); + }); }); 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('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('is correct for empty array', () => { - verb.core.Mat.transpose([]).should.eql( [] ); - }); + it('is correct for empty array', () => { + verb.core.Mat.transpose([]).should.eql( [] ); + }); }); 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 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 ); + 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); }); + 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); + 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); + 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); + 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', () => { + it('can add knots into a surface in the v direction', () => { - var r = 1; - var u = 0.2; - var new_knots = []; + var r = 1; + var u = 0.2; + var new_knots = []; - for (var i = 0; i < r; i++){ - new_knots.push(u); - } + for (var i = 0; i < r; i++){ + new_knots.push(u); + } - var res = verb.eval.Modify.surfaceKnotRefine( surface, new_knots, true ); + 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); }); + 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); + 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); + 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); + p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE); + p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE); + p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE); - }); + }); }); describe("verb.eval.Divide.surfaceSplit", () => { - 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 ); + var degree = 3 + , knotsV = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1] + , knotsU = [0, 0, 0, 0, 0.5, 1, 1, 1, 1] + , controlPoints = [ + [ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ], + [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ], + [ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ], + [ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ], + [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ] ] + , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); - it('can split a surface in the u direction', () => { + it('can split a surface in the u direction', () => { - var u = 0.2; + var u = 0.2; - var res = verb.eval.Divide.surfaceSplit( surface, u, false ); + var res = verb.eval.Divide.surfaceSplit( surface, u, false ); - res[0].controlPoints.forEach(function(cp){ should.exist(cp); }); - res[0].knotsU.forEach(function(cp){ should.exist(cp); }); - res[0].knotsV.forEach(function(cp){ should.exist(cp); }); - should.exist( res[0].degreeU ); - should.exist( res[0].degreeV ); + res[0].controlPoints.forEach(function(cp){ should.exist(cp); }); + res[0].knotsU.forEach(function(cp){ should.exist(cp); }); + res[0].knotsV.forEach(function(cp){ should.exist(cp); }); + should.exist( res[0].degreeU ); + should.exist( res[0].degreeV ); - res[1].controlPoints.forEach(function(cp){ should.exist(cp); }); - res[1].knotsU.forEach(function(cp){ should.exist(cp); }); - res[1].knotsV.forEach(function(cp){ should.exist(cp); }); - should.exist( res[1].degreeU ); - should.exist( res[1].degreeV ); + res[1].controlPoints.forEach(function(cp){ should.exist(cp); }); + res[1].knotsU.forEach(function(cp){ should.exist(cp); }); + res[1].knotsV.forEach(function(cp){ should.exist(cp); }); + should.exist( res[1].degreeU ); + should.exist( res[1].degreeV ); - var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); - var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); + var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); + var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); - p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE); - p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE); - p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE); + p0[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 = 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); + p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE); + p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE); + p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE); - }); + }); - it('can split a surface in the v direction', () => { + it('can split a surface in the v direction', () => { - var u = 0.2; + var u = 0.2; - var res = verb.eval.Divide.surfaceSplit( surface, u, true ); + var res = verb.eval.Divide.surfaceSplit( surface, u, true ); - res[0].controlPoints.forEach(function(cp){ should.exist(cp); }); - res[0].knotsU.forEach(function(cp){ should.exist(cp); }); - res[0].knotsV.forEach(function(cp){ should.exist(cp); }); - should.exist( res[0].degreeU ); - should.exist( res[0].degreeV ); + res[0].controlPoints.forEach(function(cp){ should.exist(cp); }); + res[0].knotsU.forEach(function(cp){ should.exist(cp); }); + res[0].knotsV.forEach(function(cp){ should.exist(cp); }); + should.exist( res[0].degreeU ); + should.exist( res[0].degreeV ); - res[1].controlPoints.forEach(function(cp){ should.exist(cp); }); - res[1].knotsU.forEach(function(cp){ should.exist(cp); }); - res[1].knotsV.forEach(function(cp){ should.exist(cp); }); - should.exist( res[1].degreeU ); - should.exist( res[1].degreeV ); + res[1].controlPoints.forEach(function(cp){ should.exist(cp); }); + res[1].knotsU.forEach(function(cp){ should.exist(cp); }); + res[1].knotsV.forEach(function(cp){ should.exist(cp); }); + should.exist( res[1].degreeU ); + should.exist( res[1].degreeV ); - var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); - var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); + var p0 = verb.eval.Eval.surfacePoint( surface, 0.1, 0.1 ); + var p1 = verb.eval.Eval.surfacePoint( res[0], 0.1, 0.1); - p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE); - p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE); - p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE); + p0[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 = 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); + p0[0].should.be.approximately(p1[0], verb.core.Constants.TOLERANCE); + p0[1].should.be.approximately(p1[1], verb.core.Constants.TOLERANCE); + p0[2].should.be.approximately(p1[2], verb.core.Constants.TOLERANCE); - }); + }); }); describe("verb.eval.Eval.rationalCurveRegularSample",() => { - it('should return 10 samples when asked to', () => { + it('should return 10 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 ); + var degree = 2 + , knots = [0, 0, 0, 1, 1, 1 ] + , controlPoints = [ [1, 0, 0, 1], [1, 1, 0, 1], [0, 2, 0, 2] ] + , numSamples = 10 + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Tess.rationalCurveRegularSample( curve, numSamples); + var p = verb.eval.Tess.rationalCurveRegularSample( curve, numSamples); - should.equal(p.length, 10); + should.equal(p.length, 10); - p.map( function(e){ e.length.should.be.equal(3); }); + p.map( function(e){ e.length.should.be.equal(3); }); - }); + }); }); describe("verb.eval.Eval.threePointsAreFlat",() => { - it('should identify flat line by returning true', () => { + it('should identify flat line by returning true', () => { - // this represents a single quarter arc, using a rational bezier curve - var p1 = [0,0,0], - p2 = [0,2,0], - p3 = [0,4,0]; + // this represents a single quarter arc, using a rational bezier curve + var p1 = [0,0,0], + p2 = [0,2,0], + p3 = [0,4,0]; - should.equal(true, verb.core.Trig.threePointsAreFlat(p1,p2,p3,1e-5)); + should.equal(true, verb.core.Trig.threePointsAreFlat(p1,p2,p3,1e-5)); - }); + }); }); describe("verb.eval.Tess.rationalCurveAdaptiveSample",() => { - it('returns two end points for a line', () => { + it('returns two end points for a line', () => { - 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 degree = 1 + , knots = [0, 0, 1, 1] + , controlPoints = [ [0, 0, 0, 1], [10, 0, 0, 1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5); + var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5); - should.equal(p[0][0], 0); - should.equal(p[1][0], 10); + should.equal(p[0][0], 0); + should.equal(p[1][0], 10); - p.map( function(e){ e.length.should.be.equal(3); }); + p.map( function(e){ e.length.should.be.equal(3); }); - }); + }); - it('returns all the control points for a degree 1 curve', () => { + it('returns all the control points for a degree 1 curve', () => { - var degree = 1 - , knots = [0, 0, 0.25, 0.5, 0.75, 1, 1] - , controlPoints = [ [0, 0, 0, 1], [10, 10, 0, 1], [14, 20, 0, 1], [10, 32, 4, 1], [12, 16, 22, 1]] - , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var degree = 1 + , knots = [0, 0, 0.25, 0.5, 0.75, 1, 1] + , controlPoints = [ [0, 0, 0, 1], [10, 10, 0, 1], [14, 20, 0, 1], [10, 32, 4, 1], [12, 16, 22, 1]] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-5); + 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.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); }); + p.map( function(e){ e.length.should.be.equal(3); }); - }); + }); - it('makes more points for an arc', () => { + it('makes more points for an arc', () => { - 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 degree = 2 + , knots = [0, 0, 0, 1, 1, 1 ] + , v = Math.sqrt(2) / 2 + , controlPoints = [ [1, 0, 0, 1], [v, v, 0, v], [0, 1, 0, 1] ] + , curve = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-8, true); - var p2 = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-4, true); + var p = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-8, true); + var p2 = verb.eval.Tess.rationalCurveAdaptiveSample( curve, 1e-4, true); - var prev = - 1e-8; - for (var i = 0; i < p.length; i++){ - p[i][0].should.be.above(prev); - p[i][0].should.be.within(-1e-8, 1 + 1e-8); - prev = p[i][0]; - } + var prev = - 1e-8; + for (var i = 0; i < p.length; i++){ + p[i][0].should.be.above(prev); + p[i][0].should.be.within(-1e-8, 1 + 1e-8); + prev = p[i][0]; + } - p.should.be.instanceof(Array).and.not.have.lengthOf(0); - p2.should.be.instanceof(Array).and.not.have.lengthOf(0); - p.should.be.instanceof(Array).and.not.have.lengthOf(p2.length); + p.should.be.instanceof(Array).and.not.have.lengthOf(0); + p2.should.be.instanceof(Array).and.not.have.lengthOf(0); + p.should.be.instanceof(Array).and.not.have.lengthOf(p2.length); - should.equal(p[p.length-1][0], 1.0); - should.equal(p2[p2.length-1][0], 1.0); + should.equal(p[p.length-1][0], 1.0); + should.equal(p2[p2.length-1][0], 1.0); - p.map( function(e){ e.length.should.be.equal(4); }); - p2.map( function(e){ e.length.should.be.equal(4); }); + p.map( function(e){ e.length.should.be.equal(4); }); + p2.map( function(e){ e.length.should.be.equal(4); }); - }); + }); }); describe("verb.eval.Tess.rationalSurfaceAdaptive",() => { - function getComplexSurface(){ + 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] ]; + 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); + pts = verb.eval.Eval.homogenize2d(pts, wts); - var srfObj = { - degreeU : degree, - degreeV : degree, - knotsU : knots, - knotsV : knots, - controlPoints : pts - }; + var srfObj = { + degreeU : degree, + degreeV : degree, + knotsU : knots, + knotsV : knots, + controlPoints : pts + }; - return srfObj; - } + return srfObj; + } - it('produces a mesh from a divided surface', () => { + it('produces a mesh from a divided surface', () => { - var srf = getComplexSurface(); + var srf = getComplexSurface(); - var mesh = verb.eval.Tess.rationalSurfaceAdaptive( srf, { minDivsU: 1, minDivsV: 4 } ); + var mesh = verb.eval.Tess.rationalSurfaceAdaptive( srf, { minDivsU: 1, minDivsV: 4 } ); - mesh.faces.length.should.be.greaterThan( 8 ); - mesh.points.forEach(function(x){ x.length.should.be.equal( 3 ); }) - mesh.points.length.should.be.equal( mesh.normals.length ); - mesh.uvs.length.should.be.equal( mesh.normals.length ); + mesh.faces.length.should.be.greaterThan( 8 ); + mesh.points.forEach(function(x){ x.length.should.be.equal( 3 ); }) + mesh.points.length.should.be.equal( mesh.normals.length ); + mesh.uvs.length.should.be.equal( mesh.normals.length ); - }); + }); }); describe("verb.eval.Make.ellipseArc",() => { - it('returns correct result for unit arc from 0 to 90 deg', () => { + 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 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); + 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 ); + // the typical parametric rep of an ellipse + var xmid = rx * Math.cos( Math.PI / 4 ) + , ymid = ry * Math.sin( Math.PI / 4 ); - var p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5); + 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[0].should.be.approximately( xmid, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p = verb.eval.Eval.rationalCurvePoint( ellipse, 1); + p = verb.eval.Eval.rationalCurvePoint( ellipse, 1); - p[0].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p[1].should.be.approximately( ry, verb.core.Constants.EPSILON ); - p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[0].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( ry, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0); + p = 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 ); + p[0].should.be.approximately( rx, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - }); + }); - it('returns correct result for unit arc from 0 to 90 deg', () => { + 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 center = [0,0,0] + , rx = 5 + , ry = 1 + , x = [rx,0,0] + , y = [0,ry,0] + , start = 0 + , end = Math.PI / 2; - var arc = verb.eval.Make.ellipseArc(center, x, y, start, end); + var arc = verb.eval.Make.ellipseArc(center, x, y, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 1); + 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 ); + p[0].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( ry, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - }); + }); - it('returns correct result for unit arc from 45 to 135 deg', () => { + it('returns correct result for unit arc from 45 to 135 deg', () => { - 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 center = [0,0,0] + , rx = 1 + , ry = 10 + , x = [rx,0,0] + , y = [0,ry,0] + , start = Math.PI/4 + , end = 3 * Math.PI/4; - var arc = verb.eval.Make.ellipseArc(center, x, y, start, end); + var arc = verb.eval.Make.ellipseArc(center, x, y, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 1); + var p = verb.eval.Eval.rationalCurvePoint( arc, 1); - // the typical parametric rep of an ellipse - var xmid = rx * Math.cos( 3 * Math.PI / 4 ) - , ymid = ry * Math.sin( 3 * Math.PI / 4 ); + // 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 ); + p[0].should.be.approximately( xmid, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - }); + }); - it('returns correct result for complete ellipse', () => { + it('returns correct result for complete ellipse', () => { - var center = [0,0,0] - , rx = 1 - , ry = 10 - , x = [rx,0,0] - , y = [0,ry,0] - , start = 0 - , end = Math.PI * 2; + var center = [0,0,0] + , rx = 1 + , ry = 10 + , x = [rx,0,0] + , y = [0,ry,0] + , start = 0 + , end = Math.PI * 2; - var ellipse = verb.eval.Make.ellipseArc(center, x, y, start, end); + 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 ); + // 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); + var p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.125); - p[0].should.be.approximately( xmid, verb.core.Constants.EPSILON ); - p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON ); - p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[0].should.be.approximately( xmid, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( ymid, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.25); + p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.25); - p[0].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p[1].should.be.approximately( ry, verb.core.Constants.EPSILON ); - p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[0].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( ry, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5); + p = verb.eval.Eval.rationalCurvePoint( ellipse, 0.5); - p[0].should.be.approximately( -rx, verb.core.Constants.EPSILON ); - p[1].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[0].should.be.approximately( -rx, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - p = verb.eval.Eval.rationalCurvePoint( ellipse, 0); + p = 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 ); + 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",() => { - it('can extrude a line into a plane', () => { + it('can extrude a line into a plane', () => { - 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 axis = [0,0,1] + , length = 5 + , prof_degree = 1 + , prof_ctrl_pts = [[0,1,0,1], [1,0,0,1]] + , prof_knots = [0,0,1,1] + , profile = new verb.core.NurbsCurveData( prof_degree, prof_knots, prof_ctrl_pts ); - var comps = verb.eval.Make.extrudedSurface(axis, length, profile); + var comps = verb.eval.Make.extrudedSurface(axis, length, profile); - // the first row are the profile control pts - should.equal( 0, comps.controlPoints[2][0][0] ); - should.equal( 1, comps.controlPoints[2][0][1] ); - should.equal( 0, comps.controlPoints[2][0][2] ); + // the first row are the profile control pts + should.equal( 0, comps.controlPoints[2][0][0] ); + should.equal( 1, comps.controlPoints[2][0][1] ); + should.equal( 0, comps.controlPoints[2][0][2] ); - should.equal( 1, comps.controlPoints[2][1][0] ); - should.equal( 0, comps.controlPoints[2][1][1] ); - should.equal( 0, comps.controlPoints[2][1][2] ); + should.equal( 1, comps.controlPoints[2][1][0] ); + should.equal( 0, comps.controlPoints[2][1][1] ); + should.equal( 0, comps.controlPoints[2][1][2] ); - // sample at the center - var p = verb.eval.Eval.rationalSurfacePoint( comps, 0.5, 0.5); + // 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 ); + 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', () => { + it('can extrude a 90 deg quadratic arc bezier curve', () => { - 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 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); + var comps = verb.eval.Make.extrudedSurface(axis, length, profile); - // the first row are the profile control pts - should.equal( 0, comps.controlPoints[2][0][0] ); - should.equal( 1, comps.controlPoints[2][0][1] ); - should.equal( 0, comps.controlPoints[2][0][2] ); - should.equal( 1, comps.controlPoints[2][0][3] ); + // the first row are the profile control pts + should.equal( 0, comps.controlPoints[2][0][0] ); + should.equal( 1, comps.controlPoints[2][0][1] ); + should.equal( 0, comps.controlPoints[2][0][2] ); + should.equal( 1, comps.controlPoints[2][0][3] ); - should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][0] ); - should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][1] ); - should.equal( 0, comps.controlPoints[2][1][2] ); - should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][3] ); + should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][0] ); + should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][1] ); + should.equal( 0, comps.controlPoints[2][1][2] ); + should.equal( Math.sqrt(2) / 2, comps.controlPoints[2][1][3] ); - should.equal( 1, comps.controlPoints[2][2][0] ); - should.equal( 0, comps.controlPoints[2][2][1] ); - should.equal( 0, comps.controlPoints[2][2][2] ); - should.equal( 1, comps.controlPoints[2][2][3] ); + 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); - 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 ); + should.equal( Math.abs( Math.sqrt(2)/2 - p[0]) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( Math.sqrt(2)/2 - p[1]) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( 2.5 - p[2]) < verb.core.Constants.EPSILON, true ); - }); + }); }); describe("verb.eval.Make.arc",() => { - it('returns correct result for unit arc from 0 to 90 deg', () => { + it('returns correct result for unit arc from 0 to 90 deg', () => { - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = 0 - , end = Math.PI/2; + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = 0 + , end = Math.PI/2; - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); + 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 ); + should.equal( Math.abs( p[0] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( p[1] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true ); + should.equal( p[2], 0 ); - }); + }); - it('returns correct result for unit arc from 0 to 45 deg', () => { + it('returns correct result for unit arc from 0 to 45 deg', () => { - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = 0 - , end = Math.PI/4; + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = 0 + , end = Math.PI/4; - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 1); + var p = verb.eval.Eval.rationalCurvePoint( arc, 1); - should.equal( Math.abs( p[0] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( p[1] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true ); - should.equal( p[2], 0 ); + should.equal( Math.abs( p[0] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( p[1] - Math.sqrt(2)/2 ) < verb.core.Constants.EPSILON, true ); + should.equal( p[2], 0 ); - }); + }); - it('returns correct result for unit arc from 45 to 135 deg', () => { + it('returns correct result for unit arc from 45 to 135 deg', () => { - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = Math.PI/4 - , end = 3 * Math.PI/4; + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = Math.PI/4 + , end = 3 * Math.PI/4; - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); + 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 ); + should.equal( Math.abs( p[0] ) < verb.core.Constants.EPSILON, true ); + should.equal( Math.abs( p[1] - 1 ) < verb.core.Constants.EPSILON, true ); + should.equal( p[2], 0 ); - }); + }); - it('returns correct result for unit circle', () => { + it('returns correct result for unit circle', () => { - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 5 - , start = 0 - , end = Math.PI; + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 5 + , start = 0 + , end = Math.PI; - var arc = verb.eval.Make.arc(center, x, y, r, start, end); + var arc = verb.eval.Make.arc(center, x, y, r, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); + 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 ); + p[0].should.be.approximately( 0, verb.core.Constants.EPSILON ); + p[1].should.be.approximately( 5 , verb.core.Constants.EPSILON); + p[2].should.be.approximately( 0, verb.core.Constants.EPSILON ); - }); + }); - it('returns correct result for unit circle', () => { + it('returns correct result for unit circle', () => { - var center = [0,0,0] - , x = [1,0,0] - , y = [0,1,0] - , r = 1 - , start = 0 - , end = Math.PI * 2; + var center = [0,0,0] + , x = [1,0,0] + , y = [0,1,0] + , r = 1 + , start = 0 + , end = Math.PI * 2; - var arc = verb.eval.Make.arc(center, x, y, 1, start, end); + var arc = verb.eval.Make.arc(center, x, y, 1, start, end); - var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); + var p = verb.eval.Eval.rationalCurvePoint( arc, 0.5); - should.equal( Math.abs( p[0] + 1) < verb.core.Constants.EPSILON, true ); - should.equal( Math.abs( p[1] ) < verb.core.Constants.EPSILON, true ); - should.equal( p[2], 0 ); + 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.polyline",() => { - it('can create a polyline with correct structure', () => { + it('can create a polyline with correct structure', () => { - 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 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.polyline( controlPoints ); + var comps = verb.eval.Make.polyline( controlPoints ); - comps.degree.should.equal(degree); - comps.controlPoints.should.eql( verb.eval.Eval.homogenize1d( controlPoints, weights )); + comps.degree.should.equal(degree); + comps.controlPoints.should.eql( verb.eval.Eval.homogenize1d( controlPoints, weights )); - // natural parameterization - for (var i = 1; i < knots.length-1; i++){ - vecShouldBe( controlPoints[i-1], verb.eval.Eval.rationalCurvePoint(comps, comps.knots[i] ) ); - } + // 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",() => { - it('can create a cylinder', () => { + it('can create a cylinder', () => { - var axis = [0,0,1] - , xaxis = [1,0,0] - , base = [0,0,0] - , height = 5 - , radius = 5; + var axis = [0,0,1] + , xaxis = [1,0,0] + , base = [0,0,0] + , height = 5 + , radius = 5; - var comps = verb.eval.Make.cylindricalSurface(axis, xaxis, base, height, radius); + var comps = verb.eval.Make.cylindricalSurface(axis, xaxis, base, height, radius); - comps.degreeU.should.equal(2); - comps.degreeV.should.equal(2); + comps.degreeU.should.equal(2); + comps.degreeV.should.equal(2); - // 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); + 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); + 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[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); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 1, + 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(0, verb.core.Constants.EPSILON); + 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); - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 1); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 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); + 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); - }); + }); }); describe("verb.eval.Make.revolvedSurface",() => { - it('creates a 90 degree cone with the given line for a profile', () => { + it('creates a 90 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 ); + 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 comps = verb.eval.Make.revolvedSurface(profile, center, axis, angle ); + 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] ); + // 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] ); - 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( 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); + 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 ); + 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('creates a 180 degree cone with the given line for a profile', () => { + it('creates a 180 degree cone with the given line for a profile', () => { - 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 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 comps = verb.eval.Make.revolvedSurface( profile, center, axis, angle ); + 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][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][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] ); + 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); + 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 ); + 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 ); - }); + }); - it('creates a 360 degree cone with the given line for a profile', () => { + 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 ); + 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 comps = verb.eval.Make.revolvedSurface( profile, center, axis, angle ); + 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] ); + // 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] ); - 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( 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); + 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, 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, verb.core.Constants.EPSILON ); + p[2].should.be.approximately(0.5, verb.core.Constants.EPSILON ); - }); + }); }); describe("verb.core.Trig.rayClosestPoint",() => { - it('returns correct result for xaxis and 3d pt', () => { + it('returns correct result for xaxis and 3d pt', () => { - var r = [1,0,0] - , o = [0,0,0] - , pt = [3,4,-1]; + var r = [1,0,0] + , o = [0,0,0] + , pt = [3,4,-1]; - var proj = verb.core.Trig.rayClosestPoint(pt, o, r); + var proj = verb.core.Trig.rayClosestPoint(pt, o, r); - 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 ); + 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 ); - }); + }); }); describe("verb.core.Trig.distToRay",() => { - it('returns correct result for xaxis and 3d pt', () => { + it('returns correct result for xaxis and 3d pt', () => { - var r = [1,0,0] - , o = [0,0,0] - , pt = [3,4,-1]; + var r = [1,0,0] + , o = [0,0,0] + , pt = [3,4,-1]; - var d = verb.core.Trig.distToRay(pt, o, r); + var d = verb.core.Trig.distToRay(pt, o, r); - d.should.be.approximately( Math.sqrt( 17 ), verb.core.Constants.TOLERANCE ); + d.should.be.approximately( Math.sqrt( 17 ), verb.core.Constants.TOLERANCE ); - }); + }); }); describe("verb.eval.Make.conicalSurface",() => { - it('can create a cone', () => { + it('can create a cone', () => { - var axis = [0,0,1] - , xaxis = [1,0,0] - , base = [0,0,0] - , height = 5 - , radius = 10; + var axis = [0,0,1] + , xaxis = [1,0,0] + , base = [0,0,0] + , height = 5 + , radius = 10; - var comps = verb.eval.Make.conicalSurface(axis, xaxis, base, height, radius); + var comps = verb.eval.Make.conicalSurface(axis, xaxis, base, height, radius); - comps.degreeU.should.equal(2); - comps.degreeV.should.equal(1); + comps.degreeU.should.equal(2); + comps.degreeV.should.equal(1); - // 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/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[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); + 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(height, 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(height, verb.core.Constants.EPSILON); - p = verb.eval.Eval.rationalSurfacePoint( comps, - 1, - 0); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 1, + 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(height, 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(height, verb.core.Constants.EPSILON); - p = verb.eval.Eval.rationalSurfacePoint( comps, - 0, - 1); + p = verb.eval.Eval.rationalSurfacePoint( comps, + 0, + 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(0, verb.core.Constants.EPSILON); - }); + 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); + }); }); describe("verb.eval.Make.sphericalSurface",() => { - it('can create a unit sphere', () => { + it('can create a unit sphere', () => { - var center = [0,0,0] - , axis = [0,0,1] - , xaxis = [1,0,0] - , radius = 1; + var center = [0,0,0] + , axis = [0,0,1] + , xaxis = [1,0,0] + , radius = 1; - var comps = verb.eval.Make.sphericalSurface(center, axis, xaxis, radius); + var comps = verb.eval.Make.sphericalSurface(center, axis, xaxis, radius); - comps.degreeU.should.equal(2); - comps.degreeV.should.equal(2); + comps.degreeU.should.equal(2); + comps.degreeV.should.equal(2); - // 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(-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.Analyze.rationalBezierCurveArcLength",() => { - it('can compute entire arc length of straight cubic bezier parameterized from 0 to 1', () => { + 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 ); + 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 res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 1 ); + var res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 1 ); - res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); + res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); - }); + }); - it('can compute entire arc length of straight cubic bezier parameterized from 1 to 4', () => { + it('can compute entire arc length of straight cubic bezier parameterized from 1 to 4', () => { - 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 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 res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 4 ); + var res = verb.eval.Analyze.rationalBezierCurveArcLength( curve, 4 ); - res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); + res.should.be.approximately( 3, verb.core.Constants.TOLERANCE ); - }); + }); }); describe("verb.eval.Analyze.rationalCurveArcLength",() => { - it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { + it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { - 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 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 = 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 = 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 ); - res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); + res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); - u += inc; - } - }); + u += inc; + } + }); - it('can compute entire arc length of curved nurbs curve parameterized from 0 to 1', () => { + it('can compute entire arc length of curved nurbs curve parameterized from 0 to 1', () => { - 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 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 ); + var gaussLen = verb.eval.Analyze.rationalCurveArcLength( curve ); - // sample the curve with 10,000 pts - var samples = verb.eval.Tess.rationalCurveRegularSampleRange( curve, 0, 1, 10000 ); + // sample the curve with 10,000 pts + var samples = verb.eval.Tess.rationalCurveRegularSampleRange( curve, 0, 1, 10000 ); - 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 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 }); - gaussLen.should.be.approximately( red.l, 1e-3 ) + gaussLen.should.be.approximately( red.l, 1e-3 ) - }); + }); - it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { + it('can compute entire arc length of straight nurbs curve parameterized from 0 to 2', () => { - 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 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 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 ); + 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 ); + res2.should.be.approximately( verb.core.Vec.norm( pt ), verb.core.Constants.TOLERANCE ); - u += inc; - } + u += inc; + } - }); + }); }); describe("verb.eval.Analyze.rationalBezierCurveParamAtArcLength",() => { - it('can compute parameter at arc length of straight bezier curve', () => { + it('can compute parameter at arc length of straight bezier curve', () => { - 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 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);; + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 3 / (steps-1);; - for (var i = 0; i < steps; i++){ + for (var i = 0; i < steps; i++){ - var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); + var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); - len.should.be.approximately( d, tol ); + len.should.be.approximately( d, tol ); - d += inc; - } + d += inc; + } - }); + }); - it('can compute parameter at arc length of curved bezier curve', () => { + it('can compute parameter at arc length of curved bezier curve', () => { - 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 ); + 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 ); - var tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 3 / (steps-1); + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 3 / (steps-1); - for (var i = 0; i < steps; i++){ + for (var i = 0; i < steps; i++){ - var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); + var u = verb.eval.Analyze.rationalBezierCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalBezierCurveArcLength(curve, u); - len.should.be.approximately( d, tol ); + len.should.be.approximately( d, tol ); - d += inc; - } + d += inc; + } - }); + }); }); describe("verb.eval.Analyze.rationalCurveParamAtArcLength",() => { - it('can compute parameter at arc length of straight NURBS curve', () => { + it('can compute parameter at arc length of 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 ); + 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 tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 4 / (steps-1); + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 4 / (steps-1); - var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, 2, tol); + var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, 2, tol); - for (var i = 0; i < steps; i++){ + for (var i = 0; i < steps; i++){ - var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); + var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); - len.should.be.approximately( d, tol ); + len.should.be.approximately( d, tol ); - d += inc; - } + d += inc; + } - }); + }); - it('can compute parameter at arc length of curved NURBS curve', () => { + it('can compute parameter at arc length of curved NURBS curve', () => { - 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 ); + 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 ); - var tol = 1e-3; - var d = 0; - var steps = 10; - var inc = 3 / (steps-1); + var tol = 1e-3; + var d = 0; + var steps = 10; + var inc = 3 / (steps-1); - for (var i = 0; i < steps; i++){ + for (var i = 0; i < steps; i++){ - var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); - var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); + var u = verb.eval.Analyze.rationalCurveParamAtArcLength(curve, d, tol); + var len = verb.eval.Analyze.rationalCurveArcLength(curve, u); - len.should.be.approximately( d, tol ); + len.should.be.approximately( d, tol ); - d += inc; - } + d += inc; + } - }); + }); }); describe("verb.eval.Divide.rationalCurveByArcLength",() => { - it('can divide a straight NURBS curve', () => { + 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 ) - , d = 0.5 - , tol = 1e-3; + 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); + var res = verb.eval.Divide.rationalCurveByArcLength(curve, d); - var s = 0; - res.forEach(function(u){ + 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; + var pt = verb.eval.Eval.rationalCurvePoint( curve, u.u ); + u.len.should.be.approximately( s, tol ); + s += d; - }); + }); - }); + }); }); describe("verb.eval.Divide.rationalCurveByEqualArcLength",() => { - it('can divide a straight NURBS curve', () => { + 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 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 res = verb.eval.Divide.rationalCurveByEqualArcLength(curve, divs ); - var s = 0; - res.forEach(function(u){ + 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; + var pt = verb.eval.Eval.rationalCurvePoint( curve, u.u ); + u.len.should.be.approximately( s, tol ); + s += d; - }); + }); - }); + }); }); describe("verb.eval.Analyze.rationalCurveClosestParam",() => { - it('can get closest point to a straight curve', () => { + it('can get closest point to a straight 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 ) - , pt = [1,0.2,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 ) + , pt = [1,0.2,0]; - var res = verb.eval.Analyze.rationalCurveClosestParam(curve, [1,0.2,0] ); - var p = verb.eval.Eval.rationalCurvePoint( curve, res ); + 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 ); + vecShouldBe( [1,0,0], p, 1e-3 ); - res = verb.eval.Analyze.rationalCurveClosestParam(curve, [2,0.2,0] ); - p = verb.eval.Eval.rationalCurvePoint( curve, res ); + res = verb.eval.Analyze.rationalCurveClosestParam(curve, [2,0.2,0] ); + p = verb.eval.Eval.rationalCurvePoint( curve, res ); - vecShouldBe( [2,0,0], p, 1e-3 ); + 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 ); + // 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 ); + 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 ); + // 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 ); + vecShouldBe( [4,0,0], p, 1e-3 ); - }); + }); }); describe("verb.eval.Analyze.rationalSurfaceClosestParam",() => { - it('can get closest point to flat bezier patch', () => { + it('can get closest point to flat bezier patch', () => { - 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 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 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 ); + vecShouldBe( [12,-20,0], p, 1e-3 ); - }); + }); }); describe("verb.eval.Intersect.segmentWithTriangle",() => { - it('gives correct result for intersecting axis aligned segment and triangle ', () => { + it('gives correct result for intersecting axis aligned segment and triangle ', () => { - // 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 ]; + // 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 ); + 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); + 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() + 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])))); + 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 ); + 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 ', () => { + it('gives correct result for intersecting axis aligned segment and planar triangle ', () => { - // 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 ]; + // 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 ); + 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); + 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])))); + 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 ); + 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', () => { + it('gives null for non-intersecting segment and triangle', () => { - // line from [5,5,5] to [5,5,-5] - var p0 = [ 5,5,5 ] - , p1 = [ 5,5,4 ] + // 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 ]; + // 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 ); + var res = verb.eval.Intersect.segmentWithTriangle( p0, p1, points, tri ); - (null === res).should.be.true; + (null === res).should.be.true; - }); + }); }); describe("verb.eval.Make.fourPointSurface",() => { - it('can create an inclined plane', () => { + 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', () => { + 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",() => { - it('can intersect two simple lines', () => { + 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', () => { + 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', () => { + 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', () => { + 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",() => { - it('is correct for intersection of 3 basis planes', () => { + 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', () => { + 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', () => { + 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",() => { - it('is correct for intersection of xz and yz planes', () => { + 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', () => { + 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', () => { + 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",() => { - it('is correct for a basic example 1', () => { + 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', () => { + 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', () => { + 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', () => { + 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', () => { + 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', () => { + 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",() => { - it('is correct for a basic example', () => { + 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', () => { + 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",() => { - it('is correct for a basic example', () => { + 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', () => { + 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",() => { - it('gives valid result for two planar lines', () => { + 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', () => { + 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', () => { + 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', () => { + 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",() => { - it('gives valid result for planar surface and line', () => { + 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', () => { + 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', () => { + 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', () => { + 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",() => { - it('gives valid result for planar surface and degree 2 bezier', () => { + 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",() => { - 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', () => { + 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', () => { + 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 ",() => { - it('is correct for a basic example', () => { + 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",() => { - it('is correct for a basic example', () => { + 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",() => { - it('is correct for two intersecting triangles', () => { + 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', () => { + 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', () => { + 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",() => { - it('gives valid result for uniform 3x3x3 cube', () => { + 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",() => { - // 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', () => { - 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', () => { - 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', () => { - 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",() => { - 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', () => { + 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",() => { - 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', () => { + 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",() => { - 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('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",() => { - 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', () => { - 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( 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 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 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 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 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 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 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', () => { + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + verb.eval.Check.isValidNurbsSurfaceData(c); + }); -describe("verb.eval.Check.isValidKnotVector",() => { + 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 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 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 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 incorrect knot vector 0', () => { - verb.eval.Check.isValidKnotVector( [0,0,1,1,1], 2 ).should.be.equal(false); - }); + 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 incorrect knot vector 1', () => { - verb.eval.Check.isValidKnotVector( [0,0,0.5,1,1,1], 2 ).should.be.equal(false); - }); + 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 incorrect knot vector 2', () => { - verb.eval.Check.isValidKnotVector( [0,0,0,1,1,2], 2 ).should.be.equal(false); - }); + 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 incorrect knot vector 3', () => { - verb.eval.Check.isValidKnotVector( [0,0,0,0.5,1,1,2], 2 ).should.be.equal(false); - }); + 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 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 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] ] ]; + + var c = new verb.core.NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); + try { verb.eval.Check.isValidNurbsSurfaceData(c) } catch (e) { done(); } + + }); - 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",() => { +describe("verb.eval.Check.isValidKnotVector",() => { + + 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', () => { + verb.eval.Check.isValidKnotVector( [0,0,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', () => { + verb.eval.Check.isValidKnotVector( [0,0,0,1,1,2], 2 ).should.be.equal(false); + }); - function glancingPlaneCylindricalSurface(){ + it('detects incorrect knot vector 3', () => { + verb.eval.Check.isValidKnotVector( [0,0,0,0.5,1,1,2], 2 ).should.be.equal(false); + }); - var axis = [0,0,1] - , xaxis = [1,0,0] - , base = [0,0,0] - , height = 5 - , radius = 3; + 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); + }); +}); - var srf1 = new verb.geom.CylindricalSurface( axis, xaxis, base, height, radius ); +describe("verb.eval.Intersect.meshes",() => { - var p5 = [5,5,0] - , p6 = [-5,5,0] - , p7 = [-5,-5,0] - , p8 = [5,-5,0]; + function glancingPlaneCylindricalSurface(){ - var srf2 = verb.geom.NurbsSurface.byCorners( p5, p6, p7, p8 ); + var axis = [0,0,1] + , xaxis = [1,0,0] + , base = [0,0,0] + , height = 5 + , radius = 3; - return [srf1, srf2]; + 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]; - function nurbsSurfacePlane(){ + var srf2 = verb.geom.NurbsSurface.byCorners( p5, p6, p7, p8 ); - 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 ); + return [srf1, srf2]; - 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 ); + function nurbsSurfacePlane(){ - return [srf1,srf2]; - } + 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 ); + 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 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 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 ); + var srf2 = new verb.geom.CylindricalSurface( axis, xaxis, base, height, radius ); - return [srf1,srf2]; - } + 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() ); + 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 ); - }); + 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() ); + 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 ); - }); + 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() ); + 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 ); - }); + res.length.should.be.equal( 1 ); + }); }); 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] ); - }); + 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",() => { - 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 ); + 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",() => { - 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', () => { + 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', () => { + 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",() => { - it('is correct for basic example', () => { + 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",() => { - it('provides expected result for linear rail and profile', () => { + 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 ); @@ -3596,7 +3595,7 @@ describe("verb.eval.Make.rationalTranslationalSurface",() => { 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', () => { @@ -3616,15 +3615,15 @@ describe("verb.eval.Make.rationalTranslationalSurface",() => { 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', () => { @@ -3641,23 +3640,23 @@ describe("verb.eval.Make.surfaceIsocurve",() => { }); - it('provides isocurves at expected location in v direction', () => { + 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",() => { @@ -3695,132 +3694,132 @@ describe("verb.eval.Make.surfaceBoundaryCurves",() => { }); 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 ); - }); + 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 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 (TODO: do this more efficiently) + var tess = verb.eval.Tess.rationalCurveAdaptiveSample( crv, 1e-8 ); - 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', () => { - var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 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', () => { + 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] ]; + var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - shouldInterpPoints( pts, 4 ); + shouldInterpPoints( pts, 4 ); - }); + }); - it('can compute valid quadratic interpolating curve for 4 points', () => { + 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] ]; + var pts = [ [0, 0, 0], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; - shouldInterpPoints( pts, 2 ); + shouldInterpPoints( pts, 2 ); - }); + }); - it('can compute valid cubic interpolating curve for 100 points', () => { + it('can compute valid cubic interpolating curve for 100 points', () => { - var pts = []; - for (var i = 0; i < 100; i++){ + 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 ]); + 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', () => { + 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] ]; + 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] ); + 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', () => { + // 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] ]; + // 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] ); + // shouldInterpPointsWithTangents( pts, 2, false, [1,0,0], [0,1,0] ); - // }); + // }); - // it('can compute valid quadratic curve interpolating points and tangents', () => { + // 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] ]; + // 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] ); + // shouldInterpPointsWithTangents( pts, 4, false, [1,0,0], [0,1,0] ); - // }); + // }); }); @@ -3832,13 +3831,13 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { 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], + , 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], @@ -3860,22 +3859,22 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { var complexSurface = getComplexSurface(); - it('returns correct result for complex surface', () => { + it('returns correct result for complex surface', () => { - var p = verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 10, 10 ); + var p = verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 10, 10 ); var ar = []; - var sp = 1 / 10; + var sp = 1 / 10; - var i, j; + 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 ) ) - } - } + 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); @@ -3887,39 +3886,39 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { 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', () => { + 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 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]); + } - var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); + var crv = new verb.core.NurbsCurveData( degree, knots, controlPoints ); - var res = verb.eval.Modify.decomposeCurveIntoBeziers( crv ); + var res = verb.eval.Modify.decomposeCurveIntoBeziers( crv ); - res.length.should.be.equal( 5 ); + res.length.should.be.equal( 5 ); - res.forEach(function(x){ + res.forEach(function(x){ - var u0 = x.knots[0]; + var u0 = x.knots[0]; - var pt0 = verb.eval.Eval.curvePoint( x, u0); - var pt1 = verb.eval.Eval.curvePoint( crv, u0); + 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 ); + ( 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', () => { @@ -3950,8 +3949,8 @@ describe("verb.eval.Eval.rationalCurveRegularSamplePoints",() => { function evalAndCompare(crv){ - var divs = 200; - var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, divs ); + var divs = 100; + var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, divs ); var p2 = []; var sp = 1 / divs; @@ -3967,34 +3966,34 @@ describe("verb.eval.Eval.rationalCurveRegularSamplePoints",() => { } } - it('returns correct result for basic bezier curve', () => { + 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 ); - 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); -// -// }); + }); }); From 14216c3f1b80e7400e4198bfe3e2493dd4a64ad9 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Thu, 29 Oct 2015 01:18:08 -0400 Subject: [PATCH 05/25] Some cleanup --- test/testCore.js | 955 +++++++++++++++++++++++------------------------ 1 file changed, 475 insertions(+), 480 deletions(-) diff --git a/test/testCore.js b/test/testCore.js index 9bc4a3e9..892b41e3 100755 --- a/test/testCore.js +++ b/test/testCore.js @@ -1,10 +1,5 @@ var should = require('should') - , verb = require('../build/js/verb.js'); - -var fs = require('fs'); -var f = fs.readFileSync(process.cwd() + '/build/js/verb.js', 'utf8'); -console.log( f.slice(-300, -1) ); - + , verb = require('../build/js/verb.js'); // necessary for multi-threading verb.exe.WorkerPool.basePath = process.cwd() + "/build/js/"; @@ -12,227 +7,227 @@ 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", () => { - it('should allow array of point arguments', () => { + 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", () => { - it('returns expected results', () => { + 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", () => { - it('returns expected results', () => { + 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", () => { - it('returns expected results', () => { + 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", () => { - it('returns expected results', () => { + 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", () => { - it('BoundingBox.clear', () => { + 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", () => { - it('should return correct value', () => { + 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", () => { - it('should return correct value', () => { + 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", () => { - it('should return 0 when given out of bounds index', () => { + 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", () => { - it('should return 0 when given out of bounds index', () => { + 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", () => { - it('should set initialized to false', () => { + 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", () => { - it('can be instantiated', () => { + 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); - }); + }); }); @@ -240,81 +235,81 @@ function extractUv(x){ return x.uv; } describe("verb.core.AdaptiveRefinementNode.getEdgeCorners", () => { - it('returns expected result for node without children', () => { + 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', () => { + 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', () => { + 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", () => { - it('returns expected result for edge with more vertices on opposite side', () => { + 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', () => { + 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 ] ] ); - }); + }); }); @@ -336,485 +331,485 @@ describe("verb.core.Trig.isPointInPlane", () => { describe("verb.core.AdaptiveRefinementNode.divide", () => { - it('can be called with options.minDepth', () => { + 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', () => { + 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", () => { - it('works for simple case', () => { + 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", () => { - it('works as expected', () => { + 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 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', () => { + 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', () => { + 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', () => { + 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', () => { + 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', () => { + 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', () => { + 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", () => { - it('can solve simple case', () => { + 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', () => { + 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", () => { - it('should return correct result for planar mesh', () => { - - // - // 0 - 1 - // | / \ - // 2 -- 3 - // | \ / - // 4 - 5 - // - - var points = [ [0,0,0], [1,0,0], [0, -1, 0 ], [2, -1, 0], [0, -2, 0], [1, -2, 0] ] - , tris = [ [0,2,1], [1,2,3], [2,4,5], [2,5,3] ] - , mesh = new verb.core.MeshData(tris, points, null, null) - , tri_indices = [0,1,2,3] - , aabb = verb.core.Mesh.makeMeshAabb(mesh, tri_indices); - - should.equal( 2, aabb.max[0] ); - should.equal( 0, aabb.min[0] ); - should.equal( 0, aabb.max[1] ); - should.equal( -2, aabb.min[1] ); - should.equal( 0, aabb.max[2] ); - should.equal( 0, aabb.min[2] ); - - }); - - it('makeMeshAabb should return correct result for non-planar mesh', () => { - - // - // 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('should return correct result for planar mesh', () => { + + // + // 0 - 1 + // | / \ + // 2 -- 3 + // | \ / + // 4 - 5 + // + + var points = [ [0,0,0], [1,0,0], [0, -1, 0 ], [2, -1, 0], [0, -2, 0], [1, -2, 0] ] + , tris = [ [0,2,1], [1,2,3], [2,4,5], [2,5,3] ] + , mesh = new verb.core.MeshData(tris, points, null, null) + , tri_indices = [0,1,2,3] + , aabb = verb.core.Mesh.makeMeshAabb(mesh, tri_indices); + + should.equal( 2, aabb.max[0] ); + should.equal( 0, aabb.min[0] ); + should.equal( 0, aabb.max[1] ); + should.equal( -2, aabb.min[1] ); + should.equal( 0, aabb.max[2] ); + should.equal( 0, aabb.min[2] ); + + }); + + it('makeMeshAabb should return correct result for non-planar mesh', () => { + + // + // 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", () => { - it('should return origin for zeroed triangle', () => { + 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', () => { + 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", () => { - it('should return correct value', () => { + 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", () => { - it('should return correct result with y axis regular array', () => { + 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', () => { + 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", () => { - 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', () => { + 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', () => { + 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", () => { - it('is correct for a basic example', () => { + 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", () => { - 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]); - }); + 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", () => { - it('can handle two empty arrays', () => { - 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', () => { - 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', () => { - 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', () => { - 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([]); + }); }); From 11877af69067ffda09e1f040aad558645e85b854 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Thu, 29 Oct 2015 01:53:19 -0400 Subject: [PATCH 06/25] Some minor perf improvements --- build/js/verb.js | 25 ++++++++++++++++++------- build/js/verbHaxe.js | 25 ++++++++++++++++++------- src/verb/core/Vec.hx | 7 ++++++- src/verb/eval/Eval.hx | 24 ++++++++++++------------ 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index f6318eb4..1ca42392 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -3508,6 +3508,14 @@ verb_core_Vec.subMutate = function(a,b) { 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; @@ -4115,23 +4123,24 @@ verb_eval_Eval.rationalSurfaceDerivatives = function(surface,u,v,numDerivs) { var _g4 = l + 1; while(_g5 < _g4) { var j = _g5++; - verb_core_Vec.subMutate(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++; - verb_core_Vec.subMutate(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++; - verb_core_Vec.addMutate(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]); } - verb_core_Vec.subMutate(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; @@ -4158,7 +4167,8 @@ verb_eval_Eval.rationalCurveDerivatives = function(curve,u,numDerivs) { var i1 = _g3++; 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; }; @@ -4400,7 +4410,8 @@ verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU, } verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1),v2); } - SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],v)); + verb_core_Vec.mulMutate(1 / wders[0][0],v); + SKL[k].push(v); } } rowders.push(SKL); diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 3ce583ed..1d0ef0d2 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -3439,6 +3439,14 @@ verb_core_Vec.subMutate = function(a,b) { 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; @@ -4046,23 +4054,24 @@ verb_eval_Eval.rationalSurfaceDerivatives = function(surface,u,v,numDerivs) { var _g4 = l + 1; while(_g5 < _g4) { var j = _g5++; - verb_core_Vec.subMutate(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++; - verb_core_Vec.subMutate(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++; - verb_core_Vec.addMutate(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]); } - verb_core_Vec.subMutate(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; @@ -4089,7 +4098,8 @@ verb_eval_Eval.rationalCurveDerivatives = function(curve,u,numDerivs) { var i1 = _g3++; 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; }; @@ -4331,7 +4341,8 @@ verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU, } verb_core_Vec.subMulMutate(v,verb_core_Binomial.get(k,i1),v2); } - SKL[k].push(verb_core_Vec.mul(1 / wders[0][0],v)); + verb_core_Vec.mulMutate(1 / wders[0][0],v); + SKL[k].push(v); } } rowders.push(SKL); diff --git a/src/verb/core/Vec.hx b/src/verb/core/Vec.hx index 02987170..dbe03a9d 100644 --- a/src/verb/core/Vec.hx +++ b/src/verb/core/Vec.hx @@ -174,6 +174,11 @@ class Vec { 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; @@ -302,4 +307,4 @@ class Vec { return result; } -} \ No newline at end of file +} diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 0d2aac22..84510e65 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -82,22 +82,23 @@ class Eval { var v = Aders[k][l]; for (j in 1...l+1){ - Vec.subMutate( v, Vec.mul( Binomial.get(l, j) * wders[0][j], SKL[k][l-j] ) ); + Vec.subMulMutate( v, Binomial.get(l, j) * wders[0][j], SKL[k][l-j] ); } for (i in 1...k+1){ - Vec.subMutate( v, Vec.mul( Binomial.get(k, i) * wders[i][0], SKL[k-i][l] ) ); + 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.addMutate( v2, Vec.mul( Binomial.get(l, j) * wders[i][j], SKL[k-i][l-j] ) ); + Vec.addMulMutate( v2, Binomial.get(l, j) * wders[i][j], SKL[k-i][l-j] ); } - Vec.subMutate( 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 } } @@ -152,7 +153,9 @@ class Eval { 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; @@ -361,8 +364,6 @@ class Eval { public static function rationalCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { - // TODO if the number of steps is less than the degree+1, just evaluate and return as forward differencing won't work - var range = crv.knots.last() - crv.knots[0]; var beziers = Modify.decomposeCurveIntoBeziers( crv ); var pts = []; @@ -453,8 +454,6 @@ class Eval { // add the new pt pts.push(dehomogenize( front[0] )); } - - } // Compute a regularly spaced grid of derivatives on a non-uniform, rational, B spline surface. Generally, this algorithm @@ -515,8 +514,9 @@ class Eval { 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 } } From 5496383276ff5d8b72ba2f6062fa76ddd6feae2d Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Thu, 29 Oct 2015 02:14:45 -0400 Subject: [PATCH 07/25] Stub out new regular surface sampling algo --- benchmark/regularSurfaceSampling.js | 79 +++++++++++++++-------------- build/js/verb.js | 13 +++++ build/js/verbHaxe.js | 13 +++++ src/verb/eval/Eval.hx | 17 +++++++ 4 files changed, 84 insertions(+), 38 deletions(-) diff --git a/benchmark/regularSurfaceSampling.js b/benchmark/regularSurfaceSampling.js index cee3edb7..e0ea5e96 100644 --- a/benchmark/regularSurfaceSampling.js +++ b/benchmark/regularSurfaceSampling.js @@ -1,34 +1,34 @@ var Benchmark = require('benchmark') - , verb = require('../build/js/verb.js'); + , 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 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(); @@ -36,20 +36,23 @@ var complexSurface = getComplexSurface(); module.exports = { name: 'Regular surface sampling', tests: { - 'surfaceRegularSample (80 x 80)': function() { - verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 80, 80 ); + 'surfaceRegularSamplePoints2 (80 x 80)': function() { + verb.eval.Eval.surfaceRegularSamplePoints2( complexSurface, 80, 80 ); + }, + 'surfaceRegularSamplePoints (80 x 80)': function() { + verb.eval.Eval.surfaceRegularSamplePoints( 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 ) ) - } - } + 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/build/js/verb.js b/build/js/verb.js index 1ca42392..0256252e 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -4484,6 +4484,19 @@ verb_eval_Eval.surfaceRegularSamplePoints = function(surface,divsU,divsV) { } return pts; }; +verb_eval_Eval.surfaceRegularSamplePoints2 = 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_Eval.rationalCurveRegularSamplePoints(iso,divsV)); + u += t; + } + 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; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 1d0ef0d2..b4363761 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -4415,6 +4415,19 @@ verb_eval_Eval.surfaceRegularSamplePoints = function(surface,divsU,divsV) { } return pts; }; +verb_eval_Eval.surfaceRegularSamplePoints2 = 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_Eval.rationalCurveRegularSamplePoints(iso,divsV)); + u += t; + } + 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; diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 84510e65..b87ac804 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -636,6 +636,23 @@ class Eval { return pts; } + public static function surfaceRegularSamplePoints2( 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( rationalCurveRegularSamplePoints( iso, divsV ) ); + u += t; + } + + return pts; + } + private static function regularlySpacedBasisFunctions( degree : Int, knots : KnotArray, divs : Int ) : Pair, Array>> { var n : Int = knots.length - degree - 2; From e41d3015bf7da65db9124b1ceae173ba56c73060 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Tue, 10 Nov 2015 15:15:45 -0500 Subject: [PATCH 08/25] Use spaces in code, rather than tabs --- Gruntfile.js | 3 +- build/js/verb.js | 73 ++ build/js/verbHaxe.js | 73 ++ examples/curveStepLength.html | 74 ++ src/verb/Verb.hx | 6 +- src/verb/core/ArrayExtensions.hx | 42 +- src/verb/core/Binomial.hx | 30 +- src/verb/core/BoundingBox.hx | 74 +- src/verb/core/Constants.hx | 8 +- src/verb/core/Data.hx | 80 +- src/verb/core/Intersections.hx | 98 +-- src/verb/core/KdTree.hx | 106 +-- src/verb/core/LazyCurveBoundingBoxTree.hx | 28 +- src/verb/core/LazyMeshBoundingBoxTree.hx | 28 +- src/verb/core/LazyPolylineBoundingBoxTree.hx | 28 +- src/verb/core/LazySurfaceBoundingBoxTree.hx | 44 +- src/verb/core/Mat.hx | 99 +-- src/verb/core/Mesh.hx | 60 +- src/verb/core/MeshBoundingBoxTree.hx | 30 +- src/verb/core/Minimizer.hx | 116 +-- src/verb/core/Serialization.hx | 8 +- src/verb/core/SurfaceBoundingBoxTree.hx | 44 +- src/verb/core/Trig.hx | 52 +- src/verb/core/Vec.hx | 171 ++-- src/verb/eval/Analyze.hx | 293 +++--- src/verb/eval/Check.hx | 56 +- src/verb/eval/Divide.hx | 64 +- src/verb/eval/Eval.hx | 694 ++++++++------- src/verb/eval/Intersect.hx | 595 +++++++------ src/verb/eval/Make.hx | 396 ++++----- src/verb/eval/Modify.hx | 348 ++++---- src/verb/eval/Tess.hx | 882 ++++++++++--------- src/verb/exe/Dispatcher.hx | 28 +- src/verb/exe/ThreadPool.hx | 278 +++--- src/verb/exe/WorkerPool.hx | 59 +- src/verb/geom/Arc.hx | 44 +- src/verb/geom/BezierCurve.hx | 4 +- src/verb/geom/Circle.hx | 10 +- src/verb/geom/ConicalSurface.hx | 29 +- src/verb/geom/CylindricalSurface.hx | 27 +- src/verb/geom/Ellipse.hx | 8 +- src/verb/geom/EllipseArc.hx | 37 +- src/verb/geom/ExtrudedSurface.hx | 12 +- src/verb/geom/ICurve.hx | 8 +- src/verb/geom/ISurface.hx | 10 +- src/verb/geom/Intersect.hx | 32 +- src/verb/geom/Line.hx | 14 +- src/verb/geom/NurbsCurve.hx | 158 ++-- src/verb/geom/NurbsSurface.hx | 154 ++-- src/verb/geom/RevolvedSurface.hx | 20 +- src/verb/geom/SphericalSurface.hx | 14 +- src/verb/geom/SweptSurface.hx | 12 +- test/testEval.js | 17 +- 53 files changed, 3006 insertions(+), 2672 deletions(-) create mode 100644 examples/curveStepLength.html diff --git a/Gruntfile.js b/Gruntfile.js index c4f8a069..0c847989 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/build/js/verb.js b/build/js/verb.js index 0256252e..2fe827ca 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -4094,6 +4094,79 @@ verb_eval_CurveLengthSample.prototype = { 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.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_Eval.secondForwardDiff(wts); + var pts = verb_eval_Eval.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_Eval.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_Eval.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_Eval.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_Eval.rationalCurveTangent = function(curve,u) { var derivs = verb_eval_Eval.rationalCurveDerivatives(curve,u,1); return derivs[1]; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index b4363761..31355cd2 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -4025,6 +4025,79 @@ verb_eval_CurveLengthSample.prototype = { 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.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_Eval.secondForwardDiff(wts); + var pts = verb_eval_Eval.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_Eval.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_Eval.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_Eval.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_Eval.rationalCurveTangent = function(curve,u) { var derivs = verb_eval_Eval.rationalCurveDerivatives(curve,u,1); return derivs[1]; diff --git a/examples/curveStepLength.html b/examples/curveStepLength.html new file mode 100644 index 00000000..13f50643 --- /dev/null +++ b/examples/curveStepLength.html @@ -0,0 +1,74 @@ + + + + Curve 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..bbed8da7 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.0.0"); + } } \ No newline at end of file diff --git a/src/verb/core/ArrayExtensions.hx b/src/verb/core/ArrayExtensions.hx index 1f3754b0..ca7e8e0c 100644 --- a/src/verb/core/ArrayExtensions.hx +++ b/src/verb/core/ArrayExtensions.hx @@ -13,7 +13,7 @@ class ArrayExtensions { // //* nothing, just mutates the given array - public static function alloc( a : Array, n : Int ){ + public static function alloc(a:Array, n:Int) { if (n < 0) return; while (a.length < n) { a.push(null); @@ -30,7 +30,7 @@ class ArrayExtensions { // //* a reversed copy of the array - public static function reversed(a : Array) : Array { + 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,11 +60,11 @@ 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 { + public static function spliceAndInsert(a:Array, start:Int, end:Int, ele:T):Void { a.splice(start, end); a.insert(start, ele); } @@ -79,10 +79,10 @@ class ArrayExtensions { // //* the left half - public static function left(arr : Array) : Array{ + public static function left(arr:Array):Array { if (arr.length == 0) return []; - var len = Math.ceil( arr.length / 2 ); - return arr.slice( 0, len ); + var len = Math.ceil(arr.length / 2); + return arr.slice(0, len); } //Get the second half of an array, not including the pivot @@ -95,10 +95,10 @@ class ArrayExtensions { // //* the right half - public static function right(arr : Array) : Array{ + public static function right(arr:Array):Array { if (arr.length == 0) return []; - var len = Math.ceil( arr.length / 2 ); - return arr.slice( len ); + var len = Math.ceil(arr.length / 2); + return arr.slice(len); } //Get the second half of an array including the pivot @@ -111,10 +111,10 @@ class ArrayExtensions { // //* the right half - public static function rightWithPivot(arr : Array) : Array{ + public static function rightWithPivot(arr:Array):Array { if (arr.length == 0) return []; - var len = Math.ceil( arr.length / 2 ); - return arr.slice( len-1 ); + var len = Math.ceil(arr.length / 2); + return arr.slice(len - 1); } //Obtain the unique set of elements in an array @@ -129,26 +129,26 @@ 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 []; var uniques = [ arr.pop() ]; - while (arr.length > 0){ + while (arr.length > 0) { 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 ){ - uniques.push( ele ); + if (isUnique) { + uniques.push(ele); } } diff --git a/src/verb/core/Binomial.hx b/src/verb/core/Binomial.hx index 422c482e..85119b80 100644 --- a/src/verb/core/Binomial.hx +++ b/src/verb/core/Binomial.hx @@ -6,7 +6,7 @@ class Binomial { static var memo = new IntMap>(); - public static function get(n : Int, k : Int) : Float { + public static function get(n:Int, k:Int):Float { if (k == 0.0) { return 1.0; } @@ -19,16 +19,16 @@ class Binomial { 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, + 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); continue; @@ -44,7 +44,7 @@ class Binomial { return r; } - public static function get_no_memo(n : Int, k : Int) : Float { + public static function get_no_memo(n:Int, k:Int):Float { if (k == 0) { return 1; } @@ -57,10 +57,10 @@ class Binomial { k = n - k; } - var r : Float = 1, + var r:Float = 1, n_o = n; - for (d in 1...k+1){ + for (d in 1...k + 1) { r *= n--; r /= d; } @@ -68,19 +68,19 @@ class Binomial { return r; } - private static function memo_exists(n : Int, k : Int) : Bool { + 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 { + 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) ) { - memo.set( n, new IntMap() ); + private static function memoize(n, k, val) { + if (!memo.exists(n)) { + memo.set(n, new IntMap()); } - memo.get( n ).set( k, val ); + memo.get(n).set(k, val); } } \ No newline at end of file diff --git a/src/verb/core/BoundingBox.hx b/src/verb/core/BoundingBox.hx index 279cde0e..31484c79 100644 --- a/src/verb/core/BoundingBox.hx +++ b/src/verb/core/BoundingBox.hx @@ -12,8 +12,8 @@ using Lambda; @:expose("core.BoundingBox") class BoundingBox { - var initialized : Bool = false; - var dim : Int = 3; + var initialized:Bool = false; + var dim:Int = 3; //BoundingBox Constructor // @@ -21,17 +21,17 @@ class BoundingBox { // //* Points to add, if desired. Otherwise, will not be initialized until add is called. - public function new( pts : Array = null ) { - if ( pts != null ) { - this.addRange( pts ); + public function new(pts:Array = null) { + if (pts != null) { + this.addRange(pts); } } // The minimum point of the BoundingBox - the coordinates of this point are always <= max. - public var min : Point = null; + public var min:Point = null; // The maximum point of the BoundingBox. The coordinates of this point are always >= min. - public var max : Point = null; + public var max:Point = null; //Create a bounding box initialized with a single element // @@ -43,7 +43,7 @@ class BoundingBox { // //* This BoundingBox for chaining - public function fromPoint( pt ){ + public function fromPoint(pt) { return new BoundingBox( [ pt ] ); } @@ -58,10 +58,8 @@ 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); @@ -70,9 +68,9 @@ class BoundingBox { 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,11 +87,10 @@ 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){ + for (i in 0...l) { this.add(points[i]); } @@ -111,14 +108,13 @@ 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; } - return this.intersects( new BoundingBox([point]), tol ); + return this.intersects(new BoundingBox([point]), tol); } //Determines if two intervals on the real number line intersect @@ -134,7 +130,7 @@ 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 @@ -155,17 +151,17 @@ class BoundingBox { // //* true if the two bounding boxes intersect, otherwise false - public function intersects( bb : BoundingBox, tol : Float = -1 ) : Bool { + public function intersects(bb:BoundingBox, tol:Float = -1):Bool { - if ( !this.initialized || !bb.initialized ) return false; + if (!this.initialized || !bb.initialized) return false; var a1 = min , a2 = max , 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,12 +185,12 @@ 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 ){ + for (i in 0...dim) { var l = this.getAxisLength(i); if (l > max) { max = l; @@ -215,9 +211,9 @@ 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; - return Math.abs( this.min[i] - this.max[i] ); + public function getAxisLength(i:Int):Float { + if (i < 0 || i > this.dim - 1) return 0.0; + return Math.abs(this.min[i] - this.max[i]); } //Compute the boolean intersection of this with another axis-aligned bounding box. If the two @@ -231,23 +227,23 @@ class BoundingBox { // //* The bounding box formed by the intersection or null if there is no intersection. - public function intersect( bb : BoundingBox, tol : Float ) : BoundingBox { + public function intersect(bb:BoundingBox, tol:Float):BoundingBox { - if ( !this.initialized ) return null; + if (!this.initialized) return null; var a1 = min , a2 = max , b1 = bb.min , b2 = bb.max; - if ( !this.intersects( bb, tol ) ) return null; + if (!this.intersects(bb, tol)) return null; var maxbb = [] , minbb = []; - for (i in 0...dim){ - maxbb.push( Math.min( a2[i], b2[i] ) ); - minbb.push( Math.max( a1[i], b1[i] ) ); + for (i in 0...dim) { + maxbb.push(Math.min(a2[i], b2[i])); + minbb.push(Math.max(a1[i], b1[i])); } return new BoundingBox([minbb, maxbb]); diff --git a/src/verb/core/Constants.hx b/src/verb/core/Constants.hx index f355d74a..01702416 100644 --- a/src/verb/core/Constants.hx +++ b/src/verb/core/Constants.hx @@ -7,13 +7,13 @@ package verb.core; class Constants { //The default euclidean distance that identifies whether two points are coincident @:expose("TOLERANCE") - public static var TOLERANCE : Float = 1e-6; - + 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; + public static var EPSILON:Float = 1e-10; //The current version of verb @:expose("VERSION") - public static var VERSION : String = "2.0.0"; + public static var VERSION:String = "2.0.0"; } diff --git a/src/verb/core/Data.hx b/src/verb/core/Data.hx index 3e3b762b..dafd3d2a 100644 --- a/src/verb/core/Data.hx +++ b/src/verb/core/Data.hx @@ -29,10 +29,10 @@ typedef KnotArray = Array; @:expose("core.Plane") class Plane extends SerializableBase { - public var normal : Vector; - public var origin : Point; + public var normal:Vector; + public var origin:Point; - public function new(origin, normal){ + public function new(origin, normal) { this.origin = origin; this.normal = normal; } @@ -43,10 +43,10 @@ class Plane extends SerializableBase { @:expose("core.Ray") class Ray extends SerializableBase { - public var dir : Vector; - public var origin : Point; + 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,20 +58,20 @@ 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; } //integer degree of curve - public var degree : Int; + public var degree:Int; // 2d array of control points, where each control point is an array of length (dim) - public var controlPoints : Array; + public var controlPoints:Array; //array of nondecreasing knot values - public var knots : Array; + public var knots:Array; } @@ -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; @@ -90,20 +90,20 @@ class NurbsSurfaceData extends SerializableBase { } //integer degree of surface in u direction - public var degreeU : Int; + public var degreeU:Int; //integer degree of surface in v direction - public var degreeV : Int; + public var degreeV:Int; //array of nondecreasing knot values in u direction - public var knotsU : KnotArray; + public var knotsU:KnotArray; //array of nondecreasing knot values in v direction - public var knotsV : KnotArray; + public var knotsV:KnotArray; // 2d array of control points, the vertical direction (u) increases from top to bottom, the v direction from left to right, //and where each control point is an array of length (dim) - public var controlPoints : Array>; + public var controlPoints:Array>; } @@ -122,20 +122,20 @@ typedef UV = Array; @:expose("core.MeshData") class MeshData extends SerializableBase { - public var faces : Array; - public var points : Array; - public var normals : Array; - public var uvs : Array; + public var faces:Array; + public var points:Array; + 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([], [], [], []); } } @@ -145,12 +145,12 @@ class MeshData extends SerializableBase { class PolylineData extends SerializableBase { // The points in the polyline - public var points : Array; + public var points:Array; // The parameters of the individual points - public var params : Array; + 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; @@ -173,26 +173,26 @@ class VolumeData extends SerializableBase { } //integer degree in u direction - public var degreeU : Int; + public var degreeU:Int; //integer degree in v direction - public var degreeV : Int; + public var degreeV:Int; //integer degree in w direction - public var degreeW : Int; + public var degreeW:Int; //array of nondecreasing knot values in u direction - public var knotsU : KnotArray; + public var knotsU:KnotArray; //array of nondecreasing knot values in v direction - public var knotsV : KnotArray; + public var knotsV:KnotArray; //array of nondecreasing knot values in w direction - public var knotsW : KnotArray; + public var knotsW:KnotArray; // 3d array of control points, where rows are the u dir, and columns run along the positive v direction, //and where each control point is an array of length (dim) - public var controlPoints : Array>>; + public var controlPoints:Array>>; } @@ -200,10 +200,10 @@ class VolumeData extends SerializableBase { @:expose("core.Pair") class Pair { - public var item0 : T1; - public var item1 : T2; + 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; } @@ -213,10 +213,10 @@ class Pair { @:expose("core.Interval") class Interval { - public var min : T; - public var max : T; + 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..9c860fc9 100644 --- a/src/verb/core/Intersections.hx +++ b/src/verb/core/Intersections.hx @@ -6,18 +6,18 @@ import verb.core.Data; class CurveCurveIntersection { //where the intersection took place - public var point0 : Point; + public var point0:Point; //where the intersection took place on the second curve - public var point1 : Point; + public var point1:Point; //the parameter on the first curve - public var u0 : Float; + public var u0:Float; //the parameter on the second curve - public var u1 : Float; + 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; @@ -28,12 +28,12 @@ class CurveCurveIntersection { @:expose("core.CurveSurfaceIntersection") class CurveSurfaceIntersection { - public var u : Float; - public var uv : UV; - public var curvePoint : Point; - public var surfacePoint : Point; + public var u:Float; + public var uv:UV; + 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; @@ -44,19 +44,19 @@ class CurveSurfaceIntersection { @:expose("core.MeshIntersectionPoint") class MeshIntersectionPoint { - public var uv0 : UV; - public var uv1 : UV; - public var point : Point; + public var uv0:UV; + public var uv1:UV; + public var point:Point; - public var faceIndex0 : Int; - public var faceIndex1 : Int; + public var faceIndex0:Int; + public var faceIndex1:Int; //tags to navigate a segment structure - public var opp : MeshIntersectionPoint = null; - public var adj : MeshIntersectionPoint = null; - public var visited : Bool = false; + public var opp:MeshIntersectionPoint = null; + 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; @@ -68,13 +68,13 @@ class MeshIntersectionPoint { @:expose("core.PolylineMeshIntersection") class PolylineMeshIntersection { - public var point : Point; - public var u : Float; - public var uv : UV; - public var polylineIndex : Int; - public var faceIndex : Int; + public var point:Point; + public var u:Float; + public var uv:UV; + 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; @@ -86,12 +86,12 @@ class PolylineMeshIntersection { @:expose("core.SurfaceSurfaceIntersectionPoint") class SurfaceSurfaceIntersectionPoint { - public var uv0 : UV; - public var uv1 : UV; - public var point : Point; - public var dist : Float; + public var uv0:UV; + public var uv1:UV; + 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; @@ -103,18 +103,18 @@ class SurfaceSurfaceIntersectionPoint { class TriSegmentIntersection { //where the intersection took place - public var point : Point; + public var point:Point; //the u param where u is the axis from v0 to v1 - public var s : Float; + public var s:Float; //the v param where v is the axis from v0 to v2 - public var t : Float; + public var t:Float; //the parameter along the segment - public var p : Float; + 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; @@ -124,11 +124,11 @@ class TriSegmentIntersection { @:expose("core.CurveTriPoint") class CurveTriPoint { - public var u : Float; - public var uv : UV; - public var point : Point; + public var u:Float; + 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; @@ -137,13 +137,13 @@ class CurveTriPoint { class SurfacePoint { - public var uv : UV; - public var point : Point; - public var normal : Point; - public var id : Int; - public var degen : Bool; + public var uv:UV; + public var point:Point; + public var normal:Point; + 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,15 +151,15 @@ 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] ); } } @:expose("core.CurvePoint") class CurvePoint { - public var u : Float; - public var pt : Point; + public var u:Float; + public var pt:Point; public function new(u, pt) { this.u = u; diff --git a/src/verb/core/KdTree.hx b/src/verb/core/KdTree.hx index 1c851947..3fd8a953 100644 --- a/src/verb/core/KdTree.hx +++ b/src/verb/core/KdTree.hx @@ -16,10 +16,10 @@ import verb.core.Data; @:expose("core.KdTree") class KdTree { - private var points : Array>; - private var distanceFunction : Point -> Point -> Float; - private var dim : Int = 3; - private var root : KdNode; + private var points:Array>; + private var distanceFunction:Point -> Point -> Float; + private var dim:Int = 3; + private var root:KdNode; public function new(points, distanceFunction) { this.points = points; @@ -29,17 +29,17 @@ class KdTree { 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); - 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) { return 1; @@ -52,36 +52,36 @@ class KdTree { 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 { + 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){ + for (i in 0...dim) { if (i == node.dimension) { linearPoint[i] = point[i]; } else { @@ -89,7 +89,7 @@ class KdTree { } } - linearDistance = distanceFunction( linearPoint, node.kdPoint.point ); + linearDistance = distanceFunction(linearPoint, node.kdPoint.point); if (node.right == null && node.left == null) { if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek().item1) { @@ -110,7 +110,7 @@ class KdTree { } } - nearestSearch( bestChild ); + nearestSearch(bestChild); if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek().item1) { saveNode(node, ownDistance); @@ -128,15 +128,15 @@ class KdTree { } } - for (i in 0...maxNodes){ + for (i in 0...maxNodes) { bestNodes.push(new Pair, Float>(null, maxDistance)); } - nearestSearch( this.root ); + nearestSearch(this.root); var result = []; - for (i in 0...maxNodes){ + 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)); } @@ -151,22 +151,22 @@ class KdTree { class BinaryHeap { - public var content : Array>; - private var scoreFunction : Pair -> Float; + 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); //Allow it to bubble up. 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. @@ -180,15 +180,15 @@ class BinaryHeap { 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){ + 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. @@ -206,11 +206,11 @@ 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. @@ -225,27 +225,27 @@ class BinaryHeap { //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); - while(true) { + while (true) { //Compute the indices of the child elements. var child2N = (n + 1) * 2; var child1N = child2N - 1; //This is used to store the new position of the element, //if any. var swap = -1; - var child1Score : Float = 0.0; + var child1Score:Float = 0.0; //If the first child exists (is inside the array)... if (child1N < length) { @@ -260,7 +260,7 @@ class BinaryHeap { if (child2N < length) { var child2 = this.content[child2N]; var child2Score = this.scoreFunction(child2); - if (child2Score < (swap == -1 ? elemScore : child1Score)){ + if (child2Score < (swap == -1 ? elemScore : child1Score)) { swap = child2N; } } @@ -271,7 +271,7 @@ class BinaryHeap { this.content[swap] = element; n = swap; } - //Otherwise, we are done. + //Otherwise, we are done. else { break; } @@ -284,12 +284,12 @@ class BinaryHeap { class KdPoint { // The point - public var point : Point; + public var point:Point; // An arbitrary object to attach - public var obj : T; + public var obj:T; - public function new(point, obj){ + public function new(point, obj) { this.point = point; this.obj = obj; } @@ -300,21 +300,21 @@ class KdPoint { class KdNode { // The point itself - public var kdPoint : KdPoint; + public var kdPoint:KdPoint; // The left child - public var left : KdNode; + public var left:KdNode; // The right child - public var right : KdNode; + public var right:KdNode; // The parent of the node - public var parent : KdNode; + public var parent:KdNode; // The dimensionality of the point - public var dimension : Int; + 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..f4b18ce6 100644 --- a/src/verb/core/LazyCurveBoundingBoxTree.hx +++ b/src/verb/core/LazyCurveBoundingBoxTree.hx @@ -10,46 +10,46 @@ import verb.eval.Intersect; class LazyCurveBoundingBoxTree implements IBoundingBoxTree { - var _curve : NurbsCurveData; - var _boundingBox : BoundingBox = null; - var _knotTol : Float; + var _curve:NurbsCurveData; + 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){ + if (knotTol == null) { knotTol = _curve.knots.domain() / 64; } _knotTol = knotTol; } - public function split() : Pair, IBoundingBoxTree> { + 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){ + 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 ){ + 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..ca43ae95 100644 --- a/src/verb/core/LazyMeshBoundingBoxTree.hx +++ b/src/verb/core/LazyMeshBoundingBoxTree.hx @@ -6,11 +6,11 @@ import verb.eval.Intersect; using verb.core.ArrayExtensions; class LazyMeshBoundingBoxTree implements IBoundingBoxTree { - var _mesh : MeshData; - var _faceIndices : Array; - var _boundingBox : BoundingBox = null; + var _mesh:MeshData; + 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 ]; @@ -18,32 +18,32 @@ class LazyMeshBoundingBoxTree implements IBoundingBoxTree { _faceIndices = faceIndices; } - public function split() : Pair, IBoundingBoxTree> { - var as = Mesh.sortTrianglesOnLongestAxis( boundingBox(), _mesh, _faceIndices ) + 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){ - _boundingBox = Mesh.makeMeshAabb( _mesh, _faceIndices ); + 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..f6bfe180 100644 --- a/src/verb/core/LazyPolylineBoundingBoxTree.hx +++ b/src/verb/core/LazyPolylineBoundingBoxTree.hx @@ -5,51 +5,51 @@ import verb.eval.Intersect; class LazyPolylineBoundingBoxTree implements IBoundingBoxTree { - var _interval : Interval; - var _polyline : PolylineData; - var _boundingBox : BoundingBox = null; + var _interval:Interval; + 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); + 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..392f24d7 100644 --- a/src/verb/core/LazySurfaceBoundingBoxTree.hx +++ b/src/verb/core/LazySurfaceBoundingBoxTree.hx @@ -10,21 +10,21 @@ import verb.eval.Intersect; class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { - var _surface : NurbsSurfaceData; - var _boundingBox : BoundingBox = null; - var _splitV : Bool; - var _knotTolU : Float; - var _knotTolV : Float; + var _surface:NurbsSurfaceData; + var _boundingBox:BoundingBox = null; + var _splitV:Bool; + 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){ + if (knotTolU == null) { knotTolU = (surface.knotsU.domain()) / 16; } - if (knotTolV == null){ + if (knotTolV == null) { knotTolV = (surface.knotsV.domain()) / 16; } @@ -32,11 +32,11 @@ class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { _knotTolV = knotTolV; } - public function split() : Pair, IBoundingBoxTree> { - var min : Float; - var max : Float; + public function split():Pair, IBoundingBoxTree> { + var min:Float; + var max:Float; - if (_splitV){ + if (_splitV) { min = _surface.knotsV.first(); max = _surface.knotsV.last(); } else { @@ -47,32 +47,32 @@ class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { var dom = max - min; var pivot = (min + max) / 2.0; //* dom * 0.01 * Math.random(); - var srfs = Divide.surfaceSplit( _surface, pivot, _splitV ); + 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 ){ + 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..a7562bf3 100644 --- a/src/verb/core/Mat.hx +++ b/src/verb/core/Mat.hx @@ -10,7 +10,7 @@ class Mat { // Multiply a `Matrix` by a constant - public static function mul(a : Float, b : Matrix ) : Matrix { + public static function mul(a:Float, b:Matrix):Matrix { return [ for (i in 0...b.length) Vec.mul(a, b[i]) ]; } @@ -18,32 +18,32 @@ class Mat { // // 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,67 +55,67 @@ class Mat { // Add two matrices - public static function add(a : Matrix, b : Matrix ) : Matrix { + 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 { + 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 { + 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 { + 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 { + public static function identity(n:Int):Matrix { var zeros = Vec.zeros2d(n, n); - for (i in 0...n){ zeros[i][i] = 1.0; } + for (i in 0...n) { zeros[i][i] = 1.0; } return zeros; } // Transpose a matrix - public static function transpose(a : Array>) : Array> { + 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] ] ]; + 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 n = LU.length; var x = b.copy(); - var P = LUP.P; + 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) { tmp = x[i]; @@ -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; } @@ -150,24 +150,24 @@ class Mat { // Based on methods from numeric.js - private static function LU( A : Matrix ) : LUDecomp { + private static function LU(A:Matrix):LUDecomp { var abs = Math.abs; 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; + 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]); - j = k+1; - while (j < n){ + j = k + 1; + while (j < n) { absAjk = Math.abs(A[j][k]); if (max < absAjk) { max = absAjk; @@ -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; } @@ -217,9 +217,10 @@ class Mat { private class LUDecomp { - public var LU : Matrix; - public var P : Array; - public function new( lu : Matrix, p : Array ){ + public var LU:Matrix; + public var 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..3bda1e98 100644 --- a/src/verb/core/Mesh.hx +++ b/src/verb/core/Mesh.hx @@ -22,16 +22,16 @@ class Mesh { //* a normal vector represented by an array of length 3 // - public static function getTriangleNorm( points : Array, tri : Tri ) : Point { + public static function getTriangleNorm(points:Array, tri:Tri):Point { var v0 = points[ tri[0] ] , v1 = points[ tri[1] ] , v2 = points[ tri[2] ] - , u = Vec.sub( v1, v0 ) - , v = Vec.sub( v2, v0 ) - , n = Vec.cross( u, v ); + , u = Vec.sub(v1, v0) + , v = Vec.sub(v2, v0) + , n = Vec.cross(u, v); - return Vec.mul( 1 / Vec.norm( n ), n ); + return Vec.mul(1 / Vec.norm(n), n); } @@ -47,14 +47,14 @@ class Mesh { //* a BoundingBox containing the mesh // - public static function makeMeshAabb( mesh : MeshData, faceIndices : Array ) : BoundingBox { + public static function makeMeshAabb(mesh:MeshData, faceIndices:Array):BoundingBox { var bb = new verb.core.BoundingBox(); - 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] ] ); + 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] ]); } return bb; @@ -73,17 +73,17 @@ class Mesh { //* a point represented by an array of length (dim) // - public static function sortTrianglesOnLongestAxis( bb : BoundingBox, mesh : MeshData, faceIndices : Array ) : Array { + public static function sortTrianglesOnLongestAxis(bb:BoundingBox, mesh:MeshData, faceIndices:Array):Array { var longAxis = bb.getLongestAxis(); var minCoordFaceMap = new Array>(); - for ( faceIndex in faceIndices){ - var tri_min = getMinCoordOnAxis( mesh.points, mesh.faces[ faceIndex ], longAxis ); - minCoordFaceMap.push( new Pair(tri_min, faceIndex) ); + for (faceIndex in faceIndices) { + var tri_min = getMinCoordOnAxis(mesh.points, mesh.faces[ faceIndex ], longAxis); + 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; @@ -91,8 +91,8 @@ class Mesh { }); var sortedFaceIndices = new Array(); - for ( i in 0...minCoordFaceMap.length){ - sortedFaceIndices.push( minCoordFaceMap[i].item1 ); + for (i in 0...minCoordFaceMap.length) { + sortedFaceIndices.push(minCoordFaceMap[i].item1); } return sortedFaceIndices; @@ -110,11 +110,11 @@ class Mesh { // //* the minimum coordinate - private static function getMinCoordOnAxis( points : Array, tri : Tri, axis : Int ) : Float { + private static function getMinCoordOnAxis(points:Array, tri:Tri, axis:Int):Float { 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; } @@ -134,17 +134,17 @@ class Mesh { //* a point represented by an array of length 3 // - public static function getTriangleCentroid( points : Array, tri : Tri ) : Point { + 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; } @@ -163,7 +163,7 @@ class Mesh { // //* the UV on the face - public static function triangleUVFromPoint( mesh : MeshData, faceIndex : Int, f : Point ) : UV { + public static function triangleUVFromPoint(mesh:MeshData, faceIndex:Int, f:Point):UV { var tri = mesh.faces[faceIndex]; @@ -180,12 +180,12 @@ class Mesh { 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..62533ac0 100644 --- a/src/verb/core/MeshBoundingBoxTree.hx +++ b/src/verb/core/MeshBoundingBoxTree.hx @@ -7,54 +7,54 @@ import verb.eval.Intersect; class MeshBoundingBoxTree implements IBoundingBoxTree { - var _children : Pair, IBoundingBoxTree>; - var _boundingBox : BoundingBox; - var _face : Int = -1; - var _empty : Bool = false; + var _children:Pair, IBoundingBoxTree>; + var _boundingBox:BoundingBox; + 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 ]; } - _boundingBox = Mesh.makeMeshAabb( mesh, faceIndices ); + _boundingBox = Mesh.makeMeshAabb(mesh, faceIndices); 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 as = Mesh.sortTrianglesOnLongestAxis(_boundingBox, mesh, faceIndices); 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..ca39a05a 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); 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; + 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 ); + 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; } + 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; } + while (it < maxit) { + if (t * nstep < tol) { break; } s = Vec.mul(t, step); - x1 = Vec.add(x0,s); + x1 = Vec.add(x0, s); f1 = f(x1); - if(f1-f0 >= 0.1*t*df0 || Math.isNaN(f1)) { + 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); + 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); - 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); - while(true) { + while (true) { ++it; - if( it>20 ) { throw "Numerical gradient fails"; } - x0[i] = x[i]+h; + if (it > 20) { throw "Numerical gradient fails"; } + x0[i] = x[i] + h; f1 = f(x0); - x0[i] = x[i]-h; + 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; + 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--; } @@ -146,14 +146,14 @@ class Minimizer { class MinimizationResult { - public var solution : Vector; - public var value : Float; - public var gradient : Vector; - public var invHessian : Matrix; - public var iterations : Int; - public var message : String; + public var solution:Vector; + public var value:Float; + public var gradient:Vector; + public var invHessian:Matrix; + 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..6cfa0ac4 100644 --- a/src/verb/core/Serialization.hx +++ b/src/verb/core/Serialization.hx @@ -10,14 +10,14 @@ 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(); @@ -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..c881486e 100644 --- a/src/verb/core/SurfaceBoundingBoxTree.hx +++ b/src/verb/core/SurfaceBoundingBoxTree.hx @@ -9,35 +9,35 @@ import verb.eval.Intersect; class SurfaceBoundingBoxTree implements IBoundingBoxTree { - var _children : Pair, IBoundingBoxTree>; - var _surface : NurbsSurfaceData; - var _boundingBox : BoundingBox = null; + var _children:Pair, 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){ + if (knotTolU == null) { knotTolU = (surface.knotsU.domain()) / 16; } - if (knotTolV == null){ + if (knotTolV == null) { knotTolV = (surface.knotsV.domain()) / 16; } var divisible = false; - if (splitV){ + if (splitV) { divisible = _surface.knotsV.domain() > knotTolV; } else { divisible = _surface.knotsU.domain() > knotTolU; } - if ( !divisible ) return; + if (!divisible) return; - var min : Float; - var max : Float; + var min:Float; + var max:Float; - if (splitV){ + if (splitV) { min = _surface.knotsV.first(); max = _surface.knotsV.last(); } else { @@ -48,37 +48,37 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { var dom = max - min; var pivot = (min + max) / 2.0 + dom * 0.1 * Math.random(); - var srfs = Divide.surfaceSplit( _surface, pivot, splitV ); + 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..76c79e3f 100644 --- a/src/verb/core/Trig.hx +++ b/src/verb/core/Trig.hx @@ -10,13 +10,13 @@ using verb.core.Vec; @:expose("core.Trig") class Trig { - 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 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){ - var res = segmentClosestPoint( b, a, c, 0.0, 1.0 ); - return Vec.dist( b, res.pt ); + 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); } //Find the closest point on a ray @@ -31,8 +31,8 @@ class Trig { // //* pt - public static function rayClosestPoint( pt, o, r ) { - var o2pt = Vec.sub(pt,o) + 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)); @@ -51,11 +51,11 @@ class Trig { // //* the distance - public static function distToRay( pt, o, r ) { - var d = rayClosestPoint( pt, o, r ); - var dif = Vec.sub( d, pt ); + public static function distToRay(pt, o, r) { + var d = rayClosestPoint(pt, o, r); + var dif = Vec.sub(d, pt); - return Vec.norm( dif ); + return Vec.norm(dif); } @@ -81,13 +81,13 @@ class Trig { // //* Whether the triangle passes the test - public static function threePointsAreFlat( p1, p2, p3, tol ) { + public static function threePointsAreFlat(p1, p2, p3, tol) { //find the area of the triangle without using a square root - var p2mp1 = Vec.sub( p2, p1 ) - , p3mp1 = Vec.sub( p3, p1 ) - , norm = Vec.cross( p2mp1, p3mp1 ) - , area = Vec.dot( norm, norm ); + var p2mp1 = Vec.sub(p2, p1) + , p3mp1 = Vec.sub(p3, p1) + , norm = Vec.cross(p2mp1, p3mp1) + , area = Vec.dot(norm, norm); return area < tol; @@ -107,27 +107,27 @@ class Trig { // //* *Object* with u and pt properties - public static function segmentClosestPoint( pt : Point, segpt0 : Point, segpt1 : Point, u0 : Float, u1 : Float ) { + public static function segmentClosestPoint(pt:Point, segpt0:Point, segpt1:Point, u0:Float, u1:Float) { - var dif = Vec.sub( segpt1, segpt0 ) - , l = Vec.norm( dif ); + 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 ) + , r = Vec.mul(1 / l, dif) , 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 dbe03a9d..68197cd4 100644 --- a/src/verb/core/Vec.hx +++ b/src/verb/core/Vec.hx @@ -13,22 +13,22 @@ 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 abl = al * bl; - var adb = Vec.dot(a,b); + var adb = Vec.dot(a, b); var sina = Vec.norm(nab) / abl; var cosa = adb / abl; - var w = Math.atan2( sina, cosa ); + var w = Math.atan2(sina, cosa); var s = Vec.dot(n, nab); if (Math.abs(s) < Constants.EPSILON) return w; @@ -36,45 +36,45 @@ class Vec { 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 abl = al * bl; - var adb = Vec.dot(a,b); + var adb = Vec.dot(a, b); var sina = Vec.norm(nab) / abl; var cosa = adb / abl; - var w = Math.atan2( sina, cosa ); + var w = Math.atan2(sina, cosa); 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]; + 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 { + 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 ){ + 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 @@ -83,7 +83,7 @@ class Vec { var l = []; var cur = min; - while( cur <= max ){ + while (cur <= max) { l.push(cur); cur += step; } @@ -91,188 +91,188 @@ class Vec { 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 { + public static function addAll(a:Iterable>):Array { var i = a.iterator(); if (!i.hasNext()) return null; 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 addAllMutate(a : Array>) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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 { + public static function norm(a:Iterable):Float { var norm2 = normSquared(a); - return norm2 != 0.0 ? Math.sqrt( norm2 ) : norm2; + 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 { + public static function rep(num:Int, ele:T):Array { return [ for (i in 0...num) ele ]; } - public static function zeros1d(rows : Int) : Array { + public static function zeros1d(rows:Int):Array { return [ for (i in 0...rows) 0.0 ]; } - public static function zeros2d(rows : Int, cols : Int) : Array> { + 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>> { + 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 { - var sum : Float = 0; - for (i in 0...a.length){ + public static function dot(a:Array, b:Array):Float { + var sum:Float = 0; + for (i in 0...a.length) { sum += a[i] * b[i]; } return sum; } - public static function add(a : Array, b : Array) : Array{ + 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{ + 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{ + 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{ + 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 ){ - merged.push( b[bi] ); + if (ai >= a.length) { + merged.push(b[bi]); bi++; continue; - } else if ( bi >= b.length ){ - merged.push( a[ai] ); + } else if (bi >= b.length) { + merged.push(a[ai]); ai++; continue; } var diff = a[ai] - b[bi]; - if ( Math.abs(diff) < Constants.EPSILON ){ - merged.push( a[ai] ); + 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] ); + merged.push(b[bi]); bi++; continue; } //thus diff < 0.0 - merged.push( a[ai] ); + merged.push(a[ai]); ai++; } @@ -281,27 +281,28 @@ 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 ){ - result.push( a[ai] ); + 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; } - result.push( a[ai] ); + result.push(a[ai]); ai++; } diff --git a/src/verb/eval/Analyze.hx b/src/verb/eval/Analyze.hx index a4b3031a..77cd9677 100644 --- a/src/verb/eval/Analyze.hx +++ b/src/verb/eval/Analyze.hx @@ -36,13 +36,13 @@ class Analyze { // //* Array of KnotMultiplicity objects - public static function knotMultiplicities( knots : KnotArray ) : Array { + public static function knotMultiplicities(knots:KnotArray):Array { - var mults = [ new KnotMultiplicity( knots[0], 0 ) ]; - var curr : KnotMultiplicity = mults[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); } @@ -65,12 +65,12 @@ 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(); - for (i in 0...cpts[0].length){ - var test = Vec.dist( cpts.first()[i], cpts.last()[i] ) < Constants.EPSILON; + for (i in 0...cpts[0].length) { + var test = Vec.dist(cpts.first()[i], cpts.last()[i]) < Constants.EPSILON; if (!test) return false; } @@ -88,9 +88,9 @@ class Analyze { // //* The closest point on the surface, bounded by the parametric range of the surface - public static function rationalSurfaceClosestPoint( surface : NurbsSurfaceData, p : Point ) : Point { - var uv = Analyze.rationalSurfaceClosestParam( surface, p ); - return Eval.rationalSurfacePoint( surface, uv[0], uv[1] ); + public static function rationalSurfaceClosestPoint(surface:NurbsSurfaceData, p:Point):Point { + var uv = Analyze.rationalSurfaceClosestParam(surface, p); + return Eval.rationalSurfacePoint(surface, uv[0], uv[1]); } //Determine the closest parameters on a NURBS surface to a given point. *This is an experimental method and not hightly reliable.* @@ -104,7 +104,7 @@ class Analyze { // //* The closest parameters on the surface, bounded by the parametric domain of the surface - public static function rationalSurfaceClosestParam( surface : NurbsSurfaceData, p : Point ) : UV { + public static function rationalSurfaceClosestParam(surface:NurbsSurfaceData, p:Point):UV { //for surfaces, we try to minimize the following: // @@ -165,25 +165,25 @@ class Analyze { //todo: divide surface instead of a full on tessellation //approximate closest point with tessellation - var tess = Tess.rationalSurfaceAdaptive( surface, new AdaptiveRefinementOptions() ); + var tess = Tess.rationalSurfaceAdaptive(surface, new AdaptiveRefinementOptions()); 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 ) ); + 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> { - return Eval.rationalSurfaceDerivatives( surface, uv[0], uv[1], 2 ); + 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 @@ -197,15 +197,15 @@ class Analyze { var Suv = e[1][1]; var Svu = e[1][1]; - var f = Vec.dot( Su, r ); - var g = Vec.dot( Sv, r ); + var f = Vec.dot(Su, r); + var g = Vec.dot(Sv, r); var k = [-f, -g]; - var J00 = Vec.dot( Su, Su ) + Vec.dot( Suu, r ); - var J01 = Vec.dot( Su, Sv ) + Vec.dot( Suv, r ); - var J10 = Vec.dot( Su, Sv ) + Vec.dot( Svu, r ); - var J11 = Vec.dot( Sv, Sv ) + Vec.dot( Svv, r ); + var J00 = Vec.dot(Su, Su) + Vec.dot(Suu, r); + var J01 = Vec.dot(Su, Sv) + Vec.dot(Suv, r); + var J10 = Vec.dot(Su, Sv) + Vec.dot(Svu, r); + var J11 = Vec.dot(Sv, Sv) + Vec.dot(Svv, r); var J = [ [ J00, J01 ], [ J10, J11 ] ]; @@ -216,21 +216,21 @@ class Analyze { // Su*Sv + Svu * r |Sv|^2 + Svv * r // - var d = Mat.solve( J, k ); + var d = Mat.solve(J, k); - return Vec.add( d, uv ); + return Vec.add(d, uv); } - while( i < maxits ){ + while (i < maxits) { e = f(cuv); - dif = Vec.sub(e[0][0], p ); + dif = Vec.sub(e[0][0], p); // point coincidence // // |S(u,v) - p| < e1 - var c1v = Vec.norm( dif ); + var c1v = Vec.norm(dif); // // cosine @@ -243,11 +243,11 @@ class Analyze { // ---------------------- < e2 // |Sv(u,v)| |S(u,v) - P| // - var c2an = Vec.dot( e[1][0], dif); - var c2ad = Vec.norm( e[1][0] ) * c1v; + 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 c2bd = Vec.norm( e[0][1] ) * c1v; + var c2bn = Vec.dot(e[0][1], dif); + var c2bd = Vec.norm(e[0][1]) * c1v; var c2av = c2an / c2ad; var c2bv = c2bn / c2bd; @@ -257,7 +257,7 @@ 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; } @@ -265,21 +265,21 @@ class Analyze { 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) { return cuv; @@ -305,8 +305,8 @@ 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)); + public static function rationalCurveClosestPoint(curve:NurbsCurveData, p:Point):Point { + return Eval.rationalCurvePoint(curve, rationalCurveClosestParam(curve, p)); } //Determine the closest parameters on a NURBS curve to a given point. @@ -320,7 +320,7 @@ class Analyze { // //* The closest parameter on the curve, bounded by the parametric domain of the curve - public static function rationalCurveClosestParam( curve : NurbsCurveData, p : Point ) : Float { + public static function rationalCurveClosestParam(curve:NurbsCurveData, p:Point):Float { // We want to solve: // @@ -355,20 +355,20 @@ class Analyze { var min = Math.POSITIVE_INFINITY; var u = 0.0; - var pts = Tess.rationalCurveRegularSample( curve, curve.controlPoints.length * curve.degree, true ); + 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 u1 = pts[i + 1][0]; var p0 = pts[i].slice(1); - var p1 = pts[i+1].slice(1); + var p1 = pts[i + 1].slice(1); - var proj = Trig.segmentClosestPoint( p, p0, p1, u0, u1 ); - var d = Vec.norm( Vec.sub( p, proj.pt ) ); + 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; } @@ -382,38 +382,38 @@ class Analyze { , dif , minu = curve.knots[0] , maxu = curve.knots.last() - , closed = Vec.normSquared( Vec.sub( curve.controlPoints[0], curve.controlPoints.last() ) ) < Constants.EPSILON + , closed = Vec.normSquared(Vec.sub(curve.controlPoints[0], curve.controlPoints.last())) < Constants.EPSILON , cu = u; - function f(u : Float) : Array { - return Eval.rationalCurveDerivatives( curve, u, 2 ); + 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 ); + var f = Vec.dot(e[1], d); // f' = C"(u) * ( C(u) - p ) + C'(u) * C'(u) - var s0 = Vec.dot( e[2], d ) - , s1 = Vec.dot( e[1], e[1] ) + var s0 = Vec.dot(e[2], d) + , s1 = Vec.dot(e[1], e[1]) , df = s0 + s1; return u - f / df; } - while( i < maxits ){ + while (i < maxits) { - e = f( cu ); - dif = Vec.sub( e[0], p ); + e = f(cu); + dif = Vec.sub(e[0], p); // |C(u) - p| < e1 - var c1v = Vec.norm( dif ); + var c1v = Vec.norm(dif); //C'(u) * (C(u) - P) // ------------------ < e2 // |C'(u)| |C(u) - P| - var c2n = Vec.dot( e[1], dif); - var c2d = Vec.norm( e[1] ) * c1v; + var c2n = Vec.dot(e[1], dif); + var c2d = Vec.norm(e[1]) * c1v; var c2v = c2n / c2d; @@ -421,21 +421,21 @@ class Analyze { 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); //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) { return cu; @@ -464,28 +464,28 @@ 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]; - 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 []; //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 ); + bezier_lengths[i] = i < bezier_lengths.length ? bezier_lengths[i] : rationalBezierCurveArcLength(curve); cl += bezier_lengths[i]; - if (len < cl + Constants.EPSILON){ + if (len < cl + Constants.EPSILON) { return rationalBezierCurveParamAtArcLength(curve, len, tol, bezier_lengths[i]); } @@ -508,14 +508,14 @@ class Analyze { // //* the parameter - public static function rationalBezierCurveParamAtArcLength(curve : NurbsCurveData, - len : Float, - tol : Float = null, - totalLength : Float = null) : Float { + 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 ); + var totalLen = totalLength != null ? totalLength : rationalBezierCurveArcLength(curve); if (len > totalLen) return curve.knots.last(); @@ -526,12 +526,12 @@ class Analyze { , mid = { p : 0.0, l : 0.0 } , 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,17 +556,17 @@ class Analyze { // //* the approximate length - public static function rationalCurveArcLength(curve : NurbsCurveData, u : Float = null, gaussDegIncrease : Int = 16){ + public static function rationalCurveArcLength(curve:NurbsCurveData, u:Float = null, gaussDegIncrease:Int = 16) { u = (u == null) ? curve.knots.last() : u; - var crvs = Modify.decomposeCurveIntoBeziers( curve ) + var crvs = Modify.decomposeCurveIntoBeziers(curve) , i = 0 , cc = crvs[0] , sum = 0.0; - while ( i < crvs.length && cc.knots[0] + Constants.EPSILON < u ){ + while (i < crvs.length && cc.knots[0] + Constants.EPSILON < u) { var param = Math.min(cc.knots.last(), u); - sum += rationalBezierCurveArcLength( cc, param, gaussDegIncrease ); + sum += rationalBezierCurveArcLength(cc, param, gaussDegIncrease); cc = crvs[++i]; } @@ -585,7 +585,7 @@ 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 , z = (u - curve.knots[0]) / 2 @@ -594,12 +594,12 @@ class Analyze { , 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 ); + tan = Eval.rationalCurveDerivatives(curve, cu, 1); - sum += Cvalues[gaussDeg][i] * Vec.norm( tan[1] ); + sum += Cvalues[gaussDeg][i] * Vec.norm(tan[1]); } @@ -607,59 +607,59 @@ 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> = [ + 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] ]; } @@ -669,10 +669,10 @@ class Analyze { class KnotMultiplicity { // The parameter of the knot - public var knot : Float; + public var knot:Float; // The multiplicity (i.e. the number of repeated occurrences) of the given knot in a knot vector - public var mult : Int; + public var mult:Int; // Create a new KnotMultiplicity object //**params** @@ -680,13 +680,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..16979adb 100644 --- a/src/verb/eval/Check.hx +++ b/src/verb/eval/Check.hx @@ -33,24 +33,24 @@ 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 < (degree + 1) * 2) return false; 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(); - 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 ); + return isNonDecreasing(vec); } //Check if an array of floating point numbers is non-decreasing, although there may be repeats. This is an important @@ -64,10 +64,10 @@ class Check { // //* Whether the array is non-decreasing - public static function isNonDecreasing(vec : Array){ + public static function isNonDecreasing(vec:Array) { var rep = vec.first(); - for ( i in 0...vec.length ){ - if (vec[i] < rep - Constants.EPSILON ) return false; + for (i in 0...vec.length) { + if (vec[i] < rep - Constants.EPSILON) return false; rep = vec[i]; } return true; @@ -83,19 +83,19 @@ class Check { // //* The original, unmodified data - public static function isValidNurbsCurveData( data : NurbsCurveData ) : NurbsCurveData { - if ( data.controlPoints == null ) throw "Control points array cannot be null!"; + 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.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!"; } @@ -112,26 +112,26 @@ class Check { // //* The original, unmodified data - public static function isValidNurbsSurfaceData( data : NurbsSurfaceData ) : NurbsSurfaceData { - if ( data.controlPoints == null ) throw "Control points array cannot be null!"; + 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.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 73186774..c8bb0850 100644 --- a/src/verb/eval/Divide.hx +++ b/src/verb/eval/Divide.hx @@ -24,14 +24,14 @@ 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) { - controlPoints = Mat.transpose( surface.controlPoints ); + controlPoints = Mat.transpose(surface.controlPoints); knots = surface.knotsU; degree = surface.degreeU; } else { @@ -40,27 +40,27 @@ 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>(); - var s = Eval.knotSpan( degree, u, knots ); - var res : NurbsCurveData = null; + var s = Eval.knotSpan(degree, u, knots); + var res:NurbsCurveData = null; - for (cps in controlPoints){ - res = Modify.curveKnotRefine( new NurbsCurveData(degree, knots, cps), knots_to_insert ); + 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 ) ); + 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 ); + var knots1 = res.knots.slice(s + 1); - if (!useV){ - newpts0 = Mat.transpose( newpts0 ); - newpts1 = Mat.transpose( newpts1 ); + 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 ) ]; @@ -68,7 +68,7 @@ class Divide { //v dir return [ new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots0, newpts0 ), - new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots1, newpts1 ) ]; + new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots1, newpts1 ) ]; } //Split a NURBS curve into two parts at a given parameter @@ -82,22 +82,22 @@ class Divide { // //* *Array* two new curves, defined by degree, knots, and control points - public static function curveSplit( curve : NurbsCurveData, u : Float ) : Array { + public static function curveSplit(curve:NurbsCurveData, u:Float):Array { var degree = curve.degree , controlPoints = curve.controlPoints , knots = curve.knots; - var knots_to_insert = [for (i in 0...degree+1) u]; - var res = Modify.curveKnotRefine( curve, knots_to_insert ); + 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 s = Eval.knotSpan(degree, u, knots); var knots0 = res.knots.slice(0, s + degree + 2); - var knots1 = res.knots.slice( s + 1 ); + var knots1 = res.knots.slice(s + 1); - var cpts0 = res.controlPoints.slice( 0, s + 1 ); - var cpts1 = res.controlPoints.slice( s + 1 ); + var cpts0 = res.controlPoints.slice(0, s + 1); + var cpts1 = res.controlPoints.slice(s + 1); return [ new NurbsCurveData( degree, knots0, cpts0 ), @@ -119,9 +119,9 @@ 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 tlen = Analyze.rationalCurveArcLength(curve); var inc = tlen / num; return Divide.rationalCurveByArcLength(curve, inc); @@ -139,10 +139,10 @@ 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); }) + var crvs = Modify.decomposeCurveIntoBeziers(curve) + , crvlens = crvs.map(function(x) { return Analyze.rationalBezierCurveArcLength(x); }) , totlen = Vec.sum(crvlens) , pts = [ new CurveLengthSample( curve.knots[0], 0.0 ) ]; @@ -155,15 +155,15 @@ 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] ); + u = Analyze.rationalBezierCurveParamAtArcLength(crvs[i], lc - runsum1, Constants.TOLERANCE, crvlens[i]); - pts.push( new CurveLengthSample( u, lc ) ); + pts.push(new CurveLengthSample( u, lc )); lc += inc; } @@ -183,8 +183,8 @@ class Divide { @:expose("eval.CurveLengthSample") class CurveLengthSample { - public var u : Float; - public var len : Float; + public var u:Float; + public var len:Float; public function new(u, len) { this.u = u; diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index b87ac804..efcda6fd 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -2,8 +2,12 @@ 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; @@ -29,8 +33,8 @@ class Eval { // //* a Vector represented by an array of length (dim) - public static function rationalCurveTangent( curve : NurbsCurveData, u : Float ) : Array { - var derivs = rationalCurveDerivatives( curve, u, 1 ); + public static function rationalCurveTangent(curve:NurbsCurveData, u:Float):Array { + var derivs = rationalCurveDerivatives(curve, u, 1); return derivs[1]; } @@ -46,9 +50,9 @@ class Eval { // //* a Vector represented by an array of length (dim) - 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] ); + 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]); } //Compute the derivatives at a point on a NURBS surface @@ -64,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) + 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){ - SKL.push( new Array>() ); + 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){ - Vec.subMulMutate( v, 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){ - Vec.subMulMutate( v, 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); - for (j in 1...l+1){ - Vec.addMulMutate( v2, 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]); } - Vec.subMulMutate( v, Binomial.get(k, i), v2 ); + Vec.subMulMutate(v, Binomial.get(k, i), v2); } - Vec.mulMutate(1 / wders[0][0], v ); - SKL[k].push( v ); //demogenize + Vec.mulMutate(1 / wders[0][0], v); + SKL[k].push(v); //demogenize } } @@ -122,8 +126,8 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalSurfacePoint( surface : NurbsSurfaceData, u : Float, v : Float ) : Point { - return dehomogenize( surfacePoint( surface, u, v ) ); + public static function rationalSurfacePoint(surface:NurbsSurfaceData, u:Float, v:Float):Point { + return dehomogenize(surfacePoint(surface, u, v)); } //Determine the derivatives of a NURBS curve at a given parameter @@ -138,24 +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 ) + var ders = curveDerivatives(curve, u, numDerivs) , 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) { - Vec.subMulMutate( v, 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]); } - - Vec.mulMutate( 1/wders[0], v ); - CK.push( v ); //demogenize + + Vec.mulMutate(1 / wders[0], v); + CK.push(v); //demogenize } return CK; @@ -176,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 @@ -193,12 +197,12 @@ class Eval { // //* a 2d jagged array representing the derivatives - u derivatives increase by row, v by column - public static function surfaceDerivatives( surface : NurbsSurfaceData, u : Float, v : Float, numDerivs : Int ) : Array> { + public static function surfaceDerivatives(surface:NurbsSurfaceData, u:Float, v:Float, numDerivs:Int):Array> { var n = surface.knotsU.length - surface.degreeU - 2 , m = surface.knotsV.length - surface.degreeV - 2; - return surfaceDerivativesGivenNM( n, m, surface, u, v, numDerivs ); + return surfaceDerivativesGivenNM(n, m, surface, u, v, numDerivs); } @@ -217,12 +221,12 @@ 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>{ + public static function surfaceDerivativesGivenNM(n:Int, + m:Int, + surface:NurbsSurfaceData, + u:Float, + v:Float, + numDerivs:Int):Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -230,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'; } @@ -239,31 +243,31 @@ class Eval { var dim = controlPoints[0][0].length , du = numDerivs < degreeU ? numDerivs : degreeU , dv = numDerivs < degreeV ? numDerivs : degreeV - , 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 ) + , 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) , dd = 0; - for (k in 0...du+1){ - for (s in 0...degreeV+1) { - temp[s] = Vec.zeros1d( dim ); + 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], 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){ - SKL[k][l] = Vec.zeros1d( dim ); + for (l in 0...dd + 1) { + SKL[k][l] = Vec.zeros1d(dim); - for (s in 0...degreeV+1){ - Vec.addMulMutate( SKL[k][l], vders[l][s], temp[s] ); + for (s in 0...degreeV + 1) { + Vec.addMulMutate(SKL[k][l], vders[l][s], temp[s]); } } } @@ -283,12 +287,12 @@ 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; - return surfacePointGivenNM( n, m, surface, u, v ); + return surfacePointGivenNM(n, m, surface, u, v); } @@ -307,7 +311,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function surfacePointGivenNM( n : Int, m : Int, surface : NurbsSurfaceData, u : Float, v : Float ) : Point { + public static function surfacePointGivenNM(n:Int, m:Int, surface:NurbsSurfaceData, u:Float, v:Float):Point { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -315,34 +319,34 @@ 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'; } var dim = controlPoints[0][0].length - , knotSpan_index_u = knotSpanGivenN( n, degreeU, u, knotsU ) - , knotSpan_index_v = knotSpanGivenN( m, degreeV, v, knotsV ) - , u_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_u, u, degreeU, knotsU ) - , v_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_v, v, degreeV, knotsV ) + , knotSpan_index_u = knotSpanGivenN(n, degreeU, u, knotsU) + , knotSpan_index_v = knotSpanGivenN(m, degreeV, v, knotsV) + , u_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_u, u, degreeU, knotsU) + , v_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_v, v, degreeV, knotsV) , uind = knotSpan_index_u - degreeU , vind = knotSpan_index_v - , position = Vec.zeros1d( dim ) - , temp = Vec.zeros1d( dim ); + , position = Vec.zeros1d(dim) + , temp = Vec.zeros1d(dim); - for (l in 0...degreeV + 1){ + for (l in 0...degreeV + 1) { - temp = Vec.zeros1d( dim ); + temp = Vec.zeros1d(dim); vind = knotSpan_index_v - degreeV + l; //sample u isoline for (k in 0...degreeU + 1) { - Vec.addMulMutate( temp, u_basis_vals[k], controlPoints[uind+k][vind] ); + Vec.addMulMutate(temp, u_basis_vals[k], controlPoints[uind + k][vind]); } //add point from u isoline - Vec.addMulMutate( position, v_basis_vals[l], temp ); + Vec.addMulMutate(position, v_basis_vals[l], temp); } return position; @@ -362,10 +366,10 @@ class Eval { // //* an array of (divs+1) points - public static function rationalCurveRegularSamplePoints( crv : NurbsCurveData, divs : Int ) : Array { + public static function rationalCurveRegularSamplePoints(crv:NurbsCurveData, divs:Int):Array { var range = crv.knots.last() - crv.knots[0]; - var beziers = Modify.decomposeCurveIntoBeziers( crv ); + var beziers = Modify.decomposeCurveIntoBeziers(crv); var pts = []; var brange, fraction; @@ -373,10 +377,10 @@ class Eval { var step = range / divs; var brange, bsteps, nextU; - for (i in 0...beziers.length){ + for (i in 0...beziers.length) { brange = beziers[i].knots.last() - currentU; - bsteps = Math.ceil( brange / step ); // + bsteps = Math.ceil(brange / step); // nextU = currentU + bsteps * step; if (nextU > beziers[i].knots.last() + Constants.TOLERANCE) { @@ -384,7 +388,7 @@ class Eval { bsteps--; } - rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, currentU, step, bsteps + 1 ); + rationalBezierCurveRegularSamplePointsMutate(beziers[i], pts, currentU, step, bsteps + 1); currentU = nextU + step; } @@ -392,17 +396,17 @@ class Eval { return pts; } - private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, - pts : Array, - startU : Float, - step : Float, - numSteps : Int ) { + private static function rationalBezierCurveRegularSamplePointsMutate(crv:NurbsCurveData, + pts:Array, + startU:Float, + step:Float, + numSteps:Int) { - var its = [], ts = [ its ], u = startU, degree1 = crv.degree+1; + var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; - if ( numSteps <= crv.degree + 1 ){ - for (i in 0...numSteps){ - pts.push( rationalCurvePoint( crv, u ) ); + if (numSteps <= crv.degree + 1) { + for (i in 0...numSteps) { + pts.push(rationalCurvePoint(crv, u)); u += step; } return; @@ -410,8 +414,8 @@ class Eval { // initialize forward differencing - for (i in 0...degree1){ - its.push( curvePoint( crv, u ) ); + for (i in 0...degree1) { + its.push(curvePoint(crv, u)); u += step; } @@ -419,20 +423,20 @@ class Eval { var prev; - for (i in 1...degree1){ + for (i in 1...degree1) { its = []; ts.push(its); - prev = ts[i-1]; + prev = ts[i - 1]; - for (j in 1...prev.length){ - its.push( Vec.sub( prev[j], prev[j-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( dehomogenize(pt) ); + for (pt in ts[0]) { + pts.push(dehomogenize(pt)); } // evaluate the rest of the points @@ -440,19 +444,19 @@ class Eval { var front = [ for (r in ts) r.last() ], k; var frlen2 = front.length - 2; - for (i in 0...numSteps-degree1){ + for (i in 0...numSteps - degree1) { // Rright = R + Rdown // compute the new forward difference front - for (j in 0...front.length-1){ + for (j in 0...front.length - 1) { k = frlen2 - j; // invert - Vec.addMutate(front[k], front[k+1]); + Vec.addMutate(front[k], front[k + 1]); } // add the new pt - pts.push(dehomogenize( front[0] )); + pts.push(dehomogenize(front[0])); } } @@ -470,21 +474,21 @@ class Eval { // //* 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 ) { + public static function rationalSurfaceRegularSampleDerivatives(surface:NurbsSurfaceData, divsU:Int, divsV:Int, numDerivs:Int) { - var allders = surfaceRegularSampleDerivatives( surface, divsU, divsV, numDerivs ); + var allders = surfaceRegularSampleDerivatives(surface, divsU, divsV, numDerivs); var allratders = []; - var divsU1 = divsU+1; - var divsV1 = divsV+1; - var numDerivs1 = numDerivs+1; + var divsU1 = divsU + 1; + var divsV1 = divsV + 1; + var numDerivs1 = numDerivs + 1; - for (i in 0...divsU1){ + for (i in 0...divsU1) { var rowders = []; allratders.push(rowders); - for (j in 0...divsV1){ + for (j in 0...divsV1) { var ders = allders[i][j] , Aders = rational2d(ders) @@ -492,31 +496,31 @@ class Eval { , SKL = new Array>>() , dim = Aders[0][0].length; - for (k in 0...numDerivs1){ - SKL.push( new Array>() ); + for (k in 0...numDerivs1) { + SKL.push(new Array>()); - for (l in 0...numDerivs1-k){ + 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 (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] ); + 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] ); + 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.subMulMutate(v, Binomial.get(k, i), v2); } - - Vec.mulMutate(1 / wders[0][0], v ); - SKL[k].push( v ); //demogenize + + Vec.mulMutate(1 / wders[0][0], v); + SKL[k].push(v); //demogenize } } @@ -540,7 +544,7 @@ class Eval { // //* 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 ) { + public static function surfaceRegularSampleDerivatives(surface:NurbsSurfaceData, divsU:Int, divsV:Int, numDerivs:Int) { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -551,22 +555,22 @@ class Eval { var dim = controlPoints[0][0].length , spanU = (knotsU.last() - knotsU[0]) / divsU , spanV = (knotsV.last() - knotsV[0]) / divsV - , knotSpansBasesU = regularlySpacedDerivativeBasisFunctions( degreeU, knotsU, divsU ) + , knotSpansBasesU = regularlySpacedDerivativeBasisFunctions(degreeU, knotsU, divsU) , knotSpansU = knotSpansBasesU.item0 , basesU = knotSpansBasesU.item1 - , knotSpansBasesV = regularlySpacedDerivativeBasisFunctions( degreeV, knotsV, divsV ) + , knotSpansBasesV = regularlySpacedDerivativeBasisFunctions(degreeV, knotsV, divsV) , knotSpansV = knotSpansBasesV.item0 , basesV = knotSpansBasesV.item1 , pts = [] - , divsU1 = divsU+1 - , divsV1 = divsV+1; + , divsU1 = divsU + 1 + , divsV1 = divsV + 1; - for (i in 0...divsU1){ + for (i in 0...divsU1) { var ptsi = []; - pts.push( 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 ) ); + for (j in 0...divsV1) { + ptsi.push(surfaceDerivativesGivenBasesKnotSpans(degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim, numDerivs)); } } @@ -586,8 +590,8 @@ class Eval { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function rationalSurfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { - return dehomogenize2d( surfaceRegularSamplePoints( surface, divsU, divsV ) ); + public static function rationalSurfaceRegularSamplePoints(surface:NurbsSurfaceData, divsU:Int, divsV:Int):Array> { + return dehomogenize2d(surfaceRegularSamplePoints(surface, divsU, divsV)); } // Compute a regularly spaced grid of points on a non-uniform, non-rational, B spline surface. Generally, this algorithm @@ -603,7 +607,7 @@ class Eval { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function surfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + public static function surfaceRegularSamplePoints(surface:NurbsSurfaceData, divsU:Int, divsV:Int):Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -614,155 +618,155 @@ class Eval { var dim = controlPoints[0][0].length , spanU = (knotsU.last() - knotsU[0]) / divsU , spanV = (knotsV.last() - knotsV[0]) / divsV - , knotSpansBasesU = regularlySpacedBasisFunctions( degreeU, knotsU, divsU ) + , knotSpansBasesU = regularlySpacedBasisFunctions(degreeU, knotsU, divsU) , knotSpansU = knotSpansBasesU.item0 , basesU = knotSpansBasesU.item1 - , knotSpansBasesV = regularlySpacedBasisFunctions( degreeV, knotsV, divsV ) + , knotSpansBasesV = regularlySpacedBasisFunctions(degreeV, knotsV, divsV) , knotSpansV = knotSpansBasesV.item0 , basesV = knotSpansBasesV.item1 , pts = [] - , divsU1 = divsU+1 - , divsV1 = divsV+1; + , divsU1 = divsU + 1 + , divsV1 = divsV + 1; - for (i in 0...divsU1){ + for (i in 0...divsU1) { var ptsi = []; - pts.push( ptsi ); + pts.push(ptsi); - for (j in 0...divsV1){ - ptsi.push( surfacePointGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim ) ); + for (j in 0...divsV1) { + ptsi.push(surfacePointGivenBasesKnotSpans(degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim)); } } return pts; } - public static function surfaceRegularSamplePoints2( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { - + public static function surfaceRegularSamplePoints2(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( rationalCurveRegularSamplePoints( iso, divsV ) ); + for (i in 0...divsU) { + var iso = Make.surfaceIsocurve(surface, u, true); + pts.push(rationalCurveRegularSamplePoints(iso, divsV)); u += t; } - + return pts; } - private static function regularlySpacedBasisFunctions( degree : Int, knots : KnotArray, divs : Int ) : Pair, Array>> { + private 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 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 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 ) ); + 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){ + 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 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 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 ) ); + 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 ); } - private static function surfacePointGivenBasesKnotSpans( degreeU : Int, - degreeV : Int, - controlPoints : Array>, - knotSpanU : Int, - knotSpanV : Int, - basesU : Array, - basesV : Array, - dim : Int) : Point { + private 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; + var position = Vec.zeros1d(dim) + , temp:Array; // could be precomputed var uind = knotSpanU - degreeU; var vind = knotSpanV - degreeV; - for (l in 0...degreeV + 1){ + for (l in 0...degreeV + 1) { - temp = Vec.zeros1d( dim ); + temp = Vec.zeros1d(dim); for (k in 0...degreeU + 1) { - Vec.addMulMutate( temp, basesU[k], controlPoints[uind+k][vind] ); + Vec.addMulMutate(temp, basesU[k], controlPoints[uind + k][vind]); } vind++; - Vec.addMulMutate( position, basesV[l], temp ); + 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 ){ + 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 ) + , 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 (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] ); + 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 (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] ); + for (s in 0...degreeV + 1) { + Vec.addMulMutate(SKL[k][l], basesV[l][s], temp[s]); } } } @@ -782,10 +786,10 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curveDerivatives( crv : NurbsCurveData, u : Float, numDerivs : Int ) : Array { + 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); } @@ -802,27 +806,27 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curveDerivativesGivenN( n : Int, curve : NurbsCurveData, u : Float, numDerivs : Int ) : Array { + public static function curveDerivativesGivenN(n:Int, curve:NurbsCurveData, u:Float, numDerivs:Int):Array { var degree = curve.degree , controlPoints = curve.controlPoints , knots = curve.knots; - if ( !areValidRelations( degree, controlPoints.length, knots.length ) ) { + if (!areValidRelations(degree, controlPoints.length, knots.length)) { throw 'Invalid relations between control points, knot vector, and n'; } var dim = controlPoints[0].length , du = numDerivs < degree ? numDerivs : degree - , CK = Vec.zeros2d( du+1, dim ) - , knotSpan_index = knotSpanGivenN( n, degree, u, knots ) - , nders = derivativeBasisFunctionsGivenNI( knotSpan_index, u, degree, du, knots ) + , CK = Vec.zeros2d(du + 1, dim) + , knotSpan_index = knotSpanGivenN(n, degree, u, knots) + , nders = derivativeBasisFunctionsGivenNI(knotSpan_index, u, degree, du, knots) , k = 0 , j = 0; - for (k in 0...du+1) { - for (j in 0...degree+1){ - Vec.addMulMutate( CK[k], 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; @@ -839,9 +843,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) @@ -857,7 +861,7 @@ class Eval { // //* whether the values are correct - public static function areValidRelations( degree : Int, num_controlPoints : Int, knots_length : Int ) : Bool { + public static function areValidRelations(degree:Int, num_controlPoints:Int, knots_length:Int):Bool { return num_controlPoints + degree + 1 - knots_length == 0; } @@ -874,23 +878,23 @@ 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 ) ) { + if (!areValidRelations(degree, controlPoints.length, knots.length)) { throw 'Invalid relations between control points, knot Array, and n'; return null; } - var knotSpan_index = knotSpanGivenN( n, degree, u, knots ); - var basis_values = basisFunctionsGivenKnotSpanIndex( knotSpan_index, u, degree, knots ); - var position = Vec.zeros1d( controlPoints[0].length ); + var knotSpan_index = knotSpanGivenN(n, degree, u, knots); + var basis_values = basisFunctionsGivenKnotSpanIndex(knotSpan_index, u, degree, knots); + var position = Vec.zeros1d(controlPoints[0].length); - for (j in 0...degree+1){ - Vec.addMulMutate( position, 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; @@ -909,12 +913,12 @@ class Eval { // //* a point represented by an array of length (dim) - public static function volumePoint( volume : VolumeData, u : Float, v : Float, w : Float ) : Point { + public static function volumePoint(volume:VolumeData, u:Float, v:Float, w:Float):Point { var n = volume.knotsU.length - volume.degreeU - 2 , m = volume.knotsV.length - volume.degreeV - 2 , l = volume.knotsW.length - volume.degreeW - 2; - return volumePointGivenNML( volume, n, m, l, u, v, w ); + return volumePointGivenNML(volume, n, m, l, u, v, w); } //Compute a point in a non-uniform, non-rational B spline volume @@ -930,17 +934,17 @@ class Eval { // //* a point represented by an array of length (dim) - public static function volumePointGivenNML( volume : VolumeData, - n : Int, - m : Int, - l : Int, - u : Float, - v : Float, - 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 ) ) { + public static function volumePointGivenNML(volume:VolumeData, + n:Int, + m:Int, + l:Int, + u:Float, + v:Float, + 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)) { throw 'Invalid relations between control points and knot vector'; } @@ -953,37 +957,37 @@ class Eval { , knotsW = volume.knotsW; var dim = controlPoints[0][0][0].length - , knotSpan_index_u = knotSpanGivenN( n, degreeU, u, knotsU ) - , knotSpan_index_v = knotSpanGivenN( m, degreeV, v, knotsV ) - , knotSpan_index_w = knotSpanGivenN( l, degreeW, w, knotsW ) - , u_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_u, u, degreeU, knotsU ) - , v_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_v, v, degreeV, knotsV ) - , w_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_w, w, degreeW, knotsW ) + , knotSpan_index_u = knotSpanGivenN(n, degreeU, u, knotsU) + , knotSpan_index_v = knotSpanGivenN(m, degreeV, v, knotsV) + , knotSpan_index_w = knotSpanGivenN(l, degreeW, w, knotsW) + , u_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_u, u, degreeU, knotsU) + , v_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_v, v, degreeV, knotsV) + , w_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_w, w, degreeW, knotsW) , uind = knotSpan_index_u - degreeU - , position = Vec.zeros1d( dim ) - , temp = Vec.zeros1d( dim ) - , temp2 = Vec.zeros1d( dim ); + , position = Vec.zeros1d(dim) + , temp = Vec.zeros1d(dim) + , temp2 = Vec.zeros1d(dim); - for ( i in 0...degreeW + 1 ){ + for (i in 0...degreeW + 1) { - temp2 = Vec.zeros1d( dim ); + 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; + temp = Vec.zeros1d(dim); + var vind = knotSpan_index_v - degreeV + j; - for ( k in 0...degreeU + 1 ){ - Vec.addMulMutate( temp, 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 - Vec.addMulMutate( temp2, 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 - Vec.addMulMutate( position, w_basis_vals[i], temp2 ); + Vec.addMulMutate(position, w_basis_vals[i], temp2); } return position; @@ -1001,13 +1005,12 @@ 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> - { - var knotSpan_index = knotSpan( degree, u, knots ) + 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; - return derivativeBasisFunctionsGivenNI( knotSpan_index, u, degree, n, knots ); + return derivativeBasisFunctionsGivenNI(knotSpan_index, u, degree, n, knots); } // Compute the non-vanishing basis functions and their derivatives @@ -1025,60 +1028,58 @@ 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( 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 ) + 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 , temp = 0.0; ndu[0][0] = 1.0; - for(j in 1...p+1){ - left[j] = u - knots[knotIndex+1-j]; - right[j] = knots[knotIndex+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]; + a[s2][0] = a[s1][0] / ndu[pk + 1][rk]; d = a[s2][0] * ndu[rk][pk]; } @@ -1088,19 +1089,19 @@ class Eval { 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]; } @@ -1113,11 +1114,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; @@ -1137,10 +1138,9 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctions( u : Float, degree : Int, knots : KnotArray) : Array - { + 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 ); + return basisFunctionsGivenKnotSpanIndex(knotSpan_index, u, degree, knots); } //Compute the non-vanishing basis functions @@ -1158,28 +1158,27 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctionsGivenKnotSpanIndex( knotSpan_index : Int, - 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 ); - var saved : Float = 0; - var temp : Float = 0; + public static function basisFunctionsGivenKnotSpanIndex(knotSpan_index:Int, + 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); + var saved:Float = 0; + var temp:Float = 0; 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; @@ -1201,8 +1200,7 @@ class Eval { //* the index of the knot span // - public static function knotSpan( degree : Int, u : Float, knots : Array ) : Int - { + public static function knotSpan(degree:Int, u:Float, knots:Array):Int { return knotSpanGivenN(knots.length - degree - 2, degree, u, knots); } @@ -1221,33 +1219,27 @@ 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 ); + mid = Math.floor((low + high) / 2); } return mid; @@ -1263,15 +1255,15 @@ class Eval { // //* a point represented by an array pi with length (dim) - public static function dehomogenize( homoPoint : Point ) : Point { + public static function dehomogenize(homoPoint:Point):Point { var dim = homoPoint.length , point = [] - , wt = homoPoint[dim-1] + , wt = homoPoint[dim - 1] , l = homoPoint.length - 1; - for (i in 0...l){ - point.push( homoPoint[i] / wt ); + for (i in 0...l) { + point.push(homoPoint[i] / wt); } return point; @@ -1288,9 +1280,9 @@ class Eval { // //* array of points represented by an array (wi*pi) with length (dim) - public static function rational1d( homoPoints : Array ) : Array { + 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 @@ -1304,7 +1296,7 @@ class Eval { // //* array of arrays of points, each represented by an array pi with length (dim) - public static function rational2d( homoPoints : Array> ) : Array> { + public static function rational2d(homoPoints:Array>):Array> { return homoPoints.map(rational1d); } @@ -1319,9 +1311,9 @@ class Eval { // //* a point represented by an array pi with length (dim) - public static function weight1d( homoPoints : Array ) : Array { + 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 @@ -1335,7 +1327,7 @@ class Eval { // //* array of arrays of points, each represented by an array pi with length (dim) - public static function weight2d( homoPoints : Array> ) : Array> { + public static function weight2d(homoPoints:Array>):Array> { return homoPoints.map(weight1d); } @@ -1349,7 +1341,7 @@ class Eval { // //* an array of points, each of length dim - public static function dehomogenize1d( homoPoints : Array ) : Array{ + public static function dehomogenize1d(homoPoints:Array):Array { return homoPoints.map(dehomogenize); } @@ -1363,7 +1355,7 @@ class Eval { // //* array of arrays of points, each of length dim - public static function dehomogenize2d( homoPoints : Array> ) : Array> { + public static function dehomogenize2d(homoPoints:Array>):Array> { return homoPoints.map(dehomogenize1d); } @@ -1380,14 +1372,14 @@ 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 , homo_controlPoints = new Array() - , wt : Float = 0.0 + , wt:Float = 0.0 , ref_pt = new Point() - , weights = weights != null ? weights : Vec.rep( controlPoints.length, 1.0 ); + , weights = weights != null ? weights : Vec.rep(controlPoints.length, 1.0); for (i in 0...rows) { @@ -1396,7 +1388,7 @@ class Eval { wt = weights[i]; for (k in 0...dim) { - pt.push( ref_pt[k] * wt ); + pt.push(ref_pt[k] * wt); } //append the weight @@ -1420,14 +1412,14 @@ class Eval { //i the ith control point weight and pi is the ith control point, the size is // (m x n x dim+1) - public static function homogenize2d( controlPoints : Array>, - weights: Array> = null ) : Array> { + public static function homogenize2d(controlPoints: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]) ); + 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..647e5689 100644 --- a/src/verb/eval/Intersect.hx +++ b/src/verb/eval/Intersect.hx @@ -46,25 +46,25 @@ 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 ); - var tess2 = Tess.rationalSurfaceAdaptive( surface1 ); + var tess1 = Tess.rationalSurfaceAdaptive(surface0); + var tess2 = Tess.rationalSurfaceAdaptive(surface1); // 2) intersect the two meshes, yielding a list of polylines - var resApprox = Intersect.meshes( tess1, tess2 ); + 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){ - return Intersect.surfacesAtPointWithEstimate( surface0, surface1, inter.uv0, inter.uv1, tol ); + 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); }); } @@ -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; @@ -94,61 +94,61 @@ class Intersect { do { // 1) eval normals, pts on respective surfaces (p, q, pn, qn) - pds = Eval.rationalSurfaceDerivatives( surface0, uv1[0], uv1[1], 1 ); + pds = Eval.rationalSurfaceDerivatives(surface0, uv1[0], uv1[1], 1); p = pds[0][0]; pu = pds[1][0]; pv = pds[0][1]; - pn = Vec.normalized( Vec.cross( pu, pv ) ); - pd = Vec.dot( pn, p ); + pn = Vec.normalized(Vec.cross(pu, pv)); + pd = Vec.dot(pn, p); - qds = Eval.rationalSurfaceDerivatives( surface1, uv2[0], uv2[1], 1 ); + qds = Eval.rationalSurfaceDerivatives(surface1, uv2[0], uv2[1], 1); q = qds[0][0]; qu = qds[1][0]; qv = qds[0][1]; - qn = Vec.normalized( Vec.cross( qu, qv ) ); - qd = Vec.dot( qn, q ); + qn = Vec.normalized(Vec.cross(qu, qv)); + qd = Vec.dot(qn, q); //if tolerance is met, exit loop dist = Vec.distSquared(p, q); - if (dist < tol*tol) { + if (dist < tol * tol) { break; } // 2) construct plane perp to both that passes through p (fn) - var fn = Vec.normalized( Vec.cross( pn, qn ) ); - var fd = Vec.dot( fn, p ); + var fn = Vec.normalized(Vec.cross(pn, qn)); + var fd = Vec.dot(fn, p); // 3) x = intersection of all 3 planes - var x = Intersect.threePlanes( pn, pd, qn, qd, fn, fd ); + var x = Intersect.threePlanes(pn, pd, qn, qd, fn, fd); 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) - var pdif = Vec.sub( x, p ); - var qdif = Vec.sub( x, q ); + var pdif = Vec.sub(x, p); + var qdif = Vec.sub(x, q); - var rw = Vec.cross( pu, pn ); - var rt = Vec.cross( pv, pn ); + var rw = Vec.cross(pu, pn); + var rt = Vec.cross(pv, pn); - var su = Vec.cross( qu, qn ); - var sv = Vec.cross( qv, qn ); + var su = Vec.cross(qu, qn); + var sv = Vec.cross(qv, qn); - var dw = Vec.dot( rt, pdif ) / Vec.dot( rt, pu ); - var dt = Vec.dot( rw, pdif ) / Vec.dot( rw, pv ); + var dw = Vec.dot(rt, pdif) / Vec.dot(rt, pu); + var dt = Vec.dot(rw, pdif) / Vec.dot(rw, pv); - var du = Vec.dot( sv, qdif ) / Vec.dot( sv, qu ); - var dv = Vec.dot( su, qdif ) / Vec.dot( su, qv ); + var du = Vec.dot(sv, qdif) / Vec.dot(sv, qu); + var dv = Vec.dot(su, qdif) / Vec.dot(su, qv); - uv1 = Vec.add( [dw, dt], uv1 ); - uv2 = Vec.add( [du, dv], uv2 ); + uv1 = Vec.add([dw, dt], uv1); + uv2 = Vec.add([du, dv], uv2); //repeat its++; - } while( its < maxits ); + } while (its < maxits); return new SurfaceSurfaceIntersectionPoint(uv1, uv2, p, dist); } @@ -166,47 +166,47 @@ class Intersect { // //* array of array of MeshIntersectionPoints - public static function meshes( mesh0 : MeshData, - mesh1 : MeshData, - bbtree0 : IBoundingBoxTree = null, - bbtree1 : IBoundingBoxTree = null ) : Array> { + public static function meshes(mesh0:MeshData, + mesh1:MeshData, + bbtree0:IBoundingBoxTree = null, + bbtree1:IBoundingBoxTree = null):Array> { 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 ); + var bbints = Intersect.boundingBoxTrees(bbtree0, bbtree1, 0); //get the segments of the intersection crv with uvs - var segments = bbints.map(function(ids : Pair){ - return Intersect.triangles( mesh0, ids.item0, mesh1, ids.item1 ); - }).filter(function(x){ + var segments = bbints.map(function(ids:Pair) { + return Intersect.triangles(mesh0, ids.item0, mesh1, ids.item1); + }).filter(function(x) { return x != null; - }).filter(function(x){ - return Vec.distSquared( x.min.point, x.max.point ) > Constants.EPSILON; - }).unique(function(a, b){ + }).filter(function(x) { + return Vec.distSquared(x.min.point, x.max.point) > Constants.EPSILON; + }).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 // these computations - var s1 = Vec.sub( a.min.uv0, b.min.uv0 ); - var d1 = Vec.dot( s1, s1 ); + var s1 = Vec.sub(a.min.uv0, b.min.uv0); + var d1 = Vec.dot(s1, s1); - var s2 = Vec.sub( a.max.uv0, b.max.uv0 ); - var d2 = Vec.dot( s2, s2 ); + var s2 = Vec.sub(a.max.uv0, b.max.uv0); + var d2 = Vec.dot(s2, s2); - var s3 = Vec.sub( a.min.uv0, b.max.uv0 ); - var d3 = Vec.dot( s3, s3 ); + var s3 = Vec.sub(a.min.uv0, b.max.uv0); + var d3 = Vec.dot(s3, s3); - var s4 = Vec.sub( a.max.uv0, b.min.uv0 ); - var d4 = Vec.dot( s4, s4 ); + var s4 = Vec.sub(a.max.uv0, b.min.uv0); + 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 ); + return makeMeshIntersectionPolylines(segments); } //Slice a mesh by repeated planar intersections yielding a sequence of polylines. Each plane @@ -224,7 +224,7 @@ class Intersect { //* array of array of array of MeshIntersectionPoints - corresponding to the collection of polylines formed with // each slice - public static function meshSlices( mesh : MeshData, min : Float, max : Float, step : Float ) : Array>> { + public static function meshSlices(mesh:MeshData, min:Float, max:Float, step:Float):Array>> { var bbtree = new MeshBoundingBoxTree( mesh ); var bb = bbtree.boundingBox(); @@ -234,16 +234,16 @@ class Intersect { var x1 = bb.max[0]; var y1 = bb.max[1]; - var span = Vec.span( min, max, step ); + 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 ) ); + slices.push(Intersect.meshes(mesh, plane, bbtree)); } return slices; @@ -259,41 +259,41 @@ class Intersect { // //* array of array of MeshIntersectionPoint - public static function makeMeshIntersectionPolylines( segments : Array> ) : Array> { + public static function makeMeshIntersectionPolylines(segments:Array>):Array> { 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; } //construct a tree for fast lookup - var tree = kdTreeFromSegments( segments ); + var tree = kdTreeFromSegments(segments); //flatten everything, we no longer need the segments - var ends : Array = []; + var ends:Array = []; - for (seg in segments){ + 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){ + for (segEnd in ends) { if (segEnd.adj != null) continue; - var adjEnd = lookupAdjacentSegment( segEnd, tree, segments.length ); + 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; }); @@ -306,11 +306,11 @@ class Intersect { var numVisitedEnds = 0; var loopDetected = false; - while (freeEnds.length != 0){ + while (freeEnds.length != 0) { var end = freeEnds.pop(); - if (!end.visited){ + if (!end.visited) { //traverse to end var pl = []; @@ -339,15 +339,15 @@ class Intersect { } if (pl.length > 0) { - pl.push( pl[pl.length-1].opp ); - pls.push( pl ); + 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(); - freeEnds.push( e ); + freeEnds.push(e); } } @@ -364,12 +364,12 @@ 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){ + for (seg in segments) { treePoints.push(new KdPoint(seg.min.point, seg.min )); treePoints.push(new KdPoint(seg.max.point, seg.max )); } @@ -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){ + .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; @@ -414,18 +414,18 @@ 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 { + public static function curveAndSurface(curve:NurbsCurveData, + 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 ); + 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; @@ -445,10 +445,10 @@ class Intersect { var uv = [ (minu + maxu) / 2.0, (minv + maxv) / 2.0 ]; - 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 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; }); } @@ -466,14 +466,14 @@ 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]) - , p2 = Eval.rationalSurfacePoint( surface, x[1], x[2] ) + var p1 = Eval.rationalCurvePoint(curve, x[0]) + , p2 = Eval.rationalSurfacePoint(surface, x[1], x[2]) , p1_p2 = Vec.sub(p1, p2); return Vec.dot(p1_p2, p1_p2); @@ -498,10 +498,10 @@ 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 ); + var dc = Eval.rationalCurveDerivatives(curve, x[0], 1) + , ds = Eval.rationalSurfaceDerivatives(surface, x[1], x[2], 1); var r = Vec.sub(ds[0][0], dc[0]); @@ -509,16 +509,16 @@ class Intersect { 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 @@ -532,13 +532,13 @@ class Intersect { // //* an array of PolylineMeshIntersection object - public static function polylineAndMesh( polyline : PolylineData, - mesh : MeshData, - tol : Float ) : Array { + public static function polylineAndMesh(polyline:PolylineData, + mesh:MeshData, + tol:Float):Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline ), - new LazyMeshBoundingBoxTree( mesh ), tol ); + new LazyMeshBoundingBoxTree( mesh ), tol); var finalResults = []; @@ -547,12 +547,12 @@ class Intersect { var polid = event.item0; var faceid = event.item1; - var inter = Intersect.segmentWithTriangle( polyline.points[polid], polyline.points[polid + 1], mesh.points, mesh.faces[ faceid ] ); - if ( inter == null ) continue; + var inter = Intersect.segmentWithTriangle(polyline.points[polid], polyline.points[polid + 1], mesh.points, mesh.faces[ faceid ]); + 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 )); @@ -574,66 +574,66 @@ 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> { + private static function boundingBoxTrees(ai:IBoundingBoxTree, bi:IBoundingBoxTree, tol:Float = 1e-9) + :Array> { var atrees = []; var btrees = []; - + atrees.push(ai); btrees.push(bi); var results = []; - while ( atrees.length > 0 ){ + 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; + if (!a.boundingBox().intersects(b.boundingBox(), tol)) continue; var ai = a.indivisible(tol); var bi = b.indivisible(tol); if (ai && bi) { - results.push( new Pair(a.yield(), b.yield()) ); + results.push(new Pair(a.yield(), b.yield())); continue; } else if (ai && !bi) { var bs = b.split(); - - atrees.push( a ); - btrees.push( bs.item1 ); - - atrees.push( a ); - btrees.push( bs.item0 ); - + + atrees.push(a); + btrees.push(bs.item1); + + atrees.push(a); + btrees.push(bs.item0); + continue; - } else if (!ai && bi){ + } else if (!ai && bi) { var as = a.split(); - - atrees.push( as.item1 ); - btrees.push( b ); - - atrees.push( as.item0 ); - btrees.push( b ); - + + atrees.push(as.item1); + btrees.push(b); + + atrees.push(as.item0); + btrees.push(b); + continue; } 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 ); + + 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); } @@ -652,18 +652,18 @@ class Intersect { // //* the intersections - public static function curves( curve1 : NurbsCurveData, curve2 : NurbsCurveData, tolerance : Float ) : Array { + public static function curves(curve1:NurbsCurveData, curve2:NurbsCurveData, tolerance:Float):Array { var ints = Intersect.boundingBoxTrees( 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 Vec.distSquared( x.point0, x.point1 ) < tolerance; - }).unique(function(a,b){ - return Math.abs(a.u0 - b.u0) < tolerance*5; + 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 Vec.distSquared(x.point0, x.point1) < tolerance; + }).unique(function(a, b) { + return Math.abs(a.u0 - b.u0) < tolerance * 5; }); } @@ -682,13 +682,12 @@ class Intersect { // //* array of CurveCurveIntersection objects - private static function curvesWithEstimate( curve0 : NurbsCurveData, - curve1 : NurbsCurveData, - u0 : Float, - u1 : Float, - tolerance : Float ) : CurveCurveIntersection - { - var objective = function( x : Vector ) : Float { + private static function curvesWithEstimate(curve0:NurbsCurveData, + 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); @@ -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 dc0 = Eval.rationalCurveDerivatives( curve0, x[0], 1 ) - , dc1 = Eval.rationalCurveDerivatives( curve1, x[1], 1 ); + 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 r = Vec.sub(dc0[0], dc1[0]); var drdu = dc0[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 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 ); + , p2 = Eval.rationalCurvePoint(curve1, u2); return new CurveCurveIntersection(p1, p2, u1, u2); } @@ -746,14 +745,14 @@ 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]; // 0) get the plane rep of the two triangles - var n0 = Mesh.getTriangleNorm( mesh0.points, tri0 ); - var n1 = Mesh.getTriangleNorm( mesh1.points, tri1 ); + var n0 = Mesh.getTriangleNorm(mesh0.points, tri0); + var n1 = Mesh.getTriangleNorm(mesh1.points, tri1); var o0 = mesh0.points[ tri0[0] ]; var o1 = mesh1.points[ tri1[0] ]; @@ -762,44 +761,44 @@ class Intersect { if (ray == null) return null; // 2) clip the ray within tri0 - var clip1 = clipRayInCoplanarTriangle( ray, mesh0, faceIndex0 ); + var clip1 = clipRayInCoplanarTriangle(ray, mesh0, faceIndex0); if (clip1 == null) return null; // 3) clip the ray within tri1 - var clip2 = clipRayInCoplanarTriangle( ray, mesh1, faceIndex1 ); + var clip2 = clipRayInCoplanarTriangle(ray, mesh1, faceIndex1); if (clip2 == null) return null; // 4) find the interval that overlaps - var merged = mergeTriangleClipIntervals(clip1, clip2, mesh0, faceIndex0, mesh1, faceIndex1 ); + 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]) ] - , 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 ); + , 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); // 1) for each tri ray, if intersects and in segment interval, store minU, maxU - var minU : CurveTriPoint = null; - var maxU : CurveTriPoint = null; + var minU:CurveTriPoint = null; + 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 ); + var res = Intersect.rays(o0, d0, ray.origin, ray.dir); if (res == null) { continue; @@ -812,12 +811,12 @@ class Intersect { 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])); } } @@ -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) { + if (clip2.min.u > clip1.max.u + Constants.EPSILON + || clip1.min.u > clip2.max.u + Constants.EPSILON) { return null; } @@ -844,22 +843,22 @@ 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 ); + res.min.uv1 = Mesh.triangleUVFromPoint(mesh2, faceIndex2, min.item0.point); } else { - res.min.uv0 = Mesh.triangleUVFromPoint( mesh1, faceIndex1, min.item0.point ); + res.min.uv0 = Mesh.triangleUVFromPoint(mesh1, faceIndex1, min.item0.point); 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 ); + res.max.uv1 = Mesh.triangleUVFromPoint(mesh2, faceIndex2, max.item0.point); } else { - res.max.uv0 = Mesh.triangleUVFromPoint( mesh1, faceIndex1, max.item0.point ); + res.max.uv0 = Mesh.triangleUVFromPoint(mesh1, faceIndex1, max.item0.point); res.max.uv1 = max.item0.uv; } @@ -879,7 +878,7 @@ 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); @@ -887,28 +886,28 @@ class Intersect { //find the largest index of d var li = 0; - var mi = Math.abs( d[0] ); - var m1 = Math.abs( d[1] ); - var m2 = Math.abs( d[2] ); + var mi = Math.abs(d[0]); + 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]; @@ -921,8 +920,8 @@ class Intersect { } //n dot X = d - var d1 = -Vec.dot( origin0, normal0 ); - var d2 = -Vec.dot( origin1, normal1 ); + var d1 = -Vec.dot(origin0, normal0); + var d2 = -Vec.dot(origin1, normal1); var den = a1 * b2 - b1 * a2; @@ -930,15 +929,15 @@ 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 ) ); + return new Ray( p, Vec.normalized(d) ); } //Intersect three planes, expects the planes to form a single point of @@ -957,17 +956,17 @@ 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 ); + var u = Vec.cross(n1, n2); + var den = Vec.dot(n0, u); 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 diff = Vec.sub(Vec.mul(d2, n1), Vec.mul(d1, n2)); + var num = Vec.add(Vec.mul(d0, u), Vec.cross(n0, diff)); - return Vec.mul( 1 / den, num ); + return Vec.mul(1 / den, num); } @@ -983,12 +982,12 @@ 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 { + public static function polylines(polyline0:PolylineData, polyline1:PolylineData, tol:Float) + :Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline0 ), - new LazyPolylineBoundingBoxTree( polyline1 ), tol ); + new LazyPolylineBoundingBoxTree( polyline1 ), tol); var finalResults = []; @@ -996,14 +995,14 @@ class Intersect { 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; + 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); } @@ -1025,25 +1024,25 @@ class Intersect { // //* a CurveCurveIntersection object - public static function segments( a0 : Point, a1 : Point, b0 : Point, b1 : Point, tol : Float ) : CurveCurveIntersection { + 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); - - 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); - - if ( dist < tol*tol ) { + 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); + + if (dist < tol * tol) { return new CurveCurveIntersection( point0, point1, u0, u1 ); } } @@ -1064,28 +1063,28 @@ class Intersect { // //* a CurveCurveIntersection object - public static function rays( a0 : Point, a : Point, b0 : Point, b : Point ) : CurveCurveIntersection { + public static function rays(a0:Point, a:Point, b0:Point, b:Point):CurveCurveIntersection { - var dab = Vec.dot( a, b ), - dab0 = Vec.dot( a, b0 ), - daa0 = Vec.dot( a, a0 ), - dbb0 = Vec.dot( b, b0 ), - dba0 = Vec.dot( b, a0 ), - daa = Vec.dot( a, a ), - dbb = Vec.dot( b, b ), - div = daa*dbb - dab*dab; + var dab = Vec.dot(a, b), + dab0 = Vec.dot(a, b0), + daa0 = Vec.dot(a, a0), + dbb0 = Vec.dot(b, b0), + dba0 = Vec.dot(b, a0), + daa = Vec.dot(a, a), + dbb = Vec.dot(b, b), + div = daa * dbb - dab * dab; //parallel case - if ( Math.abs( div ) < Constants.EPSILON ) { + 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 ); + var p0 = Vec.onRay(a0, a, t); + var p1 = Vec.onRay(b0, b, w); return new CurveCurveIntersection( p0, p1, t, w ); } @@ -1103,52 +1102,52 @@ class Intersect { // //* a TriangleSegmentIntersection or null if failed - public static function segmentWithTriangle( p0 : Point, p1 : Point, points : Array, tri : Tri ) : TriSegmentIntersection { + public static function segmentWithTriangle(p0:Point, p1:Point, points:Array, tri:Tri):TriSegmentIntersection { var v0 = points[ tri[0] ] , v1 = points[ tri[1] ] , v2 = points[ tri[2] ] - , u = Vec.sub( v1, v0 ) - , v = Vec.sub( v2, v0 ) - , n = Vec.cross( u, v ); + , u = Vec.sub(v1, v0) + , v = Vec.sub(v2, v0) + , n = Vec.cross(u, v); - var dir = Vec.sub( p1, p0 ) - , w0 = Vec.sub( p0, v0 ) - , a = -Vec.dot( n, w0 ) - , b = Vec.dot( n, dir ); + var dir = Vec.sub(p1, p0) + , w0 = Vec.sub(p0, v0) + , a = -Vec.dot(n, w0) + , 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; } //get proposed intersection - var pt = Vec.add( p0, Vec.mul( r, dir ) ); + 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) - , w = Vec.sub( pt, v0 ) - , wu = Vec.dot( w, u ) - , wv = Vec.dot( w, 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; } @@ -1171,21 +1170,21 @@ class Intersect { //**returns** //null or an object with a p property representing the param on the segment - public static function segmentAndPlane( p0 : Point, p1 : Point, v0 : Point, n : Point ) { + 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 ) { + 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 indivisible( tolerance : Float ) : Bool; - public function empty() : Bool; + public function boundingBox():BoundingBox; + public function split():Pair, IBoundingBoxTree>; + public function yield():T; + public function indivisible(tolerance:Float):Bool; + public function empty():Bool; } diff --git a/src/verb/eval/Make.hx b/src/verb/eval/Make.hx index 5aefcd44..2e955efa 100644 --- a/src/verb/eval/Make.hx +++ b/src/verb/eval/Make.hx @@ -40,26 +40,26 @@ class Make { // //* NurbsSurfaceData object - public static function rationalTranslationalSurface( profile : NurbsCurveData, rail : NurbsCurveData ) : NurbsSurfaceData { + 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 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]]); - crvs.push( crv ); + 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); } - return Make.loftedSurface( crvs ); + return Make.loftedSurface(crvs); } //Extract the boundary curves from a surface @@ -68,66 +68,66 @@ 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]; } - public static function surfaceIsocurve( surface : NurbsSurfaceData, u : Float, useV : Bool = false ) : NurbsCurveData { + public static function surfaceIsocurve(surface:NurbsSurfaceData, u:Float, useV:Bool = false):NurbsCurveData { var knots = useV ? surface.knotsV : surface.knotsU; var degree = useV ? surface.degreeV : surface.degreeU; - var knotMults = Analyze.knotMultiplicities( knots ); + var knotMults = Analyze.knotMultiplicities(knots); //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 ){ + var reqKnotIndex:Int = -1; + 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 ); + 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 ) { + } else if (Math.abs(u - knots.last()) < Constants.EPSILON) { span = ( if (useV) newSrf.controlPoints[0].length else newSrf.controlPoints.length ) - 1; } - if (useV){ + 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] ); } - public static function loftedSurface( curves : Array, degreeV : Int = null ) : NurbsSurfaceData { + public static function loftedSurface(curves:Array, degreeV:Int = null):NurbsSurfaceData { - curves = Modify.unifyCurveKnotVectors( curves ); + curves = Modify.unifyCurveKnotVectors(curves); //degree var degreeU = curves[0].degree; if (degreeV == null) degreeV = 3; - if (degreeV > curves.length - 1){ + if (degreeV > curves.length - 1) { degreeV = curves.length - 1; } @@ -136,24 +136,24 @@ 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 - var c = Make.rationalInterpCurve( points, degreeV, true ); - controlPoints.push( c.controlPoints ); + var c = Make.rationalInterpCurve(points, degreeV, true); + controlPoints.push(c.controlPoints); knotsV = c.knots; //redundant computation } return new NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); } - public static function clonedCurve( curve : NurbsCurveData ) : NurbsCurveData { - return new NurbsCurveData( curve.degree, curve.knots.copy(), curve.controlPoints.map(function(x){ return x.copy(); }) ); + public static function clonedCurve(curve:NurbsCurveData):NurbsCurveData { + return new NurbsCurveData( curve.degree, curve.knots.copy(), curve.controlPoints.map(function(x) { return x.copy(); }) ); } //Generate the control points, weights, and knots for a bezier curve of any degree @@ -169,18 +169,18 @@ class Make { // //* NurbsSurfaceData object - public static function rationalBezierCurve( controlPoints : Array, weights : Array = null ) : NurbsCurveData { + public static function rationalBezierCurve(controlPoints:Array, weights:Array = null):NurbsCurveData { 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 )); + return new NurbsCurveData( degree, knots, Eval.homogenize1d(controlPoints, weights)); } //Generate the control points, weights, and knots of a surface defined by 4 points @@ -196,33 +196,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 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 p1p2 = Vec.lerp(l, p1, p2); + var p4p3 = Vec.lerp(l, p4, p3); - var res = Vec.lerp( 1.0 - j / degreeFloat, p1p2, p4p3 ); + var res = Vec.lerp(1.0 - j / degreeFloat, p1p2, p4p3); res.push(1.0); //add the weight row.push(res); } - pts.push( row ); + 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 ); } @@ -240,13 +240,13 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - public static function ellipseArc( center : Point, xaxis : Point, yaxis : Point, startAngle : Float, endAngle : Float ) : NurbsCurveData { + public static function ellipseArc(center:Point, xaxis:Point, yaxis:Point, startAngle:Float, endAngle:Float):NurbsCurveData { - var xradius = Vec.norm( xaxis ); - var yradius = Vec.norm( yaxis ); + var xradius = Vec.norm(xaxis); + var yradius = Vec.norm(yaxis); - xaxis = Vec.normalized( xaxis ); - yaxis = Vec.normalized( yaxis ); + xaxis = Vec.normalized(xaxis); + 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; @@ -258,9 +258,9 @@ class Make { 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,38 +269,38 @@ 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 ); + , weights = Vec.zeros1d(numArcs * 2); 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 ) ) ); + var P2 = Vec.add(center, + 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,24 +308,24 @@ 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; knots[7] = knots[8] = 0.75; } - return new NurbsCurveData( 2, knots, Eval.homogenize1d( controlPoints, weights )); + return new NurbsCurveData( 2, knots, Eval.homogenize1d(controlPoints, weights)); } @@ -345,9 +345,9 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - 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 ); + 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); } //Generate the control points, weights, and knots of a polyline curve @@ -360,23 +360,23 @@ 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] ); - knots.push( lsum ); + for (i in 0...pts.length - 1) { + lsum += Vec.dist(pts[i], pts[i + 1]); + knots.push(lsum); } - knots.push( lsum ); + knots.push(lsum); //normalize the knot array - knots = Vec.mul( 1 / lsum, knots ); + knots = Vec.mul(1 / lsum, knots); 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)); } @@ -392,30 +392,30 @@ class Make { // //* an object with the following properties: controlPoints, weights, knots, degree - public static function extrudedSurface( axis : Point, length : Float, profile : NurbsCurveData ) : NurbsSurfaceData { + 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 ); + var prof_controlPoints = Eval.dehomogenize1d(profile.controlPoints); + var prof_weights = Eval.weight1d(profile.controlPoints); - var translation = Vec.mul( length, axis ); - var halfTranslation = Vec.mul( 0.5 * length, axis ); + var translation = Vec.mul(length, axis); + 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] ); - controlPoints[0][j] = Vec.add( translation, prof_controlPoints[j] ); + controlPoints[1][j] = Vec.add(halfTranslation, prof_controlPoints[j]); + controlPoints[0][j] = 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 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 @@ -432,13 +432,13 @@ class Make { // //* an object with the following properties: controlPoints, weights, knotsU, knotsV, degreeU, degreeV - public static function cylindricalSurface( axis : Point, xaxis : Point, base : Point, height : Float, radius : Float ) : NurbsSurfaceData { + public static function cylindricalSurface(axis:Point, xaxis:Point, base:Point, height:Float, radius:Float):NurbsSurfaceData { - var yaxis = Vec.cross( axis, xaxis ) + var yaxis = Vec.cross(axis, xaxis) , angle = 2.0 * Math.PI - , circ = Make.arc( base, xaxis, yaxis, radius, 0.0, 2 * Math.PI ); + , circ = Make.arc(base, xaxis, yaxis, radius, 0.0, 2 * Math.PI); - return Make.extrudedSurface( axis, height, circ ); + return Make.extrudedSurface(axis, height, circ); } @@ -458,56 +458,56 @@ class Make { // //* an object with the following properties: controlPoints, weights, knots, degree - public static function revolvedSurface( profile : NurbsCurveData, center : Point, axis : Point, theta : Float ) : NurbsSurfaceData { + 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 ); + var prof_controlPoints = Eval.dehomogenize1d(profile.controlPoints) + , prof_weights = Eval.weight1d(profile.controlPoints); var narcs, knotsU, controlPoints, weights; 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); @@ -515,20 +515,20 @@ class Make { //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 - , X = Vec.sub( prof_controlPoints[j], O ) - //radius at that height + //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); + //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); + 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,30 +542,30 @@ 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; @@ -576,7 +576,7 @@ class Make { } } - return new NurbsSurfaceData( 2, profile.degree, knotsU, profile.knots, Eval.homogenize2d( controlPoints, weights ) ); + return new NurbsSurfaceData( 2, profile.degree, knotsU, profile.knots, Eval.homogenize2d(controlPoints, weights) ); } @@ -594,10 +594,10 @@ 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 ); - return revolvedSurface( arc, center, axis, 2 * 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); } @@ -615,24 +615,24 @@ class Make { //* an object with the following properties: controlPoints, weights, knots, degree // - public static function conicalSurface( axis : Point, xaxis : Point, base : Point, height : Float, radius : Float ) : NurbsSurfaceData { + public static function conicalSurface(axis:Point, xaxis:Point, base:Point, height:Float, radius:Float):NurbsSurfaceData { 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 = new NurbsCurveData( prof_degree, prof_knots, Eval.homogenize1d( prof_ctrl_pts, prof_weights ) ); + , 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 = 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); } - public static function rationalInterpCurve( points : Array>, - degree : Int = 3, - homogeneousPoints : Bool = false, - start_tangent : Point = null, - end_tangent : Point = null ) : NurbsCurveData { + public static function rationalInterpCurve(points:Array>, + degree:Int = 3, + homogeneousPoints:Bool = false, + start_tangent:Point = null, + end_tangent:Point = null):NurbsCurveData { // 0) build knot vector for curve by normalized chord length // 1) construct effective basis function in square matrix (W) @@ -643,24 +643,24 @@ 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 ); + 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; } - var knotsStart = Vec.rep( degree + 1, 0.0 ); + var knotsStart = Vec.rep(degree + 1, 0.0); //we need two more control points, two more knots @@ -668,16 +668,16 @@ 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]; } - knotsStart.push( (1 / degree) * weightSums ); + knotsStart.push((1 / degree) * weightSums); } - var knots = knotsStart.concat( Vec.rep( degree + 1, 1.0 ) ); + var knots = knotsStart.concat(Vec.rep(degree + 1, 1.0)); //build matrix of basis function coeffs (TODO: use sparse rep) var A = []; @@ -686,26 +686,26 @@ class Make { var lst = hasTangents ? 1 : 0; var ld = hasTangents ? points.length - (degree - 1) : points.length - (degree + 1); - for (u in us){ - var span = Eval.knotSpanGivenN( n, degree, u, knots ); - var basisFuncs = Eval.basisFunctionsGivenKnotSpanIndex( span, u, degree, knots ); + for (u in us) { + var span = Eval.knotSpanGivenN(n, degree, u, knots); + var basisFuncs = Eval.basisFunctionsGivenKnotSpanIndex(span, u, degree, knots); var ls = span - degree; - var rowstart = Vec.zeros1d( ls ); - var rowend = Vec.zeros1d( ld - ls ); + 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(1, 0, tanRow0); + A.spliceAndInsert(A.length - 1, 0, tanRow1); } //for each dimension, solve @@ -715,29 +715,29 @@ class Make { var mult1 = (1 - knots[knots.length - degree - 2] ) / degree; var mult0 = knots[degree + 1] / degree; - for (i in 0...dim){ - var b : Array; + 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( mult1 * end_tangent[i] ); - b.push( points.last()[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]); } - var x = Mat.solve( A, b ); + var x = Mat.solve(A, b); xs.push(x); } var controlPts = Mat.transpose(xs); - if (!homogeneousPoints){ + if (!homogeneousPoints) { var weights = Vec.rep(controlPts.length, 1.0); controlPts = Eval.homogenize1d(controlPts, weights); } diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index 1efb4311..ce833da4 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -35,8 +35,8 @@ 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() ); + public static function curveReverse(curve:NurbsCurveData):NurbsCurveData { + 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. @@ -50,15 +50,15 @@ 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){ + 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() ]); + [for (row in surface.controlPoints) row.reversed() ]); } return new NurbsSurfaceData( surface.degreeU, surface.degreeV, knotsReverse(surface.knotsU), surface.knotsV, - surface.controlPoints.reversed()); + surface.controlPoints.reversed()); } //Reverse a knot vector @@ -71,14 +71,14 @@ class Modify { // //* The reversed array of knots - public static function knotsReverse( knots : KnotArray ) : KnotArray { + public static function knotsReverse(knots:KnotArray):KnotArray { 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; @@ -94,56 +94,56 @@ class Modify { // //* A collection of NURBS curves, all with the same knot vector - public static function unifyCurveKnotVectors( curves : Array ) : Array { + public static function unifyCurveKnotVectors(curves:Array):Array { 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){ - curves[i] = Modify.curveElevateDegree( curves[i], 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() ) ]; //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){ - var rem = Vec.sortedSetSub( mergedKnots, curves[i].knots ); + for (i in 0...curves.length) { + var rem = Vec.sortedSetSub(mergedKnots, curves[i].knots); if (rem.length == 0) { curves[i] = curves[i]; } - curves[i] = Modify.curveKnotRefine( curves[i], rem ); + curves[i] = Modify.curveKnotRefine(curves[i], rem); } return curves; } - private static function imin( a : Int, b : Int ) : Int { + private static function imin(a:Int, b:Int):Int { return a < b ? a : b; } - private static function imax( a : Int, b : Int ) : Int { + private static function imax(a:Int, b:Int):Int { return a > b ? a : b; } @@ -158,7 +158,7 @@ class Modify { // //* The NURBS curve after degree elevation - if the supplied degree is <= the curve is returned unmodified - public static function curveElevateDegree( curve : NurbsCurveData, finalDegree : Int ) : NurbsCurveData { + public static function curveElevateDegree(curve:NurbsCurveData, finalDegree:Int):NurbsCurveData { if (finalDegree <= curve.degree) return curve; @@ -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 = []; @@ -190,135 +190,135 @@ class Modify { bezalfs[0][0] = 1.0; bezalfs[ph][newDegree] = 1.0; - 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); + 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); } } - 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){ - 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])); + 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])); } } - 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 ); } @@ -334,20 +334,20 @@ class Modify { // //* A new NURBS surface after transformation - public static function rationalSurfaceTransform( surface : NurbsSurfaceData, mat : Matrix ) : NurbsSurfaceData { + public static function rationalSurfaceTransform(surface:NurbsSurfaceData, mat:Matrix):NurbsSurfaceData { - var pts = Eval.dehomogenize2d( surface.controlPoints ); + 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); - pts[i][j] = Mat.dot( mat, homoPt ).slice( 0, homoPt.length - 1 ); + 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 @@ -361,19 +361,19 @@ class Modify { // //* A new NURBS surface after transformation - public static function rationalCurveTransform( curve : NurbsCurveData, mat : Matrix ) : NurbsCurveData { + public static function rationalCurveTransform(curve:NurbsCurveData, mat:Matrix):NurbsCurveData { - var pts = Eval.dehomogenize1d( curve.controlPoints ); + 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); - pts[i] = Mat.dot( mat, homoPt ).slice( 0, homoPt.length - 1 ); + 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)) ); } @@ -389,7 +389,7 @@ class Modify { // //* A new NURBS surface with the knots inserted - public static function surfaceKnotRefine( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { + 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 @@ -400,11 +400,11 @@ class Modify { , ctrlPts; //u dir - if (!useV){ - ctrlPts = Mat.transpose( surface.controlPoints ); + if (!useV) { + ctrlPts = Mat.transpose(surface.controlPoints); knots = surface.knotsU; degree = surface.degreeU; - //v dir + //v dir } else { ctrlPts = surface.controlPoints; knots = surface.knotsV; @@ -412,19 +412,19 @@ class Modify { } //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 ); + var c:NurbsCurveData = null; + for (cptrow in ctrlPts) { + c = curveKnotRefine(new NurbsCurveData(degree, knots, cptrow), knotsToInsert); + newPts.push(c.controlPoints); } var newknots = c.knots; //u dir - if (!useV){ - newPts = Mat.transpose( newPts ); + if (!useV) { + newPts = Mat.transpose(newPts); return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy(), newPts ); - //v dir + //v dir } else { return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy(), newknots, newPts ); } @@ -442,7 +442,7 @@ class Modify { // //* *Array* of NurbsCurveData objects, defined by degree, knots, and control points - public static function decomposeCurveIntoBeziers( curve : NurbsCurveData ) : Array { + public static function decomposeCurveIntoBeziers(curve:NurbsCurveData):Array { var degree = curve.degree , controlPoints = curve.controlPoints @@ -451,15 +451,15 @@ class Modify { //find all of the unique knot values and their multiplicity //for each, increase their multiplicity to degree + 1 - var knotmults = Analyze.knotMultiplicities( knots ); + var knotmults = Analyze.knotMultiplicities(knots); var reqMult = degree + 1; //insert the knots for (knotmult in knotmults) { - if ( knotmult.mult < reqMult ){ + if (knotmult.mult < reqMult) { - var knotsInsert = Vec.rep( reqMult - knotmult.mult, knotmult.knot ); - var res = curveKnotRefine( new NurbsCurveData(degree, knots, controlPoints), knotsInsert ); + var knotsInsert = Vec.rep(reqMult - knotmult.mult, knotmult.knot); + var res = curveKnotRefine(new NurbsCurveData(degree, knots, controlPoints), knotsInsert); knots = res.knots; controlPoints = res.controlPoints; @@ -472,11 +472,11 @@ class Modify { var crvs = []; var i = 0; - while ( i < controlPoints.length){ - var kts = knots.slice( i, i + crvKnotLength ); - var pts = controlPoints.slice( i, i + reqMult ); + while (i < controlPoints.length) { + var kts = knots.slice(i, i + crvKnotLength); + var pts = controlPoints.slice(i, i + reqMult); - crvs.push( new NurbsCurveData(degree, kts, pts ) ); + crvs.push(new NurbsCurveData(degree, kts, pts )); i += reqMult; } @@ -499,9 +499,9 @@ class Modify { //* NurbsCurveData object representing the curve // - public static function curveKnotRefine( curve : NurbsCurveData, knotsToInsert : Array ) : NurbsCurveData { + 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 @@ -510,57 +510,57 @@ class Modify { var n = 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 ) + , 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 - 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; var k = b + degree + r; var j = r; - while ( j >= 0 ) { + 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.add( + Vec.mul(alfa, controlPoints_post[ind - 1]), + Vec.mul((1.0 - alfa), controlPoints_post[ind])); } } @@ -595,7 +595,7 @@ class Modify { //* *Object* the new curve, defined by knots and controlPoints // - public static function curveKnotInsert( curve : NurbsCurveData, u : Float, r : Int ) : NurbsCurveData { + public static function curveKnotInsert(curve:NurbsCurveData, u:Float, r:Int):NurbsCurveData { var degree = curve.degree , controlPoints = curve.controlPoints @@ -610,7 +610,7 @@ class Modify { var s = 0; //assume original multiplicity is 0 - TODO add check for multiplicity in knots var num_pts = controlPoints.length - , k = Eval.knotSpan( degree, u, knots ) //the span in which the knot will be inserted + , k = Eval.knotSpan(degree, u, knots) //the span in which the knot will be inserted , num_pts_post = num_pts + r //a new control pt for every new knot , controlPoints_temp = new Array() //new Array( degree - s ) , knots_post = new KnotArray() //new Array( knots.length + r ) //r new knots @@ -620,62 +620,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; + 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( (1.0 - alpha), controlPoints_temp[i]), - Vec.mul( alpha, controlPoints_temp[i+1] ) - ); + 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..734c91a0 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -20,350 +20,440 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { - //Sample a NURBS curve at equally spaced parametric intervals - // + //Compute the regular tessellation step length necessary to approximate a rational Bezier curve to the specified tolerance. + // + //**params** + // + //* NurbsCurveData object representing the curve + //* The desired tolerance - the resultant + // + //**returns** + // + //* The step length - domain / step length yields the number of steps to take within the curve + + public static function rationalBezierCurveStepLength(curve:NurbsCurveData, tol:Float):Float { + + // get average pt + + var dehomo = dehomogenize1d(curve.controlPoints); + + var bb = new BoundingBox( dehomo ); + 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 tc = Modify.rationalCurveTransform(curve, m); // todo util methods for translation + dehomo = dehomogenize1d(tc.controlPoints); + + // compute r = max( || Pi || ) + + 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 = 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) { + + 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; + } + + //Sample a NURBS curve at equally spaced parametric intervals + // //**params** // //* NurbsCurveData object - //* integer number of samples - //* whether to prefix the point with the parameter - // + //* 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 rationalCurveRegularSample( curve : NurbsCurveData, numSamples : Int, includeU : Bool ) : Array { - return rationalCurveRegularSampleRange( curve, curve.knots[0], curve.knots.last(), numSamples, includeU); - } + public static function rationalCurveRegularSample(curve:NurbsCurveData, numSamples:Int, includeU:Bool):Array { + return rationalCurveRegularSampleRange(curve, curve.knots[0], curve.knots.last(), numSamples, includeU); + } - //Sample a range of a NURBS curve at equally spaced parametric intervals - // + //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 - // + //* 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 - public static function rationalCurveRegularSampleRange( curve : NurbsCurveData, start : Float, end : Float, - numSamples : Int, includeU : Bool) : Array { + public static function rationalCurveRegularSampleRange(curve:NurbsCurveData, start:Float, end:Float, + numSamples:Int, includeU:Bool):Array { - if (numSamples < 1){ - numSamples = 2; - } + if (numSamples < 1) { + numSamples = 2; + } - var p = []; - var span : Float = (end - start) / (numSamples - 1); - var u : Float = 0; + var p = []; + var span:Float = (end - start) / (numSamples - 1); + var u:Float = 0; - for (i in 0...numSamples){ + for (i in 0...numSamples) { - u = start + span * i; + u = start + span * i; - if ( includeU ){ - p.push( [u].concat( Eval.rationalCurvePoint(curve, u) ) ); - } else { - p.push( Eval.rationalCurvePoint(curve, u) ); - } + if (includeU) { + p.push([u].concat(Eval.rationalCurvePoint(curve, u))); + } else { + p.push(Eval.rationalCurvePoint(curve, u)); + } - } + } - return p; - } + return p; + } - //Sample a NURBS curve over its entire domain, corresponds to [this algorithm](http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf) - // + //Sample a NURBS curve over its entire domain, corresponds to [this algorithm](http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf) + // //**params** // //* NurbsCurveData object - //* tol for the adaptive scheme - //* whether to prefix the point with the parameter - // + //* tol for the adaptive scheme + //* whether to prefix the point with the parameter + // //**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 { + 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] ) ) ]; - } - } + //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])) ]; + } + } - return rationalCurveAdaptiveSampleRange( curve, curve.knots[0], curve.knots.last(), tol, includeU ); - } + return rationalCurveAdaptiveSampleRange(curve, curve.knots[0], curve.knots.last(), tol, includeU); + } - //Sample a NURBS curve at 3 points, facilitating adaptive sampling - // + //Sample a NURBS curve at 3 points, facilitating adaptive sampling + // //**params** // //* NurbsCurveData object - //* start parameter for sampling - //* end parameter for sampling - //* whether to prefix the point with the parameter - // + //* start parameter for sampling + //* end parameter for sampling + //* whether to prefix the point with the parameter + // //**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 rationalCurveAdaptiveSampleRange( curve : NurbsCurveData, start, end, tol, includeU ) : Array{ + public static function rationalCurveAdaptiveSampleRange(curve:NurbsCurveData, start, end, tol, includeU):Array { - //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); + //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); - //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); + //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); - //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 ) ) { + //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)) { - //get the exact middle - var exact_mid = start + (end - start) * 0.5; + //get the exact middle + var exact_mid = start + (end - start) * 0.5; - //recurse on the two halves - var left_pts = rationalCurveAdaptiveSampleRange( curve, start, exact_mid, tol, includeU ) - , right_pts = rationalCurveAdaptiveSampleRange( curve, exact_mid, end, tol, includeU ); + //recurse on the two halves + var left_pts = rationalCurveAdaptiveSampleRange(curve, start, exact_mid, tol, includeU) + , right_pts = rationalCurveAdaptiveSampleRange(curve, exact_mid, end, tol, includeU); - //concatenate the two - return left_pts.slice(0, -1).concat(right_pts); + //concatenate the two + return left_pts.slice(0, -1).concat(right_pts); - } else { - if (includeU){ - return [ [ start ].concat(p1) , [end].concat(p3) ]; - } else { - return [ p1, p3 ]; - } - } - } + } else { + if (includeU) { + return [ [ start ].concat(p1), [end].concat(p3) ]; + } else { + return [ p1, p3 ]; + } + } + } - //Tessellate a NURBS surface on equal spaced intervals in the parametric domain - // + //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 = i * span_u, + pt_v = 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 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]; - - var du = (umax - umin) / divsU - , dv = (vmax - vmin) / divsV; - - var divs = []; - var pts = []; - - // 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; - - //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 ); - } - - // 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 ) ); - } - } - - if (!options.refine) return divs; - - // 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 ); - - divs[ci].neighbors = [ s, e, n, w ]; - divs[ci].divide( options ); - } - } - - 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 triangulateAdaptiveRefinementNodeTree( arrTree : Array ) : MeshData { - - //triangulate all of the nodes of the tree - var mesh = MeshData.empty(); - for (x in arrTree) x.triangulate( mesh ); - return mesh; - - } - - 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 ); - } + 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; + + //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 divs = []; + var pts = []; + + // 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; + + //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); + } + + // 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 )); + } + } + + if (!options.refine) return divs; + + // 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); + + divs[ci].neighbors = [ s, e, n, w ]; + divs[ci].divide(options); + } + } + + 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 triangulateAdaptiveRefinementNodeTree(arrTree:Array):MeshData { + + //triangulate all of the nodes of the tree + var mesh = MeshData.empty(); + for (x in arrTree) x.triangulate(mesh); + return mesh; + + } + + 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); + } } @:expose("core.AdaptiveRefinementOptions") class AdaptiveRefinementOptions { - public var normTol : Float = 2.5e-2; - public var minDepth : Int = 0; - public var maxDepth : Int = 10; - public var refine : Bool = true; - public var minDivsU : Int = 1; - public var minDivsV : Int = 1; + public var normTol:Float = 2.5e-2; + public var minDepth:Int = 0; + public var maxDepth:Int = 10; + public var refine:Bool = true; + public var minDivsU:Int = 1; + public var minDivsV:Int = 1; - public function new(){} + public function new() {} } @@ -394,19 +484,19 @@ class AdaptiveRefinementOptions { @:expose("core.AdaptiveRefinementNode") class AdaptiveRefinementNode { - var srf : NurbsSurfaceData; - public var neighbors : Array; - var children : Array; - var corners : Array; - var midPoints : Array; - var centerPoint : SurfacePoint; - var splitVert : Bool; - var splitHoriz : Bool; - var horizontal : Bool; - var u05 : Float; - var v05 : Float; + var srf:NurbsSurfaceData; + public var neighbors:Array; + var children:Array; + var corners:Array; + var midPoints:Array; + var centerPoint:SurfacePoint; + var splitVert:Bool; + var splitHoriz:Bool; + var horizontal:Bool; + var u05:Float; + var v05:Float; - public function new( srf : NurbsSurfaceData, corners : Array, neighbors : Array = null ) { + public function new(srf:NurbsSurfaceData, corners:Array, neighbors:Array = null) { this.srf = srf; @@ -415,349 +505,349 @@ class AdaptiveRefinementNode { this.corners = corners; //if no corners, we need to construct initial corners from the surface - if (this.corners == null){ - var u0 : Float = srf.knotsU[0]; - var u1 : Float = srf.knotsU.last(); - var v0 : Float = srf.knotsV[0]; - var v1 : Float = srf.knotsV.last(); + if (this.corners == null) { + var u0:Float = srf.knotsU[0]; + var u1:Float = srf.knotsU.last(); + var v0:Float = srf.knotsV[0]; + 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(){ - return this.centerPoint != null ? this.centerPoint : this.evalSrf( this.u05, this.v05 ); + 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 + //eval all of the corners for (i in 0...4) { -//if it's not already evaluated - if ( this.corners[i].point == null ){ -//evaluate it + //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 ); + this.evalSrf(c.uv[0], c.uv[1], c); } } } - public function evalSrf( u : Float, v : Float, srfPt : SurfacePoint = null ) : SurfacePoint { + public function evalSrf(u:Float, v:Float, srfPt:SurfacePoint = null):SurfacePoint { - var derivs = Eval.rationalSurfaceDerivatives( this.srf, u, v, 1 ); + 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 degen = Vec.isZero( norm ); + 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 { + 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: - return this.children[0].getEdgeCorners( 0 ); + return this.children[0].getEdgeCorners(0); case 1: - return this.children[0].getEdgeCorners( 1 ).concat( this.children[1].getEdgeCorners( 1 ) ); + return this.children[0].getEdgeCorners(1).concat(this.children[1].getEdgeCorners(1)); case 2: - return this.children[1].getEdgeCorners( 2 ); + return this.children[1].getEdgeCorners(2); case 3: - return this.children[1].getEdgeCorners( 3 ).concat( this.children[0].getEdgeCorners( 3 ) ); + return this.children[1].getEdgeCorners(3).concat(this.children[0].getEdgeCorners(3)); } } -//vertical case + //vertical case switch (edgeIndex) { case 0: - return this.children[0].getEdgeCorners( 0 ).concat( this.children[1].getEdgeCorners( 0 ) ); + return this.children[0].getEdgeCorners(0).concat(this.children[1].getEdgeCorners(0)); case 1: - return this.children[1].getEdgeCorners( 1 ); + return this.children[1].getEdgeCorners(1); case 2: - return this.children[1].getEdgeCorners( 2 ).concat( this.children[0].getEdgeCorners( 2 ) ); + return this.children[1].getEdgeCorners(2).concat(this.children[0].getEdgeCorners(2)); case 3: - return this.children[0].getEdgeCorners( 3 ); + return this.children[0].getEdgeCorners(3); } return null; } - public function getAllCorners( edgeIndex : Int ) : Array { + public function getAllCorners(edgeIndex:Int):Array { var baseArr = [ this.corners[edgeIndex] ]; - if ( this.neighbors[edgeIndex] == null ) { + if (this.neighbors[edgeIndex] == null) { return baseArr; } -//get opposite edges uvs - var corners = this.neighbors[edgeIndex].getEdgeCorners( ( edgeIndex + 2 ) % 4 ); + //get opposite edges uvs + var corners = this.neighbors[edgeIndex].getEdgeCorners(( edgeIndex + 2 ) % 4); var funcIndex = edgeIndex % 2; 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 - var cornercopy = corners.filter( rangeFuncMap[ funcIndex ] ); + //clip the range of uvs to match this one + var cornercopy = corners.filter(rangeFuncMap[ funcIndex ]); cornercopy.reverse(); - return baseArr.concat( cornercopy ); + 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]; switch (index){ case 0: - this.midPoints[0] = this.evalSrf( this.u05, this.corners[0].uv[1] ); + this.midPoints[0] = this.evalSrf(this.u05, this.corners[0].uv[1]); case 1: - this.midPoints[1] = this.evalSrf( this.corners[1].uv[0], this.v05 ); + this.midPoints[1] = this.evalSrf(this.corners[1].uv[0], this.v05); case 2: - this.midPoints[2] = this.evalSrf( this.u05, this.corners[2].uv[1] ); + this.midPoints[2] = this.evalSrf(this.u05, this.corners[2].uv[1]); case 3: - this.midPoints[3] = this.evalSrf( this.corners[0].uv[0], this.v05 ); + this.midPoints[3] = this.evalSrf(this.corners[0].uv[0], this.v05); } return this.midPoints[index]; } - 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 + //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 (currentDepth < options.minDepth) return true; + if (currentDepth >= options.maxDepth) return false; - if ( this.hasBadNormals() ) { + if (this.hasBadNormals()) { this.fixNormals(); -//don't divide any further when encountering a degenerate normal + //don't divide any further when encountering a degenerate normal return false; } - this.splitVert = Vec.normSquared( Vec.sub( this.corners[0].normal, this.corners[1].normal ) ) > options.normTol || - Vec.normSquared( Vec.sub( this.corners[2].normal, this.corners[3].normal ) ) > options.normTol; + this.splitVert = Vec.normSquared(Vec.sub(this.corners[0].normal, this.corners[1].normal)) > options.normTol || + Vec.normSquared(Vec.sub(this.corners[2].normal, this.corners[3].normal)) > options.normTol; - this.splitHoriz = Vec.normSquared( Vec.sub( this.corners[1].normal, this.corners[2].normal ) ) > options.normTol || - Vec.normSquared( Vec.sub( this.corners[3].normal, this.corners[0].normal ) ) > options.normTol; + this.splitHoriz = Vec.normSquared(Vec.sub(this.corners[1].normal, this.corners[2].normal)) > options.normTol || + Vec.normSquared(Vec.sub(this.corners[3].normal, this.corners[0].normal)) > options.normTol; - if ( this.splitVert || this.splitHoriz ) return true; + if (this.splitVert || this.splitHoriz) return true; 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 || - Vec.normSquared( Vec.sub( center.normal, this.corners[2].normal ) ) > options.normTol || - Vec.normSquared( Vec.sub( center.normal, this.corners[3].normal ) ) > options.normTol; + 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 || + Vec.normSquared(Vec.sub(center.normal, this.corners[2].normal)) > options.normTol || + Vec.normSquared(Vec.sub(center.normal, this.corners[3].normal)) > options.normTol; } - public function divide( options : AdaptiveRefinementOptions = null ) : Void { + 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 (!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 + #end - this._divide( options, 0, true ); + this._divide(options, 0, true); } - private function _divide( options : AdaptiveRefinementOptions, currentDepth : Int, horiz : Bool ) : Void { + private function _divide(options:AdaptiveRefinementOptions, currentDepth:Int, horiz:Bool):Void { 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? + //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){ - child._divide( options, currentDepth, !horiz ); + //divide all children recursively + for (child in this.children) { + child._divide(options, currentDepth, !horiz); } } - public function triangulate( mesh : MeshData = null ) : MeshData { + public function triangulate(mesh:MeshData = null):MeshData { 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){ + //recurse on the children + for (x in this.children) { if (x == null) break; - x.triangulate( mesh ); + 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); -//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 (corner in uvs){ + for (corner in uvs) { -//if the id is defined, we can just push it and continue - if (corner.id != -1){ + //if the id is defined, we can just push it and continue + if (corner.id != -1) { ids.push(corner.id); continue; } - mesh.uvs.push( corner.uv ); - mesh.points.push( corner.point ); - mesh.normals.push( corner.normal ); + mesh.uvs.push(corner.uv); + mesh.points.push(corner.point); + mesh.normals.push(corner.normal); corner.id = baseIndex; - ids.push( baseIndex ); + ids.push(baseIndex); 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 - mesh.faces.push( [ ids[0], ids[3], ids[1] ] ); - mesh.faces.push( [ ids[3], ids[2], ids[1] ] ); + //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 - 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 ] ]); + //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 ] ]); return mesh; } -//make point at center of face + //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 ); + 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++; } diff --git a/src/verb/exe/Dispatcher.hx b/src/verb/exe/Dispatcher.hx index 8ae053c7..7dd2c587 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; @@ -12,43 +12,43 @@ import promhx.Promise; @:expose("exe.Dispatcher") class Dispatcher { - public static var THREADS : Int = 1; + 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 var _init:Bool = false; - private static function init() : Void { + private static function init():Void { 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; } - public static function dispatchMethod( classType : Class, methodName : String, args : Array ) : Promise { + public static function dispatchMethod(classType:Class, methodName:String, args:Array):Promise { init(); var def = new Deferred(); - var callback = function(x){ - def.resolve( 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..74c58a12 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 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 numThreads:Int = 1; + private var threads:Array; + #end private var tasks:Array; private var nextID:Int = 0; - public function new(numThreads:Int) - { + 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 - { - tasks.push( { id: nextID, task: task, done: false, arg: arg, #if (neko || cpp) thread: null, #end onFinish: onFinish } ); - nextID++; - } + 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++; + } - #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..ecccbe6b 100644 --- a/src/verb/exe/WorkerPool.hx +++ b/src/verb/exe/WorkerPool.hx @@ -11,8 +11,8 @@ import js.html.Worker; @:expose("exe.WorkerPool") class WorkerPool { - private var _queue : Array = []; - private var _pool : Array = []; + private var _queue:Array = []; + private var _pool:Array = []; private var _working = new IntMap(); private var _callbacks = new IntMap(); @@ -23,34 +23,34 @@ class WorkerPool { //* the number of `Worker` threads to form //* the filename of verb's javascript file - defaults to "verb.js". The final path is formed by concatenating `WorkerPool.basePath` and this. - public function new( numThreads : Int = 1, fileName : String = "verb.js" ) { + public function new(numThreads:Int = 1, fileName:String = "verb.js") { - for (i in 0...numThreads){ - var w : Worker; + 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 - public function addWork( className : String, - methodName : String, - args : Array, - callback : Dynamic ) : Void { + public function addWork(className:String, + methodName:String, + args:Array, + callback:Dynamic):Void { var work = new Work( className, methodName, args ); _callbacks.set(work.id, callback); - _queue.push( work ); + _queue.push(work); processQueue(); } @@ -67,25 +67,24 @@ class WorkerPool { _working.set(workId, worker); //upon completing your task... - worker.onmessage = function( e ){ + worker.onmessage = function(e) { - _working.remove( workId ); - _pool.push( worker ); + _working.remove(workId); + _pool.push(worker); try { - if ( _callbacks.exists( workId ) ) - { - _callbacks.get( workId )( e.data.result ); - _callbacks.remove( workId ); + if (_callbacks.exists(workId)) { + _callbacks.get(workId)(e.data.result); + _callbacks.remove(workId); } - } catch(error : Dynamic) { - trace( error ); + } catch (error:Dynamic) { + trace(error); } processQueue(); }; - worker.postMessage( work ); + worker.postMessage(work); } } @@ -93,14 +92,14 @@ class WorkerPool { private class Work { - private static var uuid : Int = 0; + private static var uuid:Int = 0; - public var className : String; - public var methodName : String; - public var args : Array; - public var id : Int; + public var className:String; + public var methodName:String; + 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..10594edf 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; @@ -40,29 +40,35 @@ class Arc extends NurbsCurve { _maxAngle = maxAngle; } - private var _center : Point; - private var _xaxis : Vector; - private var _yaxis : Vector; - private var _radius : Float; - private var _minAngle : Float; - private var _maxAngle : Float; + private var _center:Point; + private var _xaxis:Vector; + private var _yaxis:Vector; + private var _radius:Float; + private var _minAngle:Float; + 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/BezierCurve.hx b/src/verb/geom/BezierCurve.hx index 3e7e2241..b1b06404 100644 --- a/src/verb/geom/BezierCurve.hx +++ b/src/verb/geom/BezierCurve.hx @@ -17,7 +17,7 @@ class BezierCurve extends NurbsCurve { //* Array of control points //* Array of control point weights (optional) - public function new( points : Array, weights : Array = null ) { - super( Make.rationalBezierCurve( points, weights ) ); + public function new(points:Array, weights:Array = null) { + super(Make.rationalBezierCurve(points, weights)); } } \ No newline at end of file diff --git a/src/verb/geom/Circle.hx b/src/verb/geom/Circle.hx index 351b47cd..6e3aff75 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 ) { - super( center, xaxis, yaxis, radius, 0, Math.PI * 2 ); + 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..fa733361 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; @@ -29,25 +29,30 @@ class ConicalSurface extends NurbsSurface { _radius = radius; } - private var _axis : Vector; - private var _xaxis : Vector; - private var _base : Point; - private var _height : Float; - private var _radius : Float; + private var _axis:Vector; + private var _xaxis:Vector; + private var _base:Point; + private var _height:Float; + 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..a6fc1fe4 100644 --- a/src/verb/geom/CylindricalSurface.hx +++ b/src/verb/geom/CylindricalSurface.hx @@ -21,7 +21,7 @@ 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) { + public function new(axis:Vector, xaxis:Vector, base:Point, height:Float, radius:Float) { super(Make.cylindricalSurface(axis, xaxis, base, height, radius)); _axis = axis; @@ -31,24 +31,29 @@ class CylindricalSurface extends NurbsSurface { _radius = radius; } - private var _axis : Vector; - private var _xaxis : Vector; - private var _base : Point; - private var _height : Float; - private var _radius : Float; + private var _axis:Vector; + private var _xaxis:Vector; + private var _base:Point; + private var _height:Float; + 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..4749180b 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 ) { - super( center, xaxis, yaxis, 0, Math.PI * 2 ); + 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..d0bacfbe 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; @@ -34,26 +34,31 @@ class EllipseArc extends NurbsCurve { _maxAngle = maxAngle; } - private var _center : Point; - private var _xaxis : Vector; - private var _yaxis : Vector; - private var _minAngle : Float; - private var _maxAngle : Float; + private var _center:Point; + private var _xaxis:Vector; + private var _yaxis:Vector; + private var _minAngle:Float; + 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..ee20b7d2 100644 --- a/src/verb/geom/ExtrudedSurface.hx +++ b/src/verb/geom/ExtrudedSurface.hx @@ -15,22 +15,22 @@ class ExtrudedSurface extends NurbsSurface { //* The profile curve //* 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() )); + public function new(profile:ICurve, direction:Vector) { + super(Make.extrudedSurface(Vec.normalized(direction), Vec.norm(direction), profile.asNurbs())); _profile = profile; _direction = direction; } - private var _profile : ICurve; - private var _direction : Vector; + private var _profile:ICurve; + private var _direction:Vector; //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..679ea89d 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..57fc9494 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..3607bd51 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 ]); + 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 ]); } //Determine the intersection of a curve and a surface @@ -50,14 +50,14 @@ 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); + public static function curveAndSurface(curve:ICurve, surface:ISurface, tol:Float = 1e-3):Array { + 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 ]); + 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 ]); } //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..4386d52a 100644 --- a/src/verb/geom/Line.hx +++ b/src/verb/geom/Line.hx @@ -17,20 +17,22 @@ class Line extends NurbsCurve { //* Length 3 array representing the start point //* Length 3 array representing the end point - public function new( start : Point, end : Point ) { - super( Make.polyline( [ start, end ] ) ); + public function new(start:Point, end:Point) { + super(Make.polyline([ start, end ])); _start = start; _end = end; } - private var _start : Point; - private var _end : Point; + private var _start:Point; + 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 5bf72216..f5fc77a3 100644 --- a/src/verb/geom/NurbsCurve.hx +++ b/src/verb/geom/NurbsCurve.hx @@ -42,8 +42,8 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public function new( data : NurbsCurveData ) { - this._data = Check.isValidNurbsCurveData( data ); + public function new(data:NurbsCurveData) { + this._data = Check.isValidNurbsCurveData(data); } //Construct a NurbsCurve by degree, knots, control points, weights @@ -59,11 +59,11 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public static function byKnotsControlPointsWeights( degree : Int, - knots : KnotArray, - controlPoints : Array, - weights : Array = null ) : NurbsCurve { - return new NurbsCurve( new NurbsCurveData( degree, knots.copy(), Eval.homogenize1d( controlPoints, weights) ) ); + public static function byKnotsControlPointsWeights(degree:Int, + knots:KnotArray, + controlPoints:Array, + weights:Array = null):NurbsCurve { + return new NurbsCurve( new NurbsCurveData( degree, knots.copy(), Eval.homogenize1d(controlPoints, weights) ) ); } //Construct a NurbsCurve by interpolating a collection of points. The resultant curve @@ -78,24 +78,28 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public static function byPoints( points : Array, degree : Int = 3 ) : NurbsCurve { + public static function byPoints(points:Array, degree:Int = 3):NurbsCurve { return new NurbsCurve( Make.rationalInterpCurve(points, degree) ); } //underlying serializable, data object - private var _data : NurbsCurveData; + 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. // @@ -103,8 +107,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 @@ -113,7 +117,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The copied curve - public function clone(){ + public function clone() { return new NurbsCurve( this._data ); } @@ -123,7 +127,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* An array representing the high and end point of the domain of the curve - public function domain() : Interval { + public function domain():Interval { return new Interval( _data.knots.first(), _data.knots.last()); } @@ -137,15 +141,15 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function transform( mat : Matrix ) : NurbsCurve { - return new NurbsCurve( Modify.rationalCurveTransform( _data, mat ) ); + public function transform(mat:Matrix):NurbsCurve { + return new NurbsCurve( Modify.rationalCurveTransform(_data, mat) ); } //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); }); + public function transformAsync(mat:Matrix):Promise { + return Dispatcher.dispatchMethod(Modify, 'rationalCurveTransform', [ _data, mat ]) + .then(function(x) { return new NurbsCurve(x); }); } //Sample a point at the given parameter @@ -158,14 +162,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function point( u : Float ) : Point { - return Eval.rationalCurvePoint( _data, u ); + public function point(u:Float):Point { + return Eval.rationalCurvePoint(_data, u); } //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 @@ -179,14 +183,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function tangent( u : Float ) : Vector { - return Eval.rationalCurveTangent( _data, u ); + public function tangent(u:Float):Vector { + return Eval.rationalCurveTangent(_data, u); } //The async version of `tangent` - public function tangentAsync( u : Float ) : Promise { - return Dispatcher.dispatchMethod( Eval, 'rationalCurveTangent', [ _data, u ] ); + public function tangentAsync(u:Float):Promise { + return Dispatcher.dispatchMethod(Eval, 'rationalCurveTangent', [ _data, u ]); } //Get derivatives at a given parameter @@ -200,14 +204,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function derivatives( u : Float, numDerivs : Int = 1 ) : Array { - return Eval.rationalCurveDerivatives( _data, u, numDerivs ); + public function derivatives(u:Float, numDerivs:Int = 1):Array { + return Eval.rationalCurveDerivatives(_data, u, numDerivs); } //The async version of `derivatives` - public function derivativesAsync( u : Float, numDerivs : Int = 1 ) : Promise> { - return Dispatcher.dispatchMethod( Eval, 'rationalCurveDerivatives', [ _data, u, numDerivs ] ); + public function derivativesAsync(u:Float, numDerivs:Int = 1):Promise> { + return Dispatcher.dispatchMethod(Eval, 'rationalCurveDerivatives', [ _data, u, numDerivs ]); } //Determine the closest point on the curve to the given point @@ -220,14 +224,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The closest point - public function closestPoint( pt : Point ) : Point { - return Analyze.rationalCurveClosestPoint( _data, pt ); + public function closestPoint(pt:Point):Point { + return Analyze.rationalCurveClosestPoint(_data, pt); } //The async version of `closestPoint` - public function closestPointAsync( pt : Point ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestPoint', [ _data, pt ] ); + public function closestPointAsync(pt:Point):Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalCurveClosestPoint', [ _data, pt ]); } //Determine the closest parameter on the curve to the given point @@ -240,14 +244,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The closest parameter - public function closestParam( pt : Point ) : Float { - return Analyze.rationalCurveClosestParam( _data, pt ); + public function closestParam(pt:Point):Float { + return Analyze.rationalCurveClosestParam(_data, pt); } //The async version of `length` - public function closestParamAsync( pt : Dynamic ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestParam', [ _data, pt ] ); + public function closestParamAsync(pt:Dynamic):Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalCurveClosestParam', [ _data, pt ]); } //Determine the arc length of the curve @@ -256,14 +260,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve - public function length() : Float { - return Analyze.rationalCurveArcLength( _data ); + public function length():Float { + return Analyze.rationalCurveArcLength(_data); } //The async version of `length` - public function lengthAsync() : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveArcLength', [ _data ] ); + public function lengthAsync():Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalCurveArcLength', [ _data ]); } //Determine the arc length of the curve at the given parameter @@ -276,14 +280,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve at the given parameter - public function lengthAtParam( u : Float ) : Float { - return Analyze.rationalCurveArcLength( _data, u ); + public function lengthAtParam(u:Float):Float { + return Analyze.rationalCurveArcLength(_data, u); } //The async version of `lengthAtParam` - public function lengthAtParamAsync() : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveArcLength', [ _data ] ); + public function lengthAtParamAsync():Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalCurveArcLength', [ _data ]); } //Determine the parameter of the curve at the given arc length @@ -296,14 +300,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve at the given parameter - public function paramAtLength( len : Float, tolerance : Float = null ) : Float { - return Analyze.rationalCurveParamAtArcLength( _data, len, tolerance ); + public function paramAtLength(len:Float, tolerance:Float = null):Float { + return Analyze.rationalCurveParamAtArcLength(_data, len, tolerance); } //The async version of `paramAtLength` - public function paramAtLengthAsync( len : Float, tolerance : Float = null ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalCurveParamAtArcLength', [ _data, len, tolerance ] ); + public function paramAtLengthAsync(len:Float, tolerance:Float = null):Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalCurveParamAtArcLength', [ _data, len, tolerance ]); } //Determine the parameters necessary to divide the curve into equal arc length segments @@ -316,14 +320,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A collection of parameters - public function divideByEqualArcLength( divisions : Int ) : Array { - return Divide.rationalCurveByEqualArcLength( _data, divisions ); + public function divideByEqualArcLength(divisions:Int):Array { + return Divide.rationalCurveByEqualArcLength(_data, divisions); } //The async version of `divideByEqualArcLength`` - public function divideByEqualArcLengthAsync( divisions : Int ) : Promise> { - return Dispatcher.dispatchMethod( Divide, 'rationalCurveByEqualArcLength', [ _data, divisions ] ); + public function divideByEqualArcLengthAsync(divisions:Int):Promise> { + return Dispatcher.dispatchMethod(Divide, 'rationalCurveByEqualArcLength', [ _data, divisions ]); } //Given the distance to divide the curve, determine the parameters necessary to divide the curve into equal arc length segments @@ -336,14 +340,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A collection of parameters - public function divideByArcLength( arcLength : Float ) : Array { - return Divide.rationalCurveByArcLength( _data, arcLength ); + public function divideByArcLength(arcLength:Float):Array { + return Divide.rationalCurveByArcLength(_data, arcLength); } //The async version of `divideByArcLength` - public function divideByArcLengthAsync( divisions : Int ) : Promise> { - return Dispatcher.dispatchMethod( Divide, 'rationalCurveByArcLength', [ _data, divisions ] ); + public function divideByArcLengthAsync(divisions:Int):Promise> { + return Dispatcher.dispatchMethod(Divide, 'rationalCurveByArcLength', [ _data, divisions ]); } //Split the curve at the given parameter @@ -356,16 +360,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); }); + public function split(u:Float):Array { + 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); }); + 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); }); }); } @@ -375,15 +379,15 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A reversed curve - public function reverse() : NurbsCurve { - return new NurbsCurve( Modify.curveReverse( _data ) ); + 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 @@ -396,14 +400,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function tessellate(tolerance : Float = null) : Array { - return Tess.rationalCurveAdaptiveSample( _data, tolerance, false ); + public function tessellate(tolerance:Float = null):Array { + return Tess.rationalCurveAdaptiveSample(_data, tolerance, false); } // The async version of `tessellate` - public function tessellateAsync( tolerance : Float = null ) : Promise> { - return Dispatcher.dispatchMethod( Tess, 'rationalCurveAdaptiveSample', [ _data, tolerance, false ] ); + public function tessellateAsync(tolerance:Float = null):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..64ea35d3 100644 --- a/src/verb/geom/NurbsSurface.hx +++ b/src/verb/geom/NurbsSurface.hx @@ -40,7 +40,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public function new( data : NurbsSurfaceData ) { + public function new(data:NurbsSurfaceData) { _data = Check.isValidNurbsSurfaceData(data); } @@ -60,12 +60,12 @@ 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 { + 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) ) ); } @@ -82,8 +82,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public static function byCorners( point0 : Point, point1 : Point, point2 : Point, point3 : Point ) : NurbsSurface { - return new NurbsSurface( Make.fourPointSurface( point0, point1, point2, point3 ) ); + public static function byCorners(point0:Point, point1:Point, point2:Point, point3:Point):NurbsSurface { + return new NurbsSurface( Make.fourPointSurface(point0, point1, point2, point3) ); } //Construct a NurbsSurface by lofting between a collection of curves @@ -96,38 +96,38 @@ 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 )); + public static function byLoftingCurves(curves:Array, degreeV:Int = null):NurbsSurface { + return new NurbsSurface( Make.loftedSurface([for (c in curves) c.asNurbs() ], degreeV)); } //underlying serializable, data object - private var _data : NurbsSurfaceData; + private var _data:NurbsSurfaceData; //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,7 +145,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public function clone() : NurbsSurface { + public function clone():NurbsSurface { return new NurbsSurface( asNurbs() ); } @@ -155,7 +155,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* An Interval object with min and max property - public function domainU() : Interval { + public function domainU():Interval { return new Interval( _data.knotsU.first(), _data.knotsU.last()); } @@ -165,7 +165,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* An Interval object with min and max property - public function domainV() : Interval { + public function domainV():Interval { return new Interval( _data.knotsV.first(), _data.knotsV.last()); } @@ -180,14 +180,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A point on the surface - public function point( u : Float, v : Float ) : Point { - return Eval.rationalSurfacePoint( _data, u, v ); + public function point(u:Float, v:Float):Point { + return Eval.rationalSurfacePoint(_data, u, v); } //The async version of `point` - public function pointAsync( u : Float, v : Float ) : Promise { - return Dispatcher.dispatchMethod( Eval, 'rationalSurfacePoint', [ _data, u, v ] ); + public function pointAsync(u:Float, v:Float):Promise { + return Dispatcher.dispatchMethod(Eval, 'rationalSurfacePoint', [ _data, u, v ]); } //Obtain the normal to the surface at the given parameter @@ -201,14 +201,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A normalized vector normal to the surface - public function normal( u : Float, v : Float ) : Point { - return Eval.rationalSurfaceNormal( _data, u, v ); + public function normal(u:Float, v:Float):Point { + return Eval.rationalSurfaceNormal(_data, u, v); } //The async version of `normal` - public function normalAsync( u : Float, v : Float ) : Promise>> { - return Dispatcher.dispatchMethod( Eval, 'rationalSurfaceNormal', [ _data, u, v ] ); + public function normalAsync(u:Float, v:Float):Promise>> { + return Dispatcher.dispatchMethod(Eval, 'rationalSurfaceNormal', [ _data, u, v ]); } //Obtain the derivatives of the NurbsSurface. Returns a two dimensional array @@ -227,14 +227,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A two dimensional array of vectors - public function derivatives( u : Float, v : Float, numDerivs : Int = 1 ) : Array> { - return Eval.rationalSurfaceDerivatives( _data, u, v, numDerivs ); + public function derivatives(u:Float, v:Float, numDerivs:Int = 1):Array> { + return Eval.rationalSurfaceDerivatives(_data, u, v, numDerivs); } //The async version of `derivatives` - public function derivativesAsync( u : Float, v : Float, numDerivs : Int = 1 ) : Promise>> { - return Dispatcher.dispatchMethod( Eval, 'rationalSurfaceDerivatives', [ _data, u, v, numDerivs ] ); + public function derivativesAsync(u:Float, v:Float, numDerivs:Int = 1):Promise>> { + return Dispatcher.dispatchMethod(Eval, 'rationalSurfaceDerivatives', [ _data, u, v, numDerivs ]); } @@ -248,14 +248,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The closest point - public function closestParam( pt : Point ) : UV { - return Analyze.rationalSurfaceClosestParam( _data, pt ); + public function closestParam(pt:Point):UV { + return Analyze.rationalSurfaceClosestParam(_data, pt); } //The async version of `closestParam` - public function closestParamAsync( pt : Point ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalSurfaceClosestParam', [ _data, pt ] ); + public function closestParamAsync(pt:Point):Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalSurfaceClosestParam', [ _data, pt ]); } //Get the closest point on the surface to a point @@ -268,14 +268,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The closest point - public function closestPoint( pt : Point ) : Point { - return Analyze.rationalSurfaceClosestPoint( _data, pt ); + public function closestPoint(pt:Point):Point { + return Analyze.rationalSurfaceClosestPoint(_data, pt); } //The async version of `closestParam` - public function closestPointAsync( pt : Point ) : Promise { - return Dispatcher.dispatchMethod( Analyze, 'rationalSurfaceClosestPoint', [ _data, pt ] ); + public function closestPointAsync(pt:Point):Promise { + return Dispatcher.dispatchMethod(Analyze, 'rationalSurfaceClosestPoint', [ _data, pt ]); } //Split a surface @@ -289,18 +289,18 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A length 2 array with two new NurbsSurface objects - public function split( u : Float, useV : Bool = false ) : Array { - return Divide.surfaceSplit( _data, u, useV ) - .map(function(x){ return new NurbsSurface(x); }); + public function split(u:Float, useV:Bool = false):Array { + return Divide.surfaceSplit(_data, u, useV) + .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); }); - }); + 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); }); + }); } //Reverse the parameterization of the curve @@ -313,15 +313,15 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The reversed surface - public function reverse( useV : Bool = false ) : NurbsSurface { - return new NurbsSurface( Modify.surfaceReverse( _data, useV ) ); + public function reverse(useV:Bool = false):NurbsSurface { + return new NurbsSurface( Modify.surfaceReverse(_data, useV) ); } //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); }); + public function reverseAsync(useV:Bool = false):Promise { + return Dispatcher.dispatchMethod(Modify, 'surfaceReverse', [ _data, useV ]) + .then(function(c) { return new NurbsSurface(c); }); } //Extract an isocurve from a surface @@ -335,15 +335,15 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A NurbsCurve in the provided direction - public function isocurve( u : Float, useV : Bool = false ) : NurbsCurve { - return new NurbsCurve( Make.surfaceIsocurve( _data, u, useV ) ); + public function isocurve(u:Float, useV:Bool = false):NurbsCurve { + return new NurbsCurve( Make.surfaceIsocurve(_data, u, useV) ); } //The async version of `isocurve` - public function isocurveAsync( u : Float, useV : Bool = false ) : Promise { - return Dispatcher.dispatchMethod( Make, 'surfaceIsocurve', [ _data, u, useV ] ) - .then(function(x){ return new NurbsCurve(x); }); + public function isocurveAsync(u:Float, useV:Bool = false):Promise { + return Dispatcher.dispatchMethod(Make, 'surfaceIsocurve', [ _data, u, useV ]) + .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); }); - }); + 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); }); + }); } @@ -376,14 +376,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A MeshData object - public function tessellate( options : AdaptiveRefinementOptions = null) : MeshData { - return Tess.rationalSurfaceAdaptive( _data, options ); + 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 ] ); + public function tessellateAsync(options:AdaptiveRefinementOptions = null):Promise { + return Dispatcher.dispatchMethod(Tess, 'rationalSurfaceAdaptive', [ _data, options ]); } //Transform a Surface with the given matrix. @@ -396,14 +396,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new Surface - public function transform( mat : Matrix ) : NurbsSurface { - return new NurbsSurface( Modify.rationalSurfaceTransform( _data, mat ) ); + public function transform(mat:Matrix):NurbsSurface { + return new NurbsSurface( Modify.rationalSurfaceTransform(_data, mat) ); } //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); }); + public function transformAsync(mat:Matrix):Promise { + 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..5d7842b9 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; @@ -27,25 +27,25 @@ class RevolvedSurface extends NurbsSurface { _angle = angle; } - private var _profile : ICurve; - private var _center : Point; - private var _axis : Vector; - private var _angle : Float; + private var _profile:ICurve; + private var _center:Point; + private var _axis:Vector; + private var _angle:Float; //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..43b65603 100644 --- a/src/verb/geom/SphericalSurface.hx +++ b/src/verb/geom/SphericalSurface.hx @@ -17,24 +17,24 @@ 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; } - private var _center : Point; - private var _radius : Float; + private var _center:Point; + private var _radius:Float; //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..a0e346e4 100644 --- a/src/verb/geom/SweptSurface.hx +++ b/src/verb/geom/SweptSurface.hx @@ -17,23 +17,23 @@ class SweptSurface extends NurbsSurface { //* The profile curve //* The rail curve - public function new( profile : ICurve, rail : ICurve ) { - super( Make.rationalTranslationalSurface( profile.asNurbs(), rail.asNurbs() )); + public function new(profile:ICurve, rail:ICurve) { + super(Make.rationalTranslationalSurface(profile.asNurbs(), rail.asNurbs())); _profile = profile; _rail = rail; } - private var _profile : ICurve; - private var _rail : ICurve; + private var _profile:ICurve; + private var _rail:ICurve; //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/testEval.js b/test/testEval.js index fa904d10..5d577485 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,7 +20,9 @@ function last(a){ return a[a.length-1]; } -describe("verb.eval.Eval.knotSpanGivenN",() => { +/* + +describe("verb.eval.Eval.knotSpanGivenN",function(){ it('returns correct result', () => { @@ -3889,6 +3891,7 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { }); }); +*/ describe("verb.eval.Modify.decomposeCurveIntoBeziers",() => { @@ -3997,3 +4000,15 @@ describe("verb.eval.Eval.rationalCurveRegularSamplePoints",() => { }); +describe("verb.eval.Eval.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 ); + + }); +}); + From ddd16745a1f84cbfb1d97b0bb16181316365eab5 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Tue, 10 Nov 2015 15:30:19 -0500 Subject: [PATCH 09/25] more code reformatting --- build/js/verb.js | 146 +++++----- build/js/verbHaxe.js | 146 +++++----- examples/conics.html | 2 + src/verb/Verb.hx | 2 +- src/verb/core/ArrayExtensions.hx | 18 +- src/verb/core/Binomial.hx | 12 +- src/verb/core/BoundingBox.hx | 28 +- src/verb/core/Constants.hx | 6 +- src/verb/core/Data.hx | 64 ++-- src/verb/core/Intersections.hx | 82 +++--- src/verb/core/KdTree.hx | 56 ++-- src/verb/core/LazyCurveBoundingBoxTree.hx | 12 +- src/verb/core/LazyMeshBoundingBoxTree.hx | 10 +- src/verb/core/LazyPolylineBoundingBoxTree.hx | 10 +- src/verb/core/LazySurfaceBoundingBoxTree.hx | 18 +- src/verb/core/Mat.hx | 28 +- src/verb/core/Mesh.hx | 14 +- src/verb/core/MeshBoundingBoxTree.hx | 14 +- src/verb/core/Minimizer.hx | 18 +- src/verb/core/Serialization.hx | 8 +- src/verb/core/SurfaceBoundingBoxTree.hx | 14 +- src/verb/core/Trig.hx | 6 +- src/verb/core/Vec.hx | 82 +++--- src/verb/eval/Analyze.hx | 54 ++-- src/verb/eval/Check.hx | 8 +- src/verb/eval/Divide.hx | 14 +- src/verb/eval/Eval.hx | 290 ++++++------------- src/verb/eval/Intersect.hx | 116 ++++---- src/verb/eval/Make.hx | 48 +-- src/verb/eval/Modify.hx | 32 +- src/verb/eval/Tess.hx | 242 ++++++++++++---- src/verb/exe/Dispatcher.hx | 14 +- src/verb/exe/ThreadPool.hx | 58 ++-- src/verb/exe/WorkerPool.hx | 30 +- src/verb/geom/Arc.hx | 36 +-- src/verb/geom/BezierCurve.hx | 2 +- src/verb/geom/Circle.hx | 8 +- src/verb/geom/ConicalSurface.hx | 12 +- src/verb/geom/CylindricalSurface.hx | 12 +- src/verb/geom/Ellipse.hx | 6 +- src/verb/geom/EllipseArc.hx | 20 +- src/verb/geom/ExtrudedSurface.hx | 10 +- src/verb/geom/ICurve.hx | 8 +- src/verb/geom/ISurface.hx | 10 +- src/verb/geom/Intersect.hx | 12 +- src/verb/geom/Line.hx | 6 +- src/verb/geom/NurbsCurve.hx | 84 +++--- src/verb/geom/NurbsSurface.hx | 86 +++--- src/verb/geom/RevolvedSurface.hx | 18 +- src/verb/geom/SphericalSurface.hx | 12 +- src/verb/geom/SweptSurface.hx | 10 +- 51 files changed, 1046 insertions(+), 1008 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index 2fe827ca..9ffac30b 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -4094,79 +4094,6 @@ verb_eval_CurveLengthSample.prototype = { 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.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_Eval.secondForwardDiff(wts); - var pts = verb_eval_Eval.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_Eval.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_Eval.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_Eval.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_Eval.rationalCurveTangent = function(curve,u) { var derivs = verb_eval_Eval.rationalCurveDerivatives(curve,u,1); return derivs[1]; @@ -6505,6 +6432,79 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.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.rationalCurveRegularSample = function(curve,numSamples,includeU) { return verb_eval_Tess.rationalCurveRegularSampleRange(curve,curve.knots[0],verb_core_ArrayExtensions.last(curve.knots),numSamples,includeU); }; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 31355cd2..0329616d 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -4025,79 +4025,6 @@ verb_eval_CurveLengthSample.prototype = { 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.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_Eval.secondForwardDiff(wts); - var pts = verb_eval_Eval.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_Eval.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_Eval.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_Eval.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_Eval.rationalCurveTangent = function(curve,u) { var derivs = verb_eval_Eval.rationalCurveDerivatives(curve,u,1); return derivs[1]; @@ -6436,6 +6363,79 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.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.rationalCurveRegularSample = function(curve,numSamples,includeU) { return verb_eval_Tess.rationalCurveRegularSampleRange(curve,curve.knots[0],verb_core_ArrayExtensions.last(curve.knots),numSamples,includeU); }; diff --git a/examples/conics.html b/examples/conics.html index 7deeebc0..4fe01c47 100644 --- a/examples/conics.html +++ b/examples/conics.html @@ -42,6 +42,8 @@ addCurveToScene( parabola.toThreeGeometry() ); renderScene(); + + diff --git a/src/verb/Verb.hx b/src/verb/Verb.hx index bbed8da7..89ab84ce 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 { + public static function main() : Void { trace("verb 2.0.0"); } } \ No newline at end of file diff --git a/src/verb/core/ArrayExtensions.hx b/src/verb/core/ArrayExtensions.hx index ca7e8e0c..f3dcd843 100644 --- a/src/verb/core/ArrayExtensions.hx +++ b/src/verb/core/ArrayExtensions.hx @@ -13,7 +13,7 @@ class ArrayExtensions { // //* nothing, just mutates the given array - public static function alloc(a:Array, n:Int) { + public static function alloc(a : Array, n : Int) { if (n < 0) return; while (a.length < n) { a.push(null); @@ -30,7 +30,7 @@ class ArrayExtensions { // //* a reversed copy of the array - public static function reversed(a:Array):Array { + public static function reversed(a : Array) : Array { var ac = a.copy(); ac.reverse(); return ac; @@ -46,7 +46,7 @@ class ArrayExtensions { // //* the last element of the array - public static function last(a:Array):T { + public static function last(a : Array) : T { return a[a.length - 1]; } @@ -60,11 +60,11 @@ 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 { + public static function spliceAndInsert(a : Array, start : Int, end : Int, ele : T) : Void { a.splice(start, end); a.insert(start, ele); } @@ -79,7 +79,7 @@ class ArrayExtensions { // //* the left half - public static function left(arr:Array):Array { + 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,7 +95,7 @@ class ArrayExtensions { // //* the right half - public static function right(arr:Array):Array { + public static function right(arr : Array) : Array { if (arr.length == 0) return []; var len = Math.ceil(arr.length / 2); return arr.slice(len); @@ -111,7 +111,7 @@ class ArrayExtensions { // //* the right half - public static function rightWithPivot(arr:Array):Array { + public static function rightWithPivot(arr : Array) : Array { if (arr.length == 0) return []; var len = Math.ceil(arr.length / 2); return arr.slice(len - 1); @@ -129,7 +129,7 @@ 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 []; diff --git a/src/verb/core/Binomial.hx b/src/verb/core/Binomial.hx index 85119b80..493e60ec 100644 --- a/src/verb/core/Binomial.hx +++ b/src/verb/core/Binomial.hx @@ -6,7 +6,7 @@ class Binomial { static var memo = new IntMap>(); - public static function get(n:Int, k:Int):Float { + public static function get(n : Int, k : Int) : Float { if (k == 0.0) { return 1.0; } @@ -23,7 +23,7 @@ class Binomial { return get_memo(n, k); } - var r:Float = 1, + var r : Float = 1, n_o = n; for (d in 1...k + 1) { @@ -44,7 +44,7 @@ class Binomial { return r; } - public static function get_no_memo(n:Int, k:Int):Float { + public static function get_no_memo(n : Int, k : Int) : Float { if (k == 0) { return 1; } @@ -57,7 +57,7 @@ class Binomial { k = n - k; } - var r:Float = 1, + var r : Float = 1, n_o = n; for (d in 1...k + 1) { @@ -68,11 +68,11 @@ class Binomial { return r; } - private static function memo_exists(n:Int, k:Int):Bool { + 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 { + private static function get_memo(n : Int, k : Int) : Float { return memo.get(n).get(k); } diff --git a/src/verb/core/BoundingBox.hx b/src/verb/core/BoundingBox.hx index 31484c79..94c0f374 100644 --- a/src/verb/core/BoundingBox.hx +++ b/src/verb/core/BoundingBox.hx @@ -12,8 +12,8 @@ using Lambda; @:expose("core.BoundingBox") class BoundingBox { - var initialized:Bool = false; - var dim:Int = 3; + var initialized : Bool = false; + var dim : Int = 3; //BoundingBox Constructor // @@ -21,17 +21,17 @@ class BoundingBox { // //* Points to add, if desired. Otherwise, will not be initialized until add is called. - public function new(pts:Array = null) { + public function new(pts : Array = null) { if (pts != null) { this.addRange(pts); } } // The minimum point of the BoundingBox - the coordinates of this point are always <= max. - public var min:Point = null; + public var min : Point = null; // The maximum point of the BoundingBox. The coordinates of this point are always >= min. - public var max:Point = null; + public var max : Point = null; //Create a bounding box initialized with a single element // @@ -58,7 +58,7 @@ class BoundingBox { // //* This BoundingBox for chaining - public function add(point:Point):BoundingBox { + public function add(point : Point) : BoundingBox { if (!this.initialized) { this.dim = point.length; this.min = point.slice(0); @@ -87,7 +87,7 @@ 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) { @@ -108,7 +108,7 @@ 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) { return false; @@ -130,7 +130,7 @@ 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 @@ -151,7 +151,7 @@ class BoundingBox { // //* true if the two bounding boxes intersect, otherwise false - public function intersects(bb:BoundingBox, tol:Float = -1):Bool { + public function intersects(bb : BoundingBox, tol : Float = -1) : Bool { if (!this.initialized || !bb.initialized) return false; @@ -174,7 +174,7 @@ class BoundingBox { // //* this BoundingBox for chaining - public function clear():BoundingBox { + public function clear() : BoundingBox { this.initialized = false; return this; } @@ -185,7 +185,7 @@ class BoundingBox { // //* Index of longest axis - public function getLongestAxis():Int { + public function getLongestAxis() : Int { var max = 0.0; var id = 0; @@ -211,7 +211,7 @@ class BoundingBox { // //* Length of the given axis. If axis is out of bounds, returns 0. - public function getAxisLength(i:Int):Float { + public function getAxisLength(i : Int) : Float { if (i < 0 || i > this.dim - 1) return 0.0; return Math.abs(this.min[i] - this.max[i]); } @@ -227,7 +227,7 @@ class BoundingBox { // //* The bounding box formed by the intersection or null if there is no intersection. - public function intersect(bb:BoundingBox, tol:Float):BoundingBox { + public function intersect(bb : BoundingBox, tol : Float) : BoundingBox { if (!this.initialized) return null; diff --git a/src/verb/core/Constants.hx b/src/verb/core/Constants.hx index 01702416..73b7bad6 100644 --- a/src/verb/core/Constants.hx +++ b/src/verb/core/Constants.hx @@ -7,13 +7,13 @@ package verb.core; class Constants { //The default euclidean distance that identifies whether two points are coincident @:expose("TOLERANCE") - public static var TOLERANCE:Float = 1e-6; + 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; + public static var EPSILON : Float = 1e-10; //The current version of verb @:expose("VERSION") - public static var VERSION:String = "2.0.0"; + public static var VERSION : String = "2.0.0"; } diff --git a/src/verb/core/Data.hx b/src/verb/core/Data.hx index dafd3d2a..35ac38c7 100644 --- a/src/verb/core/Data.hx +++ b/src/verb/core/Data.hx @@ -29,8 +29,8 @@ typedef KnotArray = Array; @:expose("core.Plane") class Plane extends SerializableBase { - public var normal:Vector; - public var origin:Point; + public var normal : Vector; + public var origin : Point; public function new(origin, normal) { this.origin = origin; @@ -43,8 +43,8 @@ class Plane extends SerializableBase { @:expose("core.Ray") class Ray extends SerializableBase { - public var dir:Vector; - public var origin:Point; + public var dir : Vector; + public var origin : Point; public function new(origin, dir) { this.origin = origin; @@ -65,13 +65,13 @@ class NurbsCurveData extends SerializableBase { } //integer degree of curve - public var degree:Int; + public var degree : Int; // 2d array of control points, where each control point is an array of length (dim) - public var controlPoints:Array; + public var controlPoints : Array; //array of nondecreasing knot values - public var knots:Array; + public var knots : Array; } @@ -90,20 +90,20 @@ class NurbsSurfaceData extends SerializableBase { } //integer degree of surface in u direction - public var degreeU:Int; + public var degreeU : Int; //integer degree of surface in v direction - public var degreeV:Int; + public var degreeV : Int; //array of nondecreasing knot values in u direction - public var knotsU:KnotArray; + public var knotsU : KnotArray; //array of nondecreasing knot values in v direction - public var knotsV:KnotArray; + public var knotsV : KnotArray; // 2d array of control points, the vertical direction (u) increases from top to bottom, the v direction from left to right, //and where each control point is an array of length (dim) - public var controlPoints:Array>; + public var controlPoints : Array>; } @@ -122,19 +122,19 @@ typedef UV = Array; @:expose("core.MeshData") class MeshData extends SerializableBase { - public var faces:Array; - public var points:Array; - public var normals:Array; - public var uvs:Array; + public var faces : Array; + public var points : Array; + 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 { + public static function empty() : MeshData { return new MeshData([], [], [], []); } } @@ -145,10 +145,10 @@ class MeshData extends SerializableBase { class PolylineData extends SerializableBase { // The points in the polyline - public var points:Array; + public var points : Array; // The parameters of the individual points - public var params:Array; + public var params : Array; public function new(points, params) { this.points = points; @@ -173,26 +173,26 @@ class VolumeData extends SerializableBase { } //integer degree in u direction - public var degreeU:Int; + public var degreeU : Int; //integer degree in v direction - public var degreeV:Int; + public var degreeV : Int; //integer degree in w direction - public var degreeW:Int; + public var degreeW : Int; //array of nondecreasing knot values in u direction - public var knotsU:KnotArray; + public var knotsU : KnotArray; //array of nondecreasing knot values in v direction - public var knotsV:KnotArray; + public var knotsV : KnotArray; //array of nondecreasing knot values in w direction - public var knotsW:KnotArray; + public var knotsW : KnotArray; // 3d array of control points, where rows are the u dir, and columns run along the positive v direction, //and where each control point is an array of length (dim) - public var controlPoints:Array>>; + public var controlPoints : Array>>; } @@ -200,10 +200,10 @@ class VolumeData extends SerializableBase { @:expose("core.Pair") class Pair { - public var item0:T1; - public var item1:T2; + 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; } @@ -213,8 +213,8 @@ class Pair { @:expose("core.Interval") class Interval { - public var min:T; - public var max:T; + public var min : T; + public var max : T; public function new(min, max) { this.min = min; diff --git a/src/verb/core/Intersections.hx b/src/verb/core/Intersections.hx index 9c860fc9..fc0c4878 100644 --- a/src/verb/core/Intersections.hx +++ b/src/verb/core/Intersections.hx @@ -6,16 +6,16 @@ import verb.core.Data; class CurveCurveIntersection { //where the intersection took place - public var point0:Point; + public var point0 : Point; //where the intersection took place on the second curve - public var point1:Point; + public var point1 : Point; //the parameter on the first curve - public var u0:Float; + public var u0 : Float; //the parameter on the second curve - public var u1:Float; + public var u1 : Float; public function new(point0, point1, u0, u1) { this.point0 = point0; @@ -28,10 +28,10 @@ class CurveCurveIntersection { @:expose("core.CurveSurfaceIntersection") class CurveSurfaceIntersection { - public var u:Float; - public var uv:UV; - public var curvePoint:Point; - public var surfacePoint:Point; + public var u : Float; + public var uv : UV; + public var curvePoint : Point; + public var surfacePoint : Point; public function new(u, uv, curvePoint, surfacePoint) { this.u = u; @@ -44,17 +44,17 @@ class CurveSurfaceIntersection { @:expose("core.MeshIntersectionPoint") class MeshIntersectionPoint { - public var uv0:UV; - public var uv1:UV; - public var point:Point; + public var uv0 : UV; + public var uv1 : UV; + public var point : Point; - public var faceIndex0:Int; - public var faceIndex1:Int; + public var faceIndex0 : Int; + public var faceIndex1 : Int; //tags to navigate a segment structure - public var opp:MeshIntersectionPoint = null; - public var adj:MeshIntersectionPoint = null; - public var visited:Bool = false; + public var opp : MeshIntersectionPoint = null; + public var adj : MeshIntersectionPoint = null; + public var visited : Bool = false; public function new(uv0, uv1, point, faceIndex0, faceIndex1) { this.uv0 = uv0; @@ -68,11 +68,11 @@ class MeshIntersectionPoint { @:expose("core.PolylineMeshIntersection") class PolylineMeshIntersection { - public var point:Point; - public var u:Float; - public var uv:UV; - public var polylineIndex:Int; - public var faceIndex:Int; + public var point : Point; + public var u : Float; + public var uv : UV; + public var polylineIndex : Int; + public var faceIndex : Int; public function new(point, u, uv, polylineIndex, faceIndex) { this.point = point; @@ -86,10 +86,10 @@ class PolylineMeshIntersection { @:expose("core.SurfaceSurfaceIntersectionPoint") class SurfaceSurfaceIntersectionPoint { - public var uv0:UV; - public var uv1:UV; - public var point:Point; - public var dist:Float; + public var uv0 : UV; + public var uv1 : UV; + public var point : Point; + public var dist : Float; public function new(uv0, uv1, point, dist) { this.uv0 = uv0; @@ -103,16 +103,16 @@ class SurfaceSurfaceIntersectionPoint { class TriSegmentIntersection { //where the intersection took place - public var point:Point; + public var point : Point; //the u param where u is the axis from v0 to v1 - public var s:Float; + public var s : Float; //the v param where v is the axis from v0 to v2 - public var t:Float; + public var t : Float; //the parameter along the segment - public var p:Float; + public var p : Float; public function new(point, s, t, r) { this.point = point; @@ -124,11 +124,11 @@ class TriSegmentIntersection { @:expose("core.CurveTriPoint") class CurveTriPoint { - public var u:Float; - public var uv:UV; - public var point:Point; + public var u : Float; + 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; @@ -137,13 +137,13 @@ class CurveTriPoint { class SurfacePoint { - public var uv:UV; - public var point:Point; - public var normal:Point; - public var id:Int; - public var degen:Bool; + public var uv : UV; + public var point : Point; + public var normal : Point; + 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; @@ -158,8 +158,8 @@ class SurfacePoint { @:expose("core.CurvePoint") class CurvePoint { - public var u:Float; - public var pt:Point; + public var u : Float; + public var pt : Point; public function new(u, pt) { this.u = u; diff --git a/src/verb/core/KdTree.hx b/src/verb/core/KdTree.hx index 3fd8a953..84b31d7b 100644 --- a/src/verb/core/KdTree.hx +++ b/src/verb/core/KdTree.hx @@ -16,10 +16,10 @@ import verb.core.Data; @:expose("core.KdTree") class KdTree { - private var points:Array>; - private var distanceFunction:Point -> Point -> Float; - private var dim:Int = 3; - private var root:KdNode; + private var points : Array>; + private var distanceFunction : Point -> Point -> Float; + private var dim : Int = 3; + private var root : KdNode; public function new(points, distanceFunction) { this.points = points; @@ -29,7 +29,7 @@ class KdTree { 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; @@ -37,7 +37,7 @@ class KdTree { 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) { return 0; @@ -58,13 +58,13 @@ class KdTree { 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, @@ -74,7 +74,7 @@ class KdTree { otherChild, i; - function saveNode(node:KdNode, distance:Float):Void { + function saveNode(node : KdNode, distance : Float) : Void { bestNodes.push(new Pair(node, distance)); if (bestNodes.size() > maxNodes) { bestNodes.pop(); @@ -151,22 +151,22 @@ class KdTree { class BinaryHeap { - public var content:Array>; - private var scoreFunction:Pair -> Float; + public var content : Array>; + private var scoreFunction : Pair -> Float; 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); //Allow it to bubble up. 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. @@ -180,11 +180,11 @@ class BinaryHeap { 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. @@ -206,11 +206,11 @@ 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. @@ -232,7 +232,7 @@ class BinaryHeap { } } - 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], @@ -245,7 +245,7 @@ class BinaryHeap { //This is used to store the new position of the element, //if any. var swap = -1; - var child1Score:Float = 0.0; + var child1Score : Float = 0.0; //If the first child exists (is inside the array)... if (child1N < length) { @@ -284,10 +284,10 @@ class BinaryHeap { class KdPoint { // The point - public var point:Point; + public var point : Point; // An arbitrary object to attach - public var obj:T; + public var obj : T; public function new(point, obj) { this.point = point; @@ -300,21 +300,21 @@ class KdPoint { class KdNode { // The point itself - public var kdPoint:KdPoint; + public var kdPoint : KdPoint; // The left child - public var left:KdNode; + public var left : KdNode; // The right child - public var right:KdNode; + public var right : KdNode; // The parent of the node - public var parent:KdNode; + public var parent : KdNode; // The dimensionality of the point - public var dimension:Int; + 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 f4b18ce6..7f59fb5c 100644 --- a/src/verb/core/LazyCurveBoundingBoxTree.hx +++ b/src/verb/core/LazyCurveBoundingBoxTree.hx @@ -10,11 +10,11 @@ import verb.eval.Intersect; class LazyCurveBoundingBoxTree implements IBoundingBoxTree { - var _curve:NurbsCurveData; - var _boundingBox:BoundingBox = null; - var _knotTol:Float; + var _curve : NurbsCurveData; + 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; @@ -22,7 +22,7 @@ class LazyCurveBoundingBoxTree implements IBoundingBoxTree { _knotTol = knotTol; } - public function split():Pair, IBoundingBoxTree> { + public function split() : Pair, IBoundingBoxTree> { var min = _curve.knots.first(); var max = _curve.knots.last(); var dom = max - min; @@ -45,7 +45,7 @@ class LazyCurveBoundingBoxTree implements IBoundingBoxTree { return _curve; } - public function indivisible(tolerance:Float) { + public function indivisible(tolerance : Float) { return _curve.knots.domain() < _knotTol; } diff --git a/src/verb/core/LazyMeshBoundingBoxTree.hx b/src/verb/core/LazyMeshBoundingBoxTree.hx index ca43ae95..ab4ac544 100644 --- a/src/verb/core/LazyMeshBoundingBoxTree.hx +++ b/src/verb/core/LazyMeshBoundingBoxTree.hx @@ -6,9 +6,9 @@ import verb.eval.Intersect; using verb.core.ArrayExtensions; class LazyMeshBoundingBoxTree implements IBoundingBoxTree { - var _mesh:MeshData; - var _faceIndices:Array; - var _boundingBox:BoundingBox = null; + var _mesh : MeshData; + var _faceIndices : Array; + var _boundingBox : BoundingBox = null; public function new(mesh, faceIndices = null) { _mesh = mesh; @@ -18,7 +18,7 @@ class LazyMeshBoundingBoxTree implements IBoundingBoxTree { _faceIndices = faceIndices; } - public function split():Pair, IBoundingBoxTree> { + public function split() : Pair, IBoundingBoxTree> { var as = Mesh.sortTrianglesOnLongestAxis(boundingBox(), _mesh, _faceIndices) , l = as.left() , r = as.right(); @@ -39,7 +39,7 @@ class LazyMeshBoundingBoxTree implements IBoundingBoxTree { return _faceIndices[0]; } - public function indivisible(tolerance:Float) { + public function indivisible(tolerance : Float) { return _faceIndices.length == 1; } diff --git a/src/verb/core/LazyPolylineBoundingBoxTree.hx b/src/verb/core/LazyPolylineBoundingBoxTree.hx index f6bfe180..832df48e 100644 --- a/src/verb/core/LazyPolylineBoundingBoxTree.hx +++ b/src/verb/core/LazyPolylineBoundingBoxTree.hx @@ -5,9 +5,9 @@ import verb.eval.Intersect; class LazyPolylineBoundingBoxTree implements IBoundingBoxTree { - var _interval:Interval; - var _polyline:PolylineData; - var _boundingBox:BoundingBox = null; + var _interval : Interval; + var _polyline : PolylineData; + var _boundingBox : BoundingBox = null; public function new(polyline, interval = null) { _polyline = polyline; @@ -18,7 +18,7 @@ class LazyPolylineBoundingBoxTree implements IBoundingBoxTree { _interval = interval; } - public function split():Pair, IBoundingBoxTree> { + public function split() : Pair, IBoundingBoxTree> { var min = _interval.min; var max = _interval.max; @@ -45,7 +45,7 @@ class LazyPolylineBoundingBoxTree implements IBoundingBoxTree { return _interval.min; } - public function indivisible(tolerance:Float) { + public function indivisible(tolerance : Float) { return _interval.max - _interval.min == 1; } diff --git a/src/verb/core/LazySurfaceBoundingBoxTree.hx b/src/verb/core/LazySurfaceBoundingBoxTree.hx index 392f24d7..21594fca 100644 --- a/src/verb/core/LazySurfaceBoundingBoxTree.hx +++ b/src/verb/core/LazySurfaceBoundingBoxTree.hx @@ -10,11 +10,11 @@ import verb.eval.Intersect; class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { - var _surface:NurbsSurfaceData; - var _boundingBox:BoundingBox = null; - var _splitV:Bool; - var _knotTolU:Float; - var _knotTolV:Float; + var _surface : NurbsSurfaceData; + var _boundingBox : BoundingBox = null; + var _splitV : Bool; + var _knotTolU : Float; + var _knotTolV : Float; public function new(surface, splitV = false, knotTolU = null, knotTolV = null) { _surface = surface; @@ -32,9 +32,9 @@ class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { _knotTolV = knotTolV; } - public function split():Pair, IBoundingBoxTree> { - var min:Float; - var max:Float; + public function split() : Pair, IBoundingBoxTree> { + var min : Float; + var max : Float; if (_splitV) { min = _surface.knotsV.first(); @@ -68,7 +68,7 @@ class LazySurfaceBoundingBoxTree implements IBoundingBoxTree { return _surface; } - public function indivisible(tolerance:Float) { + public function indivisible(tolerance : Float) { return _surface.knotsV.domain() < _knotTolV && _surface.knotsU.domain() < _knotTolU; } diff --git a/src/verb/core/Mat.hx b/src/verb/core/Mat.hx index a7562bf3..4f1b0cef 100644 --- a/src/verb/core/Mat.hx +++ b/src/verb/core/Mat.hx @@ -10,7 +10,7 @@ class Mat { // Multiply a `Matrix` by a constant - public static function mul(a:Float, b:Matrix):Matrix { + public static function mul(a : Float, b : Matrix) : Matrix { return [ for (i in 0...b.length) Vec.mul(a, b[i]) ]; } @@ -18,7 +18,7 @@ class Mat { // // 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; @@ -55,31 +55,31 @@ class Mat { // Add two matrices - public static function add(a:Matrix, b:Matrix):Matrix { + 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 { + 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 { + 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 { + 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 { + 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; @@ -87,20 +87,20 @@ class Mat { // Transpose a matrix - public static function transpose(a:Array>):Array> { + 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 { + 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; @@ -150,7 +150,7 @@ class Mat { // Based on methods from numeric.js - private static function LU(A:Matrix):LUDecomp { + private static function LU(A : Matrix) : LUDecomp { var abs = Math.abs; var i, j, k, absAjk, Akk, Ak, Pk, Ai; @@ -217,10 +217,10 @@ class Mat { private class LUDecomp { - public var LU:Matrix; - public var P:Array; + 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 3bda1e98..40d060ca 100644 --- a/src/verb/core/Mesh.hx +++ b/src/verb/core/Mesh.hx @@ -22,7 +22,7 @@ class Mesh { //* a normal vector represented by an array of length 3 // - public static function getTriangleNorm(points:Array, tri:Tri):Point { + public static function getTriangleNorm(points : Array, tri : Tri) : Point { var v0 = points[ tri[0] ] , v1 = points[ tri[1] ] @@ -47,7 +47,7 @@ class Mesh { //* a BoundingBox containing the mesh // - public static function makeMeshAabb(mesh:MeshData, faceIndices:Array):BoundingBox { + public static function makeMeshAabb(mesh : MeshData, faceIndices : Array) : BoundingBox { var bb = new verb.core.BoundingBox(); @@ -73,7 +73,7 @@ class Mesh { //* a point represented by an array of length (dim) // - public static function sortTrianglesOnLongestAxis(bb:BoundingBox, mesh:MeshData, faceIndices:Array):Array { + public static function sortTrianglesOnLongestAxis(bb : BoundingBox, mesh : MeshData, faceIndices : Array) : Array { var longAxis = bb.getLongestAxis(); @@ -83,7 +83,7 @@ class Mesh { 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; @@ -110,7 +110,7 @@ class Mesh { // //* the minimum coordinate - private static function getMinCoordOnAxis(points:Array, tri:Tri, axis:Int):Float { + private static function getMinCoordOnAxis(points : Array, tri : Tri, axis : Int) : Float { var min = Math.POSITIVE_INFINITY; @@ -134,7 +134,7 @@ class Mesh { //* a point represented by an array of length 3 // - public static function getTriangleCentroid(points:Array, tri:Tri):Point { + public static function getTriangleCentroid(points : Array, tri : Tri) : Point { var centroid = [0.0, 0.0, 0.0]; @@ -163,7 +163,7 @@ class Mesh { // //* the UV on the face - public static function triangleUVFromPoint(mesh:MeshData, faceIndex:Int, f:Point):UV { + public static function triangleUVFromPoint(mesh : MeshData, faceIndex : Int, f : Point) : UV { var tri = mesh.faces[faceIndex]; diff --git a/src/verb/core/MeshBoundingBoxTree.hx b/src/verb/core/MeshBoundingBoxTree.hx index 62533ac0..b6113ce2 100644 --- a/src/verb/core/MeshBoundingBoxTree.hx +++ b/src/verb/core/MeshBoundingBoxTree.hx @@ -7,12 +7,12 @@ import verb.eval.Intersect; class MeshBoundingBoxTree implements IBoundingBoxTree { - var _children:Pair, IBoundingBoxTree>; - var _boundingBox:BoundingBox; - var _face:Int = -1; - var _empty:Bool = false; + var _children : Pair, IBoundingBoxTree>; + var _boundingBox : BoundingBox; + 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 ]; @@ -38,7 +38,7 @@ class MeshBoundingBoxTree implements IBoundingBoxTree { ); } - public function split():Pair, IBoundingBoxTree> { + public function split() : Pair, IBoundingBoxTree> { return _children; } @@ -50,7 +50,7 @@ class MeshBoundingBoxTree implements IBoundingBoxTree { return _face; } - public function indivisible(tolerance:Float) { + public function indivisible(tolerance : Float) { return _children == null; } diff --git a/src/verb/core/Minimizer.hx b/src/verb/core/Minimizer.hx index ca39a05a..b7b40efe 100644 --- a/src/verb/core/Minimizer.hx +++ b/src/verb/core/Minimizer.hx @@ -7,7 +7,7 @@ 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); }; } @@ -72,7 +72,7 @@ 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); @@ -116,7 +116,7 @@ class Minimizer { 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; @@ -146,12 +146,12 @@ class Minimizer { class MinimizationResult { - public var solution:Vector; - public var value:Float; - public var gradient:Vector; - public var invHessian:Matrix; - public var iterations:Int; - public var message:String; + public var solution : Vector; + public var value : Float; + public var gradient : Vector; + public var invHessian : Matrix; + public var iterations : Int; + public var message : String; public function new(solution, value, gradient, invHessian, iterations, message) { this.solution = solution; diff --git a/src/verb/core/Serialization.hx b/src/verb/core/Serialization.hx index 6cfa0ac4..c5b5c9b8 100644 --- a/src/verb/core/Serialization.hx +++ b/src/verb/core/Serialization.hx @@ -10,14 +10,14 @@ 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(); @@ -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 c881486e..ed54a398 100644 --- a/src/verb/core/SurfaceBoundingBoxTree.hx +++ b/src/verb/core/SurfaceBoundingBoxTree.hx @@ -9,9 +9,9 @@ import verb.eval.Intersect; class SurfaceBoundingBoxTree implements IBoundingBoxTree { - var _children:Pair, IBoundingBoxTree>; - var _surface:NurbsSurfaceData; - var _boundingBox:BoundingBox = null; + var _children : Pair, IBoundingBoxTree>; + var _surface : NurbsSurfaceData; + var _boundingBox : BoundingBox = null; public function new(surface, splitV = false, knotTolU = null, knotTolV = null) { _surface = surface; @@ -34,8 +34,8 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { if (!divisible) return; - var min:Float; - var max:Float; + var min : Float; + var max : Float; if (splitV) { min = _surface.knotsV.first(); @@ -56,7 +56,7 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { } - public function split():Pair, IBoundingBoxTree> { + public function split() : Pair, IBoundingBoxTree> { return _children; } @@ -74,7 +74,7 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { return _surface; } - public function indivisible(tolerance:Float) { + public function indivisible(tolerance : Float) { return _children == null; } diff --git a/src/verb/core/Trig.hx b/src/verb/core/Trig.hx index 76c79e3f..89bdecc9 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); } @@ -107,7 +107,7 @@ class Trig { // //* *Object* with u and pt properties - public static function segmentClosestPoint(pt:Point, segpt0:Point, segpt1:Point, u0:Float, u1:Float) { + public static function segmentClosestPoint(pt : Point, segpt0 : Point, segpt1 : Point, u0 : Float, u1 : Float) { var dif = Vec.sub(segpt1, segpt0) , l = Vec.norm(dif); diff --git a/src/verb/core/Vec.hx b/src/verb/core/Vec.hx index 68197cd4..d412f662 100644 --- a/src/verb/core/Vec.hx +++ b/src/verb/core/Vec.hx @@ -13,11 +13,11 @@ import verb.core.Data; @:expose("core.Vec") class Vec { - public static function angleBetween(a:Array, b:Array):Float { + 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 { + public static function positiveAngleBetween(a : Array, b : Array, n : Array) : Float { var nab = Vec.cross(a, b); var al = Vec.norm(a); @@ -36,7 +36,7 @@ class Vec { return s > 0 ? w : -w; } - public static function signedAngleBetween(a:Array, b:Array, n:Array):Float { + public static function signedAngleBetween(a : Array, b : Array, n : Array) : Float { var nab = Vec.cross(a, b); var al = Vec.norm(a); @@ -53,16 +53,16 @@ class Vec { return s > 0.0 ? w : 2 * Math.PI - w; } - public static function angleBetweenNormalized2d(a:Array, b:Array):Float { + 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 { + 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) { @@ -72,7 +72,7 @@ class Vec { 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 []; #end @@ -91,55 +91,55 @@ class Vec { return l; } - public static function neg(arr:Array):Array { + public static function neg(arr : Array) : Array { return arr.map(function(x) { return -x; }); } - public static function min(arr:Array):Float { + 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 { + 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 { + public static function all(arr : Array) : Bool { return arr.fold(function(x, a) { return a && x; }, true); } - public static function finite(arr:Array):Array { + 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 { + 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 { + 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) { + public static function normalized(arr : Array) { return div(arr, norm(arr)); } - public static function cross(u:Array, v:Array):Array { + 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 { + public static function dist(a : Array, b : Array) : Float { return norm(sub(a, b)); } - public static function distSquared(a:Array, b:Array):Float { + public static function distSquared(a : Array, b : Array) : Float { return normSquared(sub(a, b)); } - public static function sum(a:Iterable):Float { + public static function sum(a : Iterable) : Float { return a.fold(function(x, a) { return a + x; }, 0); } - public static function addAll(a:Iterable>):Array { + public static function addAll(a : Iterable>) : Array { var i = a.iterator(); if (!i.hasNext()) return null; @@ -148,87 +148,87 @@ class Vec { return a.fold(function(x, a) { return add(a, x); }, rep(f, 0.0)); } - public static function addAllMutate(a:Array>) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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 { + 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 { + 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 { + public static function rep(num : Int, ele : T) : Array { return [ for (i in 0...num) ele ]; } - public static function zeros1d(rows:Int):Array { + public static function zeros1d(rows : Int) : Array { return [ for (i in 0...rows) 0.0 ]; } - public static function zeros2d(rows:Int, cols:Int):Array> { + 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>> { + 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 { - var sum:Float = 0; + public static function dot(a : Array, b : Array) : Float { + var sum : Float = 0; for (i in 0...a.length) { sum += a[i] * b[i]; } return sum; } - public static function add(a:Array, b:Array):Array { + 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 { + 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 { + 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 { + 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; @@ -237,7 +237,7 @@ class Vec { return true; } - public static function sortedSetUnion(a:Array, b:Array):Array { + public static function sortedSetUnion(a : Array, b : Array) : Array { var merged = []; @@ -282,7 +282,7 @@ 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 = []; diff --git a/src/verb/eval/Analyze.hx b/src/verb/eval/Analyze.hx index 77cd9677..ddcd3c2d 100644 --- a/src/verb/eval/Analyze.hx +++ b/src/verb/eval/Analyze.hx @@ -36,10 +36,10 @@ class Analyze { // //* Array of KnotMultiplicity objects - public static function knotMultiplicities(knots:KnotArray):Array { + public static function knotMultiplicities(knots : KnotArray) : Array { var mults = [ new KnotMultiplicity( knots[0], 0 ) ]; - var curr:KnotMultiplicity = mults[0]; + var curr : KnotMultiplicity = mults[0]; for (knot in knots) { if ((Math.abs(knot - curr.knot)) > Constants.EPSILON) { @@ -65,7 +65,7 @@ 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(); @@ -88,7 +88,7 @@ class Analyze { // //* The closest point on the surface, bounded by the parametric range of the surface - public static function rationalSurfaceClosestPoint(surface:NurbsSurfaceData, p:Point):Point { + public static function rationalSurfaceClosestPoint(surface : NurbsSurfaceData, p : Point) : Point { var uv = Analyze.rationalSurfaceClosestParam(surface, p); return Eval.rationalSurfacePoint(surface, uv[0], uv[1]); } @@ -104,7 +104,7 @@ class Analyze { // //* The closest parameters on the surface, bounded by the parametric domain of the surface - public static function rationalSurfaceClosestParam(surface:NurbsSurfaceData, p:Point):UV { + public static function rationalSurfaceClosestParam(surface : NurbsSurfaceData, p : Point) : UV { //for surfaces, we try to minimize the following: // @@ -179,11 +179,11 @@ class Analyze { } } - 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 @@ -305,7 +305,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 { + public static function rationalCurveClosestPoint(curve : NurbsCurveData, p : Point) : Point { return Eval.rationalCurvePoint(curve, rationalCurveClosestParam(curve, p)); } @@ -320,7 +320,7 @@ class Analyze { // //* The closest parameter on the curve, bounded by the parametric domain of the curve - public static function rationalCurveClosestParam(curve:NurbsCurveData, p:Point):Float { + public static function rationalCurveClosestParam(curve : NurbsCurveData, p : Point) : Float { // We want to solve: // @@ -385,11 +385,11 @@ class Analyze { , 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); @@ -464,11 +464,11 @@ 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]; @@ -508,10 +508,10 @@ class Analyze { // //* the parameter - public static function rationalBezierCurveParamAtArcLength(curve:NurbsCurveData, - len:Float, - tol:Float = null, - totalLength:Float = null):Float { + 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 @@ -556,7 +556,7 @@ class Analyze { // //* the approximate length - public static function rationalCurveArcLength(curve:NurbsCurveData, u:Float = null, gaussDegIncrease:Int = 16) { + public static function rationalCurveArcLength(curve : NurbsCurveData, u : Float = null, gaussDegIncrease : Int = 16) { u = (u == null) ? curve.knots.last() : u; var crvs = Modify.decomposeCurveIntoBeziers(curve) @@ -585,7 +585,7 @@ 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 , z = (u - curve.knots[0]) / 2 @@ -607,7 +607,7 @@ 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> = [ + static var Tvalues : Array> = [ [], [], [ -0.5773502691896257645091487805019574556476, 0.5773502691896257645091487805019574556476], [0, -0.7745966692414833770358530799564799221665, 0.7745966692414833770358530799564799221665], @@ -635,7 +635,7 @@ class Analyze { ]; //Legendre-Gauss weights - static var Cvalues:Array> = [ + static var Cvalues : Array> = [ [], [], [1.0, 1.0], [0.8888888888888888888888888888888888888888, 0.5555555555555555555555555555555555555555, 0.5555555555555555555555555555555555555555], @@ -669,10 +669,10 @@ class Analyze { class KnotMultiplicity { // The parameter of the knot - public var knot:Float; + public var knot : Float; // The multiplicity (i.e. the number of repeated occurrences) of the given knot in a knot vector - public var mult:Int; + public var mult : Int; // Create a new KnotMultiplicity object //**params** @@ -680,7 +680,7 @@ 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; } diff --git a/src/verb/eval/Check.hx b/src/verb/eval/Check.hx index 16979adb..629a1767 100644 --- a/src/verb/eval/Check.hx +++ b/src/verb/eval/Check.hx @@ -33,7 +33,7 @@ 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; @@ -64,7 +64,7 @@ class Check { // //* Whether the array is non-decreasing - public static function isNonDecreasing(vec:Array) { + public static function isNonDecreasing(vec : Array) { var rep = vec.first(); for (i in 0...vec.length) { if (vec[i] < rep - Constants.EPSILON) return false; @@ -83,7 +83,7 @@ class Check { // //* The original, unmodified data - public static function isValidNurbsCurveData(data:NurbsCurveData):NurbsCurveData { + 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!"; @@ -112,7 +112,7 @@ class Check { // //* The original, unmodified data - public static function isValidNurbsSurfaceData(data:NurbsSurfaceData):NurbsSurfaceData { + 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!"; diff --git a/src/verb/eval/Divide.hx b/src/verb/eval/Divide.hx index c8bb0850..fc9deb91 100644 --- a/src/verb/eval/Divide.hx +++ b/src/verb/eval/Divide.hx @@ -24,7 +24,7 @@ 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 @@ -46,7 +46,7 @@ class Divide { , newpts1 = new Array>(); var s = Eval.knotSpan(degree, u, knots); - var res:NurbsCurveData = null; + var res : NurbsCurveData = null; for (cps in controlPoints) { res = Modify.curveKnotRefine(new NurbsCurveData(degree, knots, cps), knots_to_insert); @@ -82,7 +82,7 @@ class Divide { // //* *Array* two new curves, defined by degree, knots, and control points - public static function curveSplit(curve:NurbsCurveData, u:Float):Array { + public static function curveSplit(curve : NurbsCurveData, u : Float) : Array { var degree = curve.degree , controlPoints = curve.controlPoints @@ -119,7 +119,7 @@ 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; @@ -139,7 +139,7 @@ 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); }) @@ -183,8 +183,8 @@ class Divide { @:expose("eval.CurveLengthSample") class CurveLengthSample { - public var u:Float; - public var len:Float; + public var u : Float; + public var len : Float; public function new(u, len) { this.u = u; diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index efcda6fd..48665858 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -33,7 +33,7 @@ class Eval { // //* a Vector represented by an array of length (dim) - public static function rationalCurveTangent(curve:NurbsCurveData, u:Float):Array { + public static function rationalCurveTangent(curve : NurbsCurveData, u : Float) : Array { var derivs = rationalCurveDerivatives(curve, u, 1); return derivs[1]; } @@ -50,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]); } @@ -68,10 +68,10 @@ 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) @@ -126,7 +126,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalSurfacePoint(surface:NurbsSurfaceData, u:Float, v:Float):Point { + public static function rationalSurfacePoint(surface : NurbsSurfaceData, u : Float, v : Float) : Point { return dehomogenize(surfacePoint(surface, u, v)); } @@ -142,7 +142,7 @@ 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) @@ -180,7 +180,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalCurvePoint(curve:NurbsCurveData, u:Float):Point { + public static function rationalCurvePoint(curve : NurbsCurveData, u : Float) : Point { return dehomogenize(curvePoint(curve, u)); } @@ -197,7 +197,7 @@ class Eval { // //* a 2d jagged array representing the derivatives - u derivatives increase by row, v by column - public static function surfaceDerivatives(surface:NurbsSurfaceData, u:Float, v:Float, numDerivs:Int):Array> { + public static function surfaceDerivatives(surface : NurbsSurfaceData, u : Float, v : Float, numDerivs : Int) : Array> { var n = surface.knotsU.length - surface.degreeU - 2 , m = surface.knotsV.length - surface.degreeV - 2; @@ -221,12 +221,12 @@ 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> { + public static function surfaceDerivativesGivenNM(n : Int, + m : Int, + surface : NurbsSurfaceData, + u : Float, + v : Float, + numDerivs : Int) : Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -287,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; @@ -311,7 +311,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function surfacePointGivenNM(n:Int, m:Int, surface:NurbsSurfaceData, u:Float, v:Float):Point { + public static function surfacePointGivenNM(n : Int, m : Int, surface : NurbsSurfaceData, u : Float, v : Float) : Point { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -352,114 +352,6 @@ class Eval { return position; } - // 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 representing the curve - //* number of divisions - // - //**returns** - // - //* an array of (divs+1) points - - public static function rationalCurveRegularSamplePoints(crv:NurbsCurveData, divs:Int):Array { - - var range = crv.knots.last() - crv.knots[0]; - var beziers = 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); - - currentU = nextU + step; - } - - return pts; - } - - private static function rationalBezierCurveRegularSamplePointsMutate(crv:NurbsCurveData, - pts:Array, - startU:Float, - step:Float, - numSteps:Int) { - - var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; - - if (numSteps <= crv.degree + 1) { - for (i in 0...numSteps) { - pts.push(rationalCurvePoint(crv, u)); - u += step; - } - return; - } - - // initialize forward differencing - - for (i in 0...degree1) { - its.push(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(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(dehomogenize(front[0])); - } - } - // 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 // @@ -474,7 +366,7 @@ class Eval { // //* 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) { + public static function rationalSurfaceRegularSampleDerivatives(surface : NurbsSurfaceData, divsU : Int, divsV : Int, numDerivs : Int) { var allders = surfaceRegularSampleDerivatives(surface, divsU, divsV, numDerivs); @@ -544,7 +436,7 @@ class Eval { // //* 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) { + public static function surfaceRegularSampleDerivatives(surface : NurbsSurfaceData, divsU : Int, divsV : Int, numDerivs : Int) { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -590,7 +482,7 @@ class Eval { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function rationalSurfaceRegularSamplePoints(surface:NurbsSurfaceData, divsU:Int, divsV:Int):Array> { + public static function rationalSurfaceRegularSamplePoints(surface : NurbsSurfaceData, divsU : Int, divsV : Int) : Array> { return dehomogenize2d(surfaceRegularSamplePoints(surface, divsU, divsV)); } @@ -607,7 +499,7 @@ class Eval { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function surfaceRegularSamplePoints(surface:NurbsSurfaceData, divsU:Int, divsV:Int):Array> { + public static function surfaceRegularSamplePoints(surface : NurbsSurfaceData, divsU : Int, divsV : Int) : Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -640,7 +532,7 @@ class Eval { return pts; } - public static function surfaceRegularSamplePoints2(surface:NurbsSurfaceData, divsU:Int, divsV:Int):Array> { + public static function surfaceRegularSamplePoints2(surface : NurbsSurfaceData, divsU : Int, divsV : Int) : Array> { var pts = []; @@ -657,10 +549,10 @@ class Eval { return pts; } - private static function regularlySpacedBasisFunctions(degree:Int, knots:KnotArray, divs:Int):Pair, Array>> { + private 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 n : Int = knots.length - degree - 2; + var span : Float = (knots.last() - knots[0]) / divs; var bases = []; var knotspans = []; @@ -679,10 +571,10 @@ class Eval { return new Pair, Array>>( knotspans, bases ); } - private static function regularlySpacedDerivativeBasisFunctions(degree:Int, knots:KnotArray, divs:Int) { + 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 n : Int = knots.length - degree - 2; + var span : Float = (knots.last() - knots[0]) / divs; var bases = []; var knotspans = []; @@ -701,17 +593,17 @@ class Eval { return new Pair, Array>>>( knotspans, bases ); } - private static function surfacePointGivenBasesKnotSpans(degreeU:Int, - degreeV:Int, - controlPoints:Array>, - knotSpanU:Int, - knotSpanV:Int, - basesU:Array, - basesV:Array, - dim:Int):Point { + private 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; + , temp : Array; // could be precomputed var uind = knotSpanU - degreeU; @@ -733,15 +625,15 @@ class Eval { return position; } - private static function surfaceDerivativesGivenBasesKnotSpans(degreeU:Int, - degreeV:Int, - controlPoints:Array>, - knotSpanU:Int, - knotSpanV:Int, - basesU:Array>, - basesV:Array>, - dim:Int, - numDerivs:Int) { + 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 @@ -786,7 +678,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curveDerivatives(crv:NurbsCurveData, u:Float, numDerivs:Int):Array { + 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); @@ -806,7 +698,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curveDerivativesGivenN(n:Int, curve:NurbsCurveData, u:Float, numDerivs:Int):Array { + public static function curveDerivativesGivenN(n : Int, curve : NurbsCurveData, u : Float, numDerivs : Int) : Array { var degree = curve.degree , controlPoints = curve.controlPoints @@ -843,7 +735,7 @@ 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); } @@ -861,7 +753,7 @@ class Eval { // //* whether the values are correct - public static function areValidRelations(degree:Int, num_controlPoints:Int, knots_length:Int):Bool { + public static function areValidRelations(degree : Int, num_controlPoints : Int, knots_length : Int) : Bool { return num_controlPoints + degree + 1 - knots_length == 0; } @@ -878,7 +770,7 @@ 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 @@ -913,7 +805,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function volumePoint(volume:VolumeData, u:Float, v:Float, w:Float):Point { + public static function volumePoint(volume : VolumeData, u : Float, v : Float, w : Float) : Point { var n = volume.knotsU.length - volume.degreeU - 2 , m = volume.knotsV.length - volume.degreeV - 2 , l = volume.knotsW.length - volume.degreeW - 2; @@ -934,13 +826,13 @@ class Eval { // //* a point represented by an array of length (dim) - public static function volumePointGivenNML(volume:VolumeData, - n:Int, - m:Int, - l:Int, - u:Float, - v:Float, - w:Float):Point { + public static function volumePointGivenNML(volume : VolumeData, + n : Int, + m : Int, + l : Int, + u : Float, + v : Float, + w : Float) : Point { if (!areValidRelations(volume.degreeU, volume.controlPoints.length, volume.knotsU.length) || !areValidRelations(volume.degreeV, volume.controlPoints[0].length, volume.knotsV.length) || @@ -1005,7 +897,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; @@ -1028,8 +920,8 @@ 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(knotIndex:Int, u:Float, p:Int, - n:Int, knots:KnotArray):Array> { + 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) @@ -1056,13 +948,13 @@ class Eval { 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; + , 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]; @@ -1138,7 +1030,7 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctions(u:Float, degree:Int, knots:KnotArray):Array { + 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); } @@ -1158,15 +1050,15 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctionsGivenKnotSpanIndex(knotSpan_index:Int, - u:Float, - degree:Int, - knots:KnotArray):Array { + public static function basisFunctionsGivenKnotSpanIndex(knotSpan_index : Int, + 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); - var saved:Float = 0; - var temp:Float = 0; + var saved : Float = 0; + var temp : Float = 0; basisFunctions[0] = 1.0; @@ -1200,7 +1092,7 @@ class Eval { //* the index of the knot span // - public static function knotSpan(degree:Int, u:Float, knots:Array):Int { + public static function knotSpan(degree : Int, u : Float, knots : Array) : Int { return knotSpanGivenN(knots.length - degree - 2, degree, u, knots); } @@ -1219,7 +1111,7 @@ class Eval { //* the index of the knot span // - public static function knotSpanGivenN(n:Int, degree:Int, u:Float, knots:Array):Int { + public static function knotSpanGivenN(n : Int, degree : Int, u : Float, knots : Array) : Int { if (u > knots[n + 1] - Constants.EPSILON) { return n; } @@ -1255,7 +1147,7 @@ class Eval { // //* a point represented by an array pi with length (dim) - public static function dehomogenize(homoPoint:Point):Point { + public static function dehomogenize(homoPoint : Point) : Point { var dim = homoPoint.length , point = [] @@ -1280,9 +1172,9 @@ class Eval { // //* array of points represented by an array (wi*pi) with length (dim) - public static function rational1d(homoPoints:Array):Array { + 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 @@ -1296,7 +1188,7 @@ class Eval { // //* array of arrays of points, each represented by an array pi with length (dim) - public static function rational2d(homoPoints:Array>):Array> { + public static function rational2d(homoPoints : Array>) : Array> { return homoPoints.map(rational1d); } @@ -1311,7 +1203,7 @@ class Eval { // //* a point represented by an array pi with length (dim) - public static function weight1d(homoPoints:Array):Array { + public static function weight1d(homoPoints : Array) : Array { var dim = homoPoints[0].length - 1; return homoPoints.map(function(x) { return x[dim]; }); } @@ -1327,7 +1219,7 @@ class Eval { // //* array of arrays of points, each represented by an array pi with length (dim) - public static function weight2d(homoPoints:Array>):Array> { + public static function weight2d(homoPoints : Array>) : Array> { return homoPoints.map(weight1d); } @@ -1341,7 +1233,7 @@ class Eval { // //* an array of points, each of length dim - public static function dehomogenize1d(homoPoints:Array):Array { + public static function dehomogenize1d(homoPoints : Array) : Array { return homoPoints.map(dehomogenize); } @@ -1355,7 +1247,7 @@ class Eval { // //* array of arrays of points, each of length dim - public static function dehomogenize2d(homoPoints:Array>):Array> { + public static function dehomogenize2d(homoPoints : Array>) : Array> { return homoPoints.map(dehomogenize1d); } @@ -1372,12 +1264,12 @@ 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 , homo_controlPoints = new Array() - , wt:Float = 0.0 + , wt : Float = 0.0 , ref_pt = new Point() , weights = weights != null ? weights : Vec.rep(controlPoints.length, 1.0); @@ -1412,8 +1304,8 @@ class Eval { //i the ith control point weight and pi is the ith control point, the size is // (m x n x dim+1) - public static function homogenize2d(controlPoints:Array>, - weights:Array> = null):Array> { + public static function homogenize2d(controlPoints : 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) ]; diff --git a/src/verb/eval/Intersect.hx b/src/verb/eval/Intersect.hx index 647e5689..f92bac55 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); @@ -57,7 +57,7 @@ class Intersect { // 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) { + return pl.map(function(inter : MeshIntersectionPoint) { return Intersect.surfacesAtPointWithEstimate(surface0, surface1, inter.uv0, inter.uv1, tol); }); }); @@ -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; @@ -166,10 +166,10 @@ class Intersect { // //* array of array of MeshIntersectionPoints - public static function meshes(mesh0:MeshData, - mesh1:MeshData, - bbtree0:IBoundingBoxTree = null, - bbtree1:IBoundingBoxTree = null):Array> { + public static function meshes(mesh0 : MeshData, + mesh1 : MeshData, + bbtree0 : IBoundingBoxTree = null, + bbtree1 : IBoundingBoxTree = null) : Array> { if (bbtree0 == null) bbtree0 = new LazyMeshBoundingBoxTree( mesh0 ); if (bbtree1 == null) bbtree1 = new LazyMeshBoundingBoxTree( mesh1 ); @@ -178,7 +178,7 @@ class Intersect { 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) { return x != null; @@ -224,7 +224,7 @@ class Intersect { //* array of array of array of MeshIntersectionPoints - corresponding to the collection of polylines formed with // each slice - public static function meshSlices(mesh:MeshData, min:Float, max:Float, step:Float):Array>> { + public static function meshSlices(mesh : MeshData, min : Float, max : Float, step : Float) : Array>> { var bbtree = new MeshBoundingBoxTree( mesh ); var bb = bbtree.boundingBox(); @@ -259,7 +259,7 @@ class Intersect { // //* array of array of MeshIntersectionPoint - public static function makeMeshIntersectionPolylines(segments:Array>):Array> { + public static function makeMeshIntersectionPolylines(segments : Array>) : Array> { if (segments.length == 0) return []; @@ -273,7 +273,7 @@ class Intersect { var tree = kdTreeFromSegments(segments); //flatten everything, we no longer need the segments - var ends:Array = []; + var ends : Array = []; for (seg in segments) { ends.push(seg.min); @@ -364,7 +364,7 @@ class Intersect { // //* array of array of MeshIntersectionPoint - private static function kdTreeFromSegments(segments:Array>):KdTree { + private static function kdTreeFromSegments(segments : Array>) : KdTree { var treePoints = []; @@ -388,7 +388,7 @@ 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 @@ -414,11 +414,11 @@ 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 { + public static function curveAndSurface(curve : NurbsCurveData, + 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 ); @@ -466,10 +466,10 @@ 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]) @@ -532,9 +532,9 @@ class Intersect { // //* an array of PolylineMeshIntersection object - public static function polylineAndMesh(polyline:PolylineData, - mesh:MeshData, - tol:Float):Array { + public static function polylineAndMesh(polyline : PolylineData, + mesh : MeshData, + tol : Float) : Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline ), @@ -574,8 +574,8 @@ 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> { + private static function boundingBoxTrees(ai : IBoundingBoxTree, bi : IBoundingBoxTree, tol : Float = 1e-9) + : Array> { var atrees = []; var btrees = []; @@ -652,13 +652,13 @@ class Intersect { // //* the intersections - public static function curves(curve1:NurbsCurveData, curve2:NurbsCurveData, tolerance:Float):Array { + public static function curves(curve1 : NurbsCurveData, curve2 : NurbsCurveData, tolerance : Float) : Array { var ints = Intersect.boundingBoxTrees( new LazyCurveBoundingBoxTree( curve1 ), new LazyCurveBoundingBoxTree( curve2 ), 0); - return ints.map(function(x:Pair):CurveCurveIntersection { + 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; @@ -682,12 +682,12 @@ class Intersect { // //* array of CurveCurveIntersection objects - private static function curvesWithEstimate(curve0:NurbsCurveData, - curve1:NurbsCurveData, - u0:Float, - u1:Float, - tolerance:Float):CurveCurveIntersection { - var objective = function(x:Vector):Float { + private static function curvesWithEstimate(curve0 : NurbsCurveData, + 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); @@ -745,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]; @@ -778,7 +778,7 @@ class Intersect { } - 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] @@ -790,8 +790,8 @@ class Intersect { , l = s.map(Vec.norm); // 1) for each tri ray, if intersects and in segment interval, store minU, maxU - var minU:CurveTriPoint = null; - var maxU:CurveTriPoint = null; + var minU : CurveTriPoint = null; + var maxU : CurveTriPoint = null; //need to clip in order to maximize the width of the intervals for (i in 0...3) { @@ -829,8 +829,8 @@ 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 @@ -878,7 +878,7 @@ 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); @@ -956,7 +956,7 @@ 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); @@ -982,8 +982,8 @@ 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 { + public static function polylines(polyline0 : PolylineData, polyline1 : PolylineData, tol : Float) + : Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline0 ), @@ -1024,7 +1024,7 @@ class Intersect { // //* a CurveCurveIntersection object - public static function segments(a0:Point, a1:Point, b0:Point, b1:Point, tol:Float):CurveCurveIntersection { + 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)), @@ -1063,7 +1063,7 @@ class Intersect { // //* a CurveCurveIntersection object - public static function rays(a0:Point, a:Point, b0:Point, b:Point):CurveCurveIntersection { + public static function rays(a0 : Point, a : Point, b0 : Point, b : Point) : CurveCurveIntersection { var dab = Vec.dot(a, b), dab0 = Vec.dot(a, b0), @@ -1102,7 +1102,7 @@ class Intersect { // //* a TriangleSegmentIntersection or null if failed - public static function segmentWithTriangle(p0:Point, p1:Point, points:Array, tri:Tri):TriSegmentIntersection { + public static function segmentWithTriangle(p0 : Point, p1 : Point, points : Array, tri : Tri) : TriSegmentIntersection { var v0 = points[ tri[0] ] , v1 = points[ tri[1] ] @@ -1170,7 +1170,7 @@ class Intersect { //**returns** //null or an object with a p property representing the param on the segment - public static function segmentAndPlane(p0:Point, p1:Point, v0:Point, n:Point) { + 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)); @@ -1193,9 +1193,9 @@ class Intersect { } interface IBoundingBoxTree { - 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 boundingBox() : BoundingBox; + public function split() : Pair, IBoundingBoxTree>; + public function yield() : T; + public function indivisible(tolerance : Float) : Bool; + public function empty() : Bool; } diff --git a/src/verb/eval/Make.hx b/src/verb/eval/Make.hx index 2e955efa..33bdeaf4 100644 --- a/src/verb/eval/Make.hx +++ b/src/verb/eval/Make.hx @@ -40,7 +40,7 @@ class Make { // //* NurbsSurfaceData object - public static function rationalTranslationalSurface(profile:NurbsCurveData, rail:NurbsCurveData):NurbsSurfaceData { + public static function rationalTranslationalSurface(profile : NurbsCurveData, rail : NurbsCurveData) : NurbsSurfaceData { var pt0 = Eval.rationalCurvePoint(rail, rail.knots.first()) , startu = rail.knots.first() @@ -68,7 +68,7 @@ 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); @@ -80,7 +80,7 @@ class Make { } - public static function surfaceIsocurve(surface:NurbsSurfaceData, u:Float, useV:Bool = false):NurbsCurveData { + public static function surfaceIsocurve(surface : NurbsSurfaceData, u : Float, useV : Bool = false) : NurbsCurveData { var knots = useV ? surface.knotsV : surface.knotsU; var degree = useV ? surface.degreeV : surface.degreeU; @@ -88,7 +88,7 @@ class Make { var knotMults = Analyze.knotMultiplicities(knots); //if the knot already exists in the array, don't make duplicates - var reqKnotIndex:Int = -1; + var reqKnotIndex : Int = -1; for (i in 0...knotMults.length) { if (Math.abs(u - knotMults[i].knot) < Constants.EPSILON) { reqKnotIndex = i; @@ -120,7 +120,7 @@ class Make { return new NurbsCurveData( newSrf.degreeV, newSrf.knotsV, newSrf.controlPoints[span] ); } - public static function loftedSurface(curves:Array, degreeV:Int = null):NurbsSurfaceData { + public static function loftedSurface(curves : Array, degreeV : Int = null) : NurbsSurfaceData { curves = Modify.unifyCurveKnotVectors(curves); @@ -152,7 +152,7 @@ class Make { return new NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); } - public static function clonedCurve(curve:NurbsCurveData):NurbsCurveData { + public static function clonedCurve(curve : NurbsCurveData) : NurbsCurveData { return new NurbsCurveData( curve.degree, curve.knots.copy(), curve.controlPoints.map(function(x) { return x.copy(); }) ); } @@ -169,7 +169,7 @@ class Make { // //* NurbsSurfaceData object - public static function rationalBezierCurve(controlPoints:Array, weights:Array = null):NurbsCurveData { + public static function rationalBezierCurve(controlPoints : Array, weights : Array = null) : NurbsCurveData { var degree = controlPoints.length - 1; @@ -196,9 +196,9 @@ 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 degreeFloat : Float = degree; var pts = []; for (i in 0...degree + 1) { @@ -240,7 +240,7 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - public static function ellipseArc(center:Point, xaxis:Point, yaxis:Point, startAngle:Float, endAngle:Float):NurbsCurveData { + public static function ellipseArc(center : Point, xaxis : Point, yaxis : Point, startAngle : Float, endAngle : Float) : NurbsCurveData { var xradius = Vec.norm(xaxis); var yradius = Vec.norm(yaxis); @@ -345,8 +345,8 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - public static function arc(center:Point, xaxis:Vector, yaxis:Vector, radius:Float, startAngle:Float, - endAngle:Float):NurbsCurveData { + 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); } @@ -360,7 +360,7 @@ 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 lsum = 0.0; @@ -392,7 +392,7 @@ class Make { // //* an object with the following properties: controlPoints, weights, knots, degree - public static function extrudedSurface(axis:Point, length:Float, profile:NurbsCurveData):NurbsSurfaceData { + public static function extrudedSurface(axis : Point, length : Float, profile : NurbsCurveData) : NurbsSurfaceData { var controlPoints = [[], [], []] , weights = [[], [], []]; @@ -432,7 +432,7 @@ class Make { // //* an object with the following properties: controlPoints, weights, knotsU, knotsV, degreeU, degreeV - public static function cylindricalSurface(axis:Point, xaxis:Point, base:Point, height:Float, radius:Float):NurbsSurfaceData { + public static function cylindricalSurface(axis : Point, xaxis : Point, base : Point, height : Float, radius : Float) : NurbsSurfaceData { var yaxis = Vec.cross(axis, xaxis) , angle = 2.0 * Math.PI @@ -458,7 +458,7 @@ class Make { // //* an object with the following properties: controlPoints, weights, knots, degree - public static function revolvedSurface(profile:NurbsCurveData, center:Point, axis:Point, theta:Float):NurbsSurfaceData { + 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); @@ -594,7 +594,7 @@ 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); return revolvedSurface(arc, center, axis, 2 * Math.PI); @@ -615,7 +615,7 @@ class Make { //* an object with the following properties: controlPoints, weights, knots, degree // - public static function conicalSurface(axis:Point, xaxis:Point, base:Point, height:Float, radius:Float):NurbsSurfaceData { + public static function conicalSurface(axis : Point, xaxis : Point, base : Point, height : Float, radius : Float) : NurbsSurfaceData { var angle = 2 * Math.PI , prof_degree = 1 @@ -628,11 +628,11 @@ class Make { } - public static function rationalInterpCurve(points:Array>, - degree:Int = 3, - homogeneousPoints:Bool = false, - start_tangent:Point = null, - end_tangent:Point = null):NurbsCurveData { + public static function rationalInterpCurve(points : Array>, + degree : Int = 3, + homogeneousPoints : Bool = false, + start_tangent : Point = null, + end_tangent : Point = null) : NurbsCurveData { // 0) build knot vector for curve by normalized chord length // 1) construct effective basis function in square matrix (W) @@ -716,7 +716,7 @@ class Make { var mult0 = knots[degree + 1] / degree; for (i in 0...dim) { - var b:Array; + var b : Array; if (!hasTangents) { b = points.map(function(x) { return x[i]; }); diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index ce833da4..83f854f7 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -35,7 +35,7 @@ class Modify { // //* A new NURBS curve with a reversed parameterization - public static function curveReverse(curve:NurbsCurveData):NurbsCurveData { + public static function curveReverse(curve : NurbsCurveData) : NurbsCurveData { return new NurbsCurveData( curve.degree, knotsReverse(curve.knots), curve.controlPoints.reversed() ); } @@ -50,7 +50,7 @@ class Modify { // //* A new NURBS surface with a reversed parameterization in the given direction - public static function surfaceReverse(surface:NurbsSurfaceData, useV:Bool = false):NurbsSurfaceData { + 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() ]); @@ -71,7 +71,7 @@ class Modify { // //* The reversed array of knots - public static function knotsReverse(knots:KnotArray):KnotArray { + public static function knotsReverse(knots : KnotArray) : KnotArray { var min = knots.first(); var max = knots.last(); @@ -94,7 +94,7 @@ class Modify { // //* A collection of NURBS curves, all with the same knot vector - public static function unifyCurveKnotVectors(curves:Array):Array { + public static function unifyCurveKnotVectors(curves : Array) : Array { curves = curves.map(Make.clonedCurve); var maxDegree = curves.fold(function(x, a) { return Modify.imax(x.degree, a); }, 0); @@ -139,11 +139,11 @@ class Modify { return curves; } - private static function imin(a:Int, b:Int):Int { + private static function imin(a : Int, b : Int) : Int { return a < b ? a : b; } - private static function imax(a:Int, b:Int):Int { + private static function imax(a : Int, b : Int) : Int { return a > b ? a : b; } @@ -158,7 +158,7 @@ class Modify { // //* The NURBS curve after degree elevation - if the supplied degree is <= the curve is returned unmodified - public static function curveElevateDegree(curve:NurbsCurveData, finalDegree:Int):NurbsCurveData { + public static function curveElevateDegree(curve : NurbsCurveData, finalDegree : Int) : NurbsCurveData { if (finalDegree <= curve.degree) return curve; @@ -334,7 +334,7 @@ class Modify { // //* A new NURBS surface after transformation - public static function rationalSurfaceTransform(surface:NurbsSurfaceData, mat:Matrix):NurbsSurfaceData { + public static function rationalSurfaceTransform(surface : NurbsSurfaceData, mat : Matrix) : NurbsSurfaceData { var pts = Eval.dehomogenize2d(surface.controlPoints); @@ -361,7 +361,7 @@ class Modify { // //* A new NURBS surface after transformation - public static function rationalCurveTransform(curve:NurbsCurveData, mat:Matrix):NurbsCurveData { + public static function rationalCurveTransform(curve : NurbsCurveData, mat : Matrix) : NurbsCurveData { var pts = Eval.dehomogenize1d(curve.controlPoints); @@ -389,7 +389,7 @@ class Modify { // //* A new NURBS surface with the knots inserted - public static function surfaceKnotRefine(surface:NurbsSurfaceData, knotsToInsert:Array, useV:Bool):NurbsSurfaceData { + 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 @@ -412,7 +412,7 @@ class Modify { } //do knot refinement on every row - var c:NurbsCurveData = null; + var c : NurbsCurveData = null; for (cptrow in ctrlPts) { c = curveKnotRefine(new NurbsCurveData(degree, knots, cptrow), knotsToInsert); newPts.push(c.controlPoints); @@ -442,7 +442,7 @@ class Modify { // //* *Array* of NurbsCurveData objects, defined by degree, knots, and control points - public static function decomposeCurveIntoBeziers(curve:NurbsCurveData):Array { + public static function decomposeCurveIntoBeziers(curve : NurbsCurveData) : Array { var degree = curve.degree , controlPoints = curve.controlPoints @@ -499,7 +499,7 @@ class Modify { //* NurbsCurveData object representing the curve // - public static function curveKnotRefine(curve:NurbsCurveData, knotsToInsert:Array):NurbsCurveData { + public static function curveKnotRefine(curve : NurbsCurveData, knotsToInsert : Array) : NurbsCurveData { if (knotsToInsert.length == 0) return Make.clonedCurve(curve); @@ -595,7 +595,7 @@ class Modify { //* *Object* the new curve, defined by knots and controlPoints // - public static function curveKnotInsert(curve:NurbsCurveData, u:Float, r:Int):NurbsCurveData { + public static function curveKnotInsert(curve : NurbsCurveData, u : Float, r : Int) : NurbsCurveData { var degree = curve.degree , controlPoints = curve.controlPoints @@ -651,8 +651,8 @@ class Modify { controlPoints_temp[i] = controlPoints[k - degree + i]; } - var L:Int = 0 - , alpha:Float = 0; + var L : Int = 0 + , alpha : Float = 0; //insert knot r times for (j in 1...r + 1) { diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 734c91a0..898930b9 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -3,6 +3,10 @@ package verb.eval; import verb.core.ArrayExtensions; using verb.core.ArrayExtensions; +import verb.eval.Eval; + +import verb.core.Mat; +import verb.core.BoundingBox; import verb.core.Intersections; import verb.core.Data; import verb.core.Vec; @@ -20,6 +24,146 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { + // 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 representing the curve + //* number of divisions + // + //**returns** + // + //* an array of (divs+1) points + + public static function rationalCurveRegularSamplePoints2(crv : NurbsCurveData, tol : Float) : Array { + + var range = crv.knots.last() - crv.knots[0]; + var beziers = Modify.decomposeCurveIntoBeziers(crv); + var pts = [], step; + + for (i in 0...beziers.length) { + + step = rationalBezierCurveStepLength(beziers[i], tol) + + rationalBezierCurveRegularSamplePointsMutate(beziers[i], pts, currentU, step, bsteps + 1); + + currentU = nextU + step; + } + + return pts; + } + + // 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 representing the curve + //* number of divisions + // + //**returns** + // + //* an array of (divs+1) points + + public static function rationalCurveRegularSamplePoints(crv : NurbsCurveData, divs : Int) : Array { + + var range = crv.knots.last() - crv.knots[0]; + var beziers = 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); + + currentU = nextU + step; + } + + return pts; + } + + private static function rationalBezierCurveRegularSamplePointsMutate(crv : NurbsCurveData, + pts : Array, + startU : Float, + step : Float, + numSteps : Int) { + + var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; + + if (numSteps <= crv.degree + 1) { + for (i in 0...numSteps) { + pts.push(rationalCurvePoint(crv, u)); + u += step; + } + return; + } + + // initialize forward differencing + + for (i in 0...degree1) { + its.push(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(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(dehomogenize(front[0])); + } + } + //Compute the regular tessellation step length necessary to approximate a rational Bezier curve to the specified tolerance. // //**params** @@ -31,11 +175,11 @@ class Tess { // //* The step length - domain / step length yields the number of steps to take within the curve - public static function rationalBezierCurveStepLength(curve:NurbsCurveData, tol:Float):Float { + public static function rationalBezierCurveStepLength(curve : NurbsCurveData, tol : Float) : Float { // get average pt - var dehomo = dehomogenize1d(curve.controlPoints); + var dehomo = Eval.dehomogenize1d(curve.controlPoints); var bb = new BoundingBox( dehomo ); var avgPt = Vec.mul(0.5, Vec.add(bb.min, bb.max)); @@ -47,7 +191,7 @@ class Tess { m[2][3] = -avgPt[2]; var tc = Modify.rationalCurveTransform(curve, m); // todo util methods for translation - dehomo = dehomogenize1d(tc.controlPoints); + dehomo = Eval.dehomogenize1d(tc.controlPoints); // compute r = max( || Pi || ) @@ -59,7 +203,7 @@ class Tess { // compute w = min( wi ) - var wts = weight1d(curve.controlPoints); + var wts = Eval.weight1d(curve.controlPoints); var w = Vec.min(wts); var domain = curve.knots.last() - curve.knots[0]; @@ -90,7 +234,7 @@ class Tess { } } - private static function secondForwardDiff(array:Array) { + 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]); @@ -100,7 +244,7 @@ class Tess { return res; } - private static function secondForwardDiff2(array:Array) { + 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]))); @@ -122,7 +266,7 @@ class Tess { // //* an array of points, prepended by the point param if required - public static function rationalCurveRegularSample(curve:NurbsCurveData, numSamples:Int, includeU:Bool):Array { + public static function rationalCurveRegularSample(curve : NurbsCurveData, numSamples : Int, includeU : Bool) : Array { return rationalCurveRegularSampleRange(curve, curve.knots[0], curve.knots.last(), numSamples, includeU); } @@ -140,16 +284,16 @@ class Tess { // //* an dictionary of parameter - point pairs - public static function rationalCurveRegularSampleRange(curve:NurbsCurveData, start:Float, end:Float, - numSamples:Int, includeU:Bool):Array { + public static function rationalCurveRegularSampleRange(curve : NurbsCurveData, start : Float, end : Float, + numSamples : Int, includeU : Bool) : Array { if (numSamples < 1) { numSamples = 2; } var p = []; - var span:Float = (end - start) / (numSamples - 1); - var u:Float = 0; + var span : Float = (end - start) / (numSamples - 1); + var u : Float = 0; for (i in 0...numSamples) { @@ -179,7 +323,7 @@ class Tess { // //* 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 { + 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) { @@ -208,7 +352,7 @@ class Tess { // //* 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 rationalCurveAdaptiveSampleRange(curve:NurbsCurveData, start, end, tol, includeU):Array { + public static function rationalCurveAdaptiveSampleRange(curve : NurbsCurveData, start, end, tol, includeU) : Array { //sample curve at three pts var p1 = Eval.rationalCurvePoint(curve, start), @@ -255,7 +399,7 @@ class Tess { // //* 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; } @@ -325,7 +469,7 @@ class Tess { // //* 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(); @@ -422,7 +566,7 @@ class Tess { return divs[ index - 1 ]; } - private static function triangulateAdaptiveRefinementNodeTree(arrTree:Array):MeshData { + private static function triangulateAdaptiveRefinementNodeTree(arrTree : Array) : MeshData { //triangulate all of the nodes of the tree var mesh = MeshData.empty(); @@ -431,7 +575,7 @@ class Tess { } - public static function rationalSurfaceAdaptive(surface:NurbsSurfaceData, options:AdaptiveRefinementOptions = null):MeshData { + public static function rationalSurfaceAdaptive(surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null) : MeshData { options = options != null ? options : new AdaptiveRefinementOptions(); @@ -446,12 +590,12 @@ class Tess { @:expose("core.AdaptiveRefinementOptions") class AdaptiveRefinementOptions { - public var normTol:Float = 2.5e-2; - public var minDepth:Int = 0; - public var maxDepth:Int = 10; - public var refine:Bool = true; - public var minDivsU:Int = 1; - public var minDivsV:Int = 1; + public var normTol : Float = 2.5e-2; + public var minDepth : Int = 0; + public var maxDepth : Int = 10; + public var refine : Bool = true; + public var minDivsU : Int = 1; + public var minDivsV : Int = 1; public function new() {} @@ -484,19 +628,19 @@ class AdaptiveRefinementOptions { @:expose("core.AdaptiveRefinementNode") class AdaptiveRefinementNode { - var srf:NurbsSurfaceData; - public var neighbors:Array; - var children:Array; - var corners:Array; - var midPoints:Array; - var centerPoint:SurfacePoint; - var splitVert:Bool; - var splitHoriz:Bool; - var horizontal:Bool; - var u05:Float; - var v05:Float; + var srf : NurbsSurfaceData; + public var neighbors : Array; + var children : Array; + var corners : Array; + var midPoints : Array; + var centerPoint : SurfacePoint; + var splitVert : Bool; + var splitHoriz : Bool; + var horizontal : Bool; + var u05 : Float; + var v05 : Float; - public function new(srf:NurbsSurfaceData, corners:Array, neighbors:Array = null) { + public function new(srf : NurbsSurfaceData, corners : Array, neighbors : Array = null) { this.srf = srf; @@ -506,10 +650,10 @@ class AdaptiveRefinementNode { //if no corners, we need to construct initial corners from the surface if (this.corners == null) { - var u0:Float = srf.knotsU[0]; - var u1:Float = srf.knotsU.last(); - var v0:Float = srf.knotsV[0]; - var v1:Float = srf.knotsV.last(); + var u0 : Float = srf.knotsU[0]; + var u1 : Float = srf.knotsU.last(); + var v0 : Float = srf.knotsV[0]; + var v1 : Float = srf.knotsV.last(); this.corners = [ SurfacePoint.fromUv(u0, v0), @@ -545,7 +689,7 @@ class AdaptiveRefinementNode { } } - public function evalSrf(u:Float, v:Float, srfPt:SurfacePoint = null):SurfacePoint { + public function evalSrf(u : Float, v : Float, srfPt : SurfacePoint = null) : SurfacePoint { var derivs = Eval.rationalSurfaceDerivatives(this.srf, u, v, 1); var pt = derivs[0][0]; @@ -564,7 +708,7 @@ class AdaptiveRefinementNode { } } - public function getEdgeCorners(edgeIndex:Int):Array { + 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 ] ]; @@ -599,7 +743,7 @@ class AdaptiveRefinementNode { return null; } - public function getAllCorners(edgeIndex:Int):Array { + public function getAllCorners(edgeIndex : Int) : Array { var baseArr = [ this.corners[edgeIndex] ]; @@ -648,11 +792,11 @@ 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) { @@ -669,7 +813,7 @@ class AdaptiveRefinementNode { } } - 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; @@ -696,7 +840,7 @@ class AdaptiveRefinementNode { Vec.normSquared(Vec.sub(center.normal, this.corners[3].normal)) > options.normTol; } - public function divide(options:AdaptiveRefinementOptions = null):Void { + 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; @@ -707,7 +851,7 @@ class AdaptiveRefinementNode { this._divide(options, 0, true); } - private function _divide(options:AdaptiveRefinementOptions, currentDepth:Int, horiz:Bool):Void { + private function _divide(options : AdaptiveRefinementOptions, currentDepth : Int, horiz : Bool) : Void { this.evalCorners(); @@ -756,7 +900,7 @@ class AdaptiveRefinementNode { } - public function triangulate(mesh:MeshData = null):MeshData { + public function triangulate(mesh : MeshData = null) : MeshData { if (mesh == null) mesh = MeshData.empty(); @@ -771,7 +915,7 @@ class AdaptiveRefinementNode { return mesh; } - public function triangulateLeaf(mesh:MeshData):MeshData { + public function triangulateLeaf(mesh : MeshData) : MeshData { var baseIndex = mesh.points.length , uvs = [] diff --git a/src/verb/exe/Dispatcher.hx b/src/verb/exe/Dispatcher.hx index 7dd2c587..f8698739 100644 --- a/src/verb/exe/Dispatcher.hx +++ b/src/verb/exe/Dispatcher.hx @@ -12,17 +12,17 @@ import promhx.Promise; @:expose("exe.Dispatcher") class Dispatcher { - public static var THREADS:Int = 1; + 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 var _init : Bool = false; - private static function init():Void { + private static function init() : Void { if (_init) return; @@ -35,7 +35,7 @@ class Dispatcher { _init = true; } - public static function dispatchMethod(classType:Class, methodName:String, args:Array):Promise { + public static function dispatchMethod(classType : Class, methodName : String, args : Array) : Promise { init(); @@ -48,7 +48,7 @@ class Dispatcher { #if js _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 74c58a12..57e61566 100644 --- a/src/verb/exe/ThreadPool.hx +++ b/src/verb/exe/ThreadPool.hx @@ -10,25 +10,25 @@ import cpp.vm.Mutex; #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 { + 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; + var d : Bool = _done; mutex.release(); return d; } - private var _result:Dynamic; - public var result(get, never):Dynamic; + private var _result : Dynamic; + public var result(get, never) : Dynamic; - private function get_result():Dynamic { + private function get_result() : Dynamic { mutex.acquire(); - var r:Dynamic = _result; + var r : Dynamic = _result; mutex.release(); return r; } @@ -37,7 +37,7 @@ private class PoolThread { mutex = new Mutex(); } - public function start(task:Dynamic -> Dynamic, arg:Dynamic):Void { + public function start(task : Dynamic -> Dynamic, arg : Dynamic) : Void { this.task = task; started = true; _done = false; @@ -45,9 +45,9 @@ private class PoolThread { thread.sendMessage(arg); } - private function doWork():Void { - var arg:Dynamic = Thread.readMessage(true); - var ret:Dynamic = task(arg); + private function doWork() : Void { + var arg : Dynamic = Thread.readMessage(true); + var ret : Dynamic = task(arg); mutex.acquire(); _result = ret; _done = true; @@ -58,14 +58,14 @@ private class PoolThread { 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; + var thread : PoolThread; #end - var onFinish:Dynamic -> Void; + var onFinish : Dynamic -> Void; } /** @@ -74,13 +74,13 @@ private typedef Task = */ class ThreadPool { #if (neko || cpp) - private var numThreads:Int = 1; - private var threads:Array; + private var numThreads : Int = 1; + private var threads : Array; #end - private var tasks:Array; - private var nextID:Int = 0; + private var tasks : Array; + private var nextID : Int = 0; - public function new(numThreads:Int) { + public function new(numThreads : Int) { tasks = new Array (); #if (neko || cpp) this.numThreads = numThreads; @@ -91,7 +91,7 @@ class ThreadPool { #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++; } diff --git a/src/verb/exe/WorkerPool.hx b/src/verb/exe/WorkerPool.hx index ecccbe6b..233528b8 100644 --- a/src/verb/exe/WorkerPool.hx +++ b/src/verb/exe/WorkerPool.hx @@ -11,8 +11,8 @@ import js.html.Worker; @:expose("exe.WorkerPool") class WorkerPool { - private var _queue:Array = []; - private var _pool:Array = []; + private var _queue : Array = []; + private var _pool : Array = []; private var _working = new IntMap(); private var _callbacks = new IntMap(); @@ -23,13 +23,13 @@ class WorkerPool { //* the number of `Worker` threads to form //* the filename of verb's javascript file - defaults to "verb.js". The final path is formed by concatenating `WorkerPool.basePath` and this. - public function new(numThreads:Int = 1, fileName:String = "verb.js") { + public function new(numThreads : Int = 1, fileName : String = "verb.js") { for (i in 0...numThreads) { - var w:Worker; + var w : Worker; try { w = new Worker( basePath + fileName ); - } catch (e:Dynamic) { + } catch (e : Dynamic) { w = new Worker( basePath + fileName.substring(0, -3) + ".min.js" ); } @@ -43,10 +43,10 @@ class WorkerPool { // Add work to perform to the queue - public function addWork(className:String, - methodName:String, - args:Array, - callback:Dynamic):Void { + public function addWork(className : String, + methodName : String, + args : Array, + callback : Dynamic) : Void { var work = new Work( className, methodName, args ); _callbacks.set(work.id, callback); @@ -77,7 +77,7 @@ class WorkerPool { _callbacks.get(workId)(e.data.result); _callbacks.remove(workId); } - } catch (error:Dynamic) { + } catch (error : Dynamic) { trace(error); } @@ -92,12 +92,12 @@ class WorkerPool { private class Work { - private static var uuid:Int = 0; + private static var uuid : Int = 0; - public var className:String; - public var methodName:String; - public var args:Array; - public var id:Int; + public var className : String; + public var methodName : String; + public var args : Array; + public var id : Int; public function new(className, methodName, args) { this.className = className; diff --git a/src/verb/geom/Arc.hx b/src/verb/geom/Arc.hx index 10594edf..72ef2813 100644 --- a/src/verb/geom/Arc.hx +++ b/src/verb/geom/Arc.hx @@ -24,12 +24,12 @@ 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) { + 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; @@ -40,35 +40,35 @@ class Arc extends NurbsCurve { _maxAngle = maxAngle; } - private var _center:Point; - private var _xaxis:Vector; - private var _yaxis:Vector; - private var _radius:Float; - private var _minAngle:Float; - private var _maxAngle:Float; + private var _center : Point; + private var _xaxis : Vector; + private var _yaxis : Vector; + private var _radius : Float; + private var _minAngle : Float; + 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/BezierCurve.hx b/src/verb/geom/BezierCurve.hx index b1b06404..a880ab10 100644 --- a/src/verb/geom/BezierCurve.hx +++ b/src/verb/geom/BezierCurve.hx @@ -17,7 +17,7 @@ class BezierCurve extends NurbsCurve { //* Array of control points //* Array of control point weights (optional) - public function new(points:Array, weights:Array = null) { + public function new(points : Array, weights : Array = null) { super(Make.rationalBezierCurve(points, weights)); } } \ No newline at end of file diff --git a/src/verb/geom/Circle.hx b/src/verb/geom/Circle.hx index 6e3aff75..4f8187dc 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 fa733361..8f657b58 100644 --- a/src/verb/geom/ConicalSurface.hx +++ b/src/verb/geom/ConicalSurface.hx @@ -19,7 +19,7 @@ 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) { + public function new(axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float) { super(Make.conicalSurface(axis, xaxis, base, height, radius)); _axis = axis; @@ -29,11 +29,11 @@ class ConicalSurface extends NurbsSurface { _radius = radius; } - private var _axis:Vector; - private var _xaxis:Vector; - private var _base:Point; - private var _height:Float; - private var _radius:Float; + private var _axis : Vector; + private var _xaxis : Vector; + private var _base : Point; + private var _height : Float; + private var _radius : Float; //Length 3 array representing the axis of the cone diff --git a/src/verb/geom/CylindricalSurface.hx b/src/verb/geom/CylindricalSurface.hx index a6fc1fe4..b7c8a989 100644 --- a/src/verb/geom/CylindricalSurface.hx +++ b/src/verb/geom/CylindricalSurface.hx @@ -21,7 +21,7 @@ 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) { + public function new(axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float) { super(Make.cylindricalSurface(axis, xaxis, base, height, radius)); _axis = axis; @@ -31,11 +31,11 @@ class CylindricalSurface extends NurbsSurface { _radius = radius; } - private var _axis:Vector; - private var _xaxis:Vector; - private var _base:Point; - private var _height:Float; - private var _radius:Float; + private var _axis : Vector; + private var _xaxis : Vector; + private var _base : Point; + private var _height : Float; + private var _radius : Float; //Length 3 array representing the axis of the cylinder diff --git a/src/verb/geom/Ellipse.hx b/src/verb/geom/Ellipse.hx index 4749180b..13066b2b 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 d0bacfbe..75cb9f4b 100644 --- a/src/verb/geom/EllipseArc.hx +++ b/src/verb/geom/EllipseArc.hx @@ -20,11 +20,11 @@ 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) { + public function new(center : Point, + xaxis : Vector, + yaxis : Vector, + minAngle : Float, + maxAngle : Float) { super(Make.ellipseArc(center, xaxis, yaxis, minAngle, maxAngle)); _center = center; @@ -34,11 +34,11 @@ class EllipseArc extends NurbsCurve { _maxAngle = maxAngle; } - private var _center:Point; - private var _xaxis:Vector; - private var _yaxis:Vector; - private var _minAngle:Float; - private var _maxAngle:Float; + private var _center : Point; + private var _xaxis : Vector; + private var _yaxis : Vector; + private var _minAngle : Float; + private var _maxAngle : Float; //Length 3 array representing the center of the arc diff --git a/src/verb/geom/ExtrudedSurface.hx b/src/verb/geom/ExtrudedSurface.hx index ee20b7d2..5772bbe1 100644 --- a/src/verb/geom/ExtrudedSurface.hx +++ b/src/verb/geom/ExtrudedSurface.hx @@ -15,22 +15,22 @@ class ExtrudedSurface extends NurbsSurface { //* The profile curve //* The direction and magnitude of the extrusion - public function new(profile:ICurve, direction:Vector) { + public function new(profile : ICurve, direction : Vector) { super(Make.extrudedSurface(Vec.normalized(direction), Vec.norm(direction), profile.asNurbs())); _profile = profile; _direction = direction; } - private var _profile:ICurve; - private var _direction:Vector; + private var _profile : ICurve; + private var _direction : Vector; //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 679ea89d..22967dcd 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 57fc9494..ced0f206 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 3607bd51..38cabe4f 100644 --- a/src/verb/geom/Intersect.hx +++ b/src/verb/geom/Intersect.hx @@ -28,13 +28,13 @@ class Intersect { // //* a possibly empty array of CurveCurveIntersection objects - public static function curves(first:ICurve, second:ICurve, tol:Float = 1e-3):Array { + 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> { + 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 ]); } @@ -50,13 +50,13 @@ class Intersect { // //* array of CurveSurfaceIntersection objects - public static function curveAndSurface(curve:ICurve, surface:ISurface, tol:Float = 1e-3):Array { + public static function curveAndSurface(curve : ICurve, surface : ISurface, tol : Float = 1e-3) : Array { 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> { + 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 ]); } @@ -71,14 +71,14 @@ class Intersect { // //* array of NurbsCurveData objects - public static function surfaces(first:ISurface, second:ISurface, tol:Float = 1e-3):Array { + 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> { + 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 4386d52a..b10f05e1 100644 --- a/src/verb/geom/Line.hx +++ b/src/verb/geom/Line.hx @@ -17,15 +17,15 @@ class Line extends NurbsCurve { //* Length 3 array representing the start point //* Length 3 array representing the end point - public function new(start:Point, end:Point) { + public function new(start : Point, end : Point) { super(Make.polyline([ start, end ])); _start = start; _end = end; } - private var _start:Point; - private var _end:Point; + private var _start : Point; + private var _end : Point; //Length 3 array representing the start point diff --git a/src/verb/geom/NurbsCurve.hx b/src/verb/geom/NurbsCurve.hx index f5fc77a3..d3bd5c2c 100644 --- a/src/verb/geom/NurbsCurve.hx +++ b/src/verb/geom/NurbsCurve.hx @@ -42,7 +42,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public function new(data:NurbsCurveData) { + public function new(data : NurbsCurveData) { this._data = Check.isValidNurbsCurveData(data); } @@ -59,10 +59,10 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public static function byKnotsControlPointsWeights(degree:Int, - knots:KnotArray, - controlPoints:Array, - weights:Array = null):NurbsCurve { + public static function byKnotsControlPointsWeights(degree : Int, + knots : KnotArray, + controlPoints : Array, + weights : Array = null) : NurbsCurve { return new NurbsCurve( new NurbsCurveData( degree, knots.copy(), Eval.homogenize1d(controlPoints, weights) ) ); } @@ -78,28 +78,28 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public static function byPoints(points:Array, degree:Int = 3):NurbsCurve { + public static function byPoints(points : Array, degree : Int = 3) : NurbsCurve { return new NurbsCurve( Make.rationalInterpCurve(points, degree) ); } //underlying serializable, data object - private var _data:NurbsCurveData; + 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. // @@ -107,7 +107,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurveData object - public function asNurbs():NurbsCurveData { + public function asNurbs() : NurbsCurveData { return new NurbsCurveData( degree(), knots(), Eval.homogenize1d(controlPoints(), weights())); } @@ -127,7 +127,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* An array representing the high and end point of the domain of the curve - public function domain():Interval { + public function domain() : Interval { return new Interval( _data.knots.first(), _data.knots.last()); } @@ -141,13 +141,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function transform(mat:Matrix):NurbsCurve { + public function transform(mat : Matrix) : NurbsCurve { return new NurbsCurve( Modify.rationalCurveTransform(_data, mat) ); } //The async version of `transform` - public function transformAsync(mat:Matrix):Promise { + public function transformAsync(mat : Matrix) : Promise { return Dispatcher.dispatchMethod(Modify, 'rationalCurveTransform', [ _data, mat ]) .then(function(x) { return new NurbsCurve(x); }); } @@ -162,13 +162,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function point(u:Float):Point { + public function point(u : Float) : Point { return Eval.rationalCurvePoint(_data, u); } //The async version of `point` - public function pointAsync(u:Float):Promise { + public function pointAsync(u : Float) : Promise { return Dispatcher.dispatchMethod(Eval, 'rationalCurvePoint', [ _data, u ]); } @@ -183,13 +183,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function tangent(u:Float):Vector { + public function tangent(u : Float) : Vector { return Eval.rationalCurveTangent(_data, u); } //The async version of `tangent` - public function tangentAsync(u:Float):Promise { + public function tangentAsync(u : Float) : Promise { return Dispatcher.dispatchMethod(Eval, 'rationalCurveTangent', [ _data, u ]); } @@ -204,13 +204,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function derivatives(u:Float, numDerivs:Int = 1):Array { + public function derivatives(u : Float, numDerivs : Int = 1) : Array { return Eval.rationalCurveDerivatives(_data, u, numDerivs); } //The async version of `derivatives` - public function derivativesAsync(u:Float, numDerivs:Int = 1):Promise> { + public function derivativesAsync(u : Float, numDerivs : Int = 1) : Promise> { return Dispatcher.dispatchMethod(Eval, 'rationalCurveDerivatives', [ _data, u, numDerivs ]); } @@ -224,13 +224,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The closest point - public function closestPoint(pt:Point):Point { + public function closestPoint(pt : Point) : Point { return Analyze.rationalCurveClosestPoint(_data, pt); } //The async version of `closestPoint` - public function closestPointAsync(pt:Point):Promise { + public function closestPointAsync(pt : Point) : Promise { return Dispatcher.dispatchMethod(Analyze, 'rationalCurveClosestPoint', [ _data, pt ]); } @@ -244,13 +244,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The closest parameter - public function closestParam(pt:Point):Float { + public function closestParam(pt : Point) : Float { return Analyze.rationalCurveClosestParam(_data, pt); } //The async version of `length` - public function closestParamAsync(pt:Dynamic):Promise { + public function closestParamAsync(pt : Dynamic) : Promise { return Dispatcher.dispatchMethod(Analyze, 'rationalCurveClosestParam', [ _data, pt ]); } @@ -260,13 +260,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 ]); } @@ -280,13 +280,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve at the given parameter - public function lengthAtParam(u:Float):Float { + public function lengthAtParam(u : Float) : Float { return Analyze.rationalCurveArcLength(_data, u); } //The async version of `lengthAtParam` - public function lengthAtParamAsync():Promise { + public function lengthAtParamAsync() : Promise { return Dispatcher.dispatchMethod(Analyze, 'rationalCurveArcLength', [ _data ]); } @@ -300,13 +300,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve at the given parameter - public function paramAtLength(len:Float, tolerance:Float = null):Float { + public function paramAtLength(len : Float, tolerance : Float = null) : Float { return Analyze.rationalCurveParamAtArcLength(_data, len, tolerance); } //The async version of `paramAtLength` - public function paramAtLengthAsync(len:Float, tolerance:Float = null):Promise { + public function paramAtLengthAsync(len : Float, tolerance : Float = null) : Promise { return Dispatcher.dispatchMethod(Analyze, 'rationalCurveParamAtArcLength', [ _data, len, tolerance ]); } @@ -320,13 +320,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A collection of parameters - public function divideByEqualArcLength(divisions:Int):Array { + public function divideByEqualArcLength(divisions : Int) : Array { return Divide.rationalCurveByEqualArcLength(_data, divisions); } //The async version of `divideByEqualArcLength`` - public function divideByEqualArcLengthAsync(divisions:Int):Promise> { + public function divideByEqualArcLengthAsync(divisions : Int) : Promise> { return Dispatcher.dispatchMethod(Divide, 'rationalCurveByEqualArcLength', [ _data, divisions ]); } @@ -340,13 +340,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A collection of parameters - public function divideByArcLength(arcLength:Float):Array { + public function divideByArcLength(arcLength : Float) : Array { return Divide.rationalCurveByArcLength(_data, arcLength); } //The async version of `divideByArcLength` - public function divideByArcLengthAsync(divisions:Int):Promise> { + public function divideByArcLengthAsync(divisions : Int) : Promise> { return Dispatcher.dispatchMethod(Divide, 'rationalCurveByArcLength', [ _data, divisions ]); } @@ -360,15 +360,15 @@ 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 { + public function split(u : Float) : Array { return Divide.curveSplit(_data, u).map(function(x) { return new NurbsCurve(x); }); } // The async version of `split` - public function splitAsync(u:Float):Promise> { + public function splitAsync(u : Float) : Promise> { return Dispatcher.dispatchMethod(Divide, 'curveSplit', [ _data, u ]) - .then(function(cs:Array):Array { + .then(function(cs : Array) : Array { return cs.map(function(x) { return new NurbsCurve(x); }); }); } @@ -379,13 +379,13 @@ 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 { + public function reverseAsync() : Promise { return Dispatcher.dispatchMethod(Modify, 'curveReverse', [ _data ]) .then(function(c) { return new NurbsCurve(c); }); } @@ -400,13 +400,13 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function tessellate(tolerance:Float = null):Array { + public function tessellate(tolerance : Float = null) : Array { return Tess.rationalCurveAdaptiveSample(_data, tolerance, false); } // The async version of `tessellate` - public function tessellateAsync(tolerance:Float = null):Promise> { + public function tessellateAsync(tolerance : Float = null) : Promise> { return Dispatcher.dispatchMethod(Tess, 'rationalCurveAdaptiveSample', [ _data, tolerance, false ]); } diff --git a/src/verb/geom/NurbsSurface.hx b/src/verb/geom/NurbsSurface.hx index 64ea35d3..d1008370 100644 --- a/src/verb/geom/NurbsSurface.hx +++ b/src/verb/geom/NurbsSurface.hx @@ -40,7 +40,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public function new(data:NurbsSurfaceData) { + public function new(data : NurbsSurfaceData) { _data = Check.isValidNurbsSurfaceData(data); } @@ -60,12 +60,12 @@ 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 { + 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) ) ); } @@ -82,7 +82,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public static function byCorners(point0:Point, point1:Point, point2:Point, point3:Point):NurbsSurface { + public static function byCorners(point0 : Point, point1 : Point, point2 : Point, point3 : Point) : NurbsSurface { return new NurbsSurface( Make.fourPointSurface(point0, point1, point2, point3) ); } @@ -96,38 +96,38 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public static function byLoftingCurves(curves:Array, degreeV:Int = null):NurbsSurface { + public static function byLoftingCurves(curves : Array, degreeV : Int = null) : NurbsSurface { return new NurbsSurface( Make.loftedSurface([for (c in curves) c.asNurbs() ], degreeV)); } //underlying serializable, data object - private var _data:NurbsSurfaceData; + private var _data : NurbsSurfaceData; //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,7 +135,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurfaceData object - public function asNurbs():NurbsSurfaceData { + public function asNurbs() : NurbsSurfaceData { return new NurbsSurfaceData( degreeU(), degreeV(), knotsU(), knotsV(), Eval.homogenize2d(controlPoints(), weights())); } @@ -145,7 +145,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public function clone():NurbsSurface { + public function clone() : NurbsSurface { return new NurbsSurface( asNurbs() ); } @@ -155,7 +155,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* An Interval object with min and max property - public function domainU():Interval { + public function domainU() : Interval { return new Interval( _data.knotsU.first(), _data.knotsU.last()); } @@ -165,7 +165,7 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* An Interval object with min and max property - public function domainV():Interval { + public function domainV() : Interval { return new Interval( _data.knotsV.first(), _data.knotsV.last()); } @@ -180,13 +180,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A point on the surface - public function point(u:Float, v:Float):Point { + public function point(u : Float, v : Float) : Point { return Eval.rationalSurfacePoint(_data, u, v); } //The async version of `point` - public function pointAsync(u:Float, v:Float):Promise { + public function pointAsync(u : Float, v : Float) : Promise { return Dispatcher.dispatchMethod(Eval, 'rationalSurfacePoint', [ _data, u, v ]); } @@ -201,13 +201,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A normalized vector normal to the surface - public function normal(u:Float, v:Float):Point { + public function normal(u : Float, v : Float) : Point { return Eval.rationalSurfaceNormal(_data, u, v); } //The async version of `normal` - public function normalAsync(u:Float, v:Float):Promise>> { + public function normalAsync(u : Float, v : Float) : Promise>> { return Dispatcher.dispatchMethod(Eval, 'rationalSurfaceNormal', [ _data, u, v ]); } @@ -227,13 +227,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A two dimensional array of vectors - public function derivatives(u:Float, v:Float, numDerivs:Int = 1):Array> { + public function derivatives(u : Float, v : Float, numDerivs : Int = 1) : Array> { return Eval.rationalSurfaceDerivatives(_data, u, v, numDerivs); } //The async version of `derivatives` - public function derivativesAsync(u:Float, v:Float, numDerivs:Int = 1):Promise>> { + public function derivativesAsync(u : Float, v : Float, numDerivs : Int = 1) : Promise>> { return Dispatcher.dispatchMethod(Eval, 'rationalSurfaceDerivatives', [ _data, u, v, numDerivs ]); } @@ -248,13 +248,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The closest point - public function closestParam(pt:Point):UV { + public function closestParam(pt : Point) : UV { return Analyze.rationalSurfaceClosestParam(_data, pt); } //The async version of `closestParam` - public function closestParamAsync(pt:Point):Promise { + public function closestParamAsync(pt : Point) : Promise { return Dispatcher.dispatchMethod(Analyze, 'rationalSurfaceClosestParam', [ _data, pt ]); } @@ -268,13 +268,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The closest point - public function closestPoint(pt:Point):Point { + public function closestPoint(pt : Point) : Point { return Analyze.rationalSurfaceClosestPoint(_data, pt); } //The async version of `closestParam` - public function closestPointAsync(pt:Point):Promise { + public function closestPointAsync(pt : Point) : Promise { return Dispatcher.dispatchMethod(Analyze, 'rationalSurfaceClosestPoint', [ _data, pt ]); } @@ -289,14 +289,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A length 2 array with two new NurbsSurface objects - public function split(u:Float, useV:Bool = false):Array { + public function split(u : Float, useV : Bool = false) : Array { return Divide.surfaceSplit(_data, u, useV) .map(function(x) { return new NurbsSurface(x); }); } //The async version of `split` - public function splitAsync(u:Float, useV:Bool = false):Promise> { + 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); }); @@ -313,13 +313,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The reversed surface - public function reverse(useV:Bool = false):NurbsSurface { + public function reverse(useV : Bool = false) : NurbsSurface { return new NurbsSurface( Modify.surfaceReverse(_data, useV) ); } //The async version of `reverse` - public function reverseAsync(useV:Bool = false):Promise { + public function reverseAsync(useV : Bool = false) : Promise { return Dispatcher.dispatchMethod(Modify, 'surfaceReverse', [ _data, useV ]) .then(function(c) { return new NurbsSurface(c); }); } @@ -335,13 +335,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A NurbsCurve in the provided direction - public function isocurve(u:Float, useV:Bool = false):NurbsCurve { + public function isocurve(u : Float, useV : Bool = false) : NurbsCurve { return new NurbsCurve( Make.surfaceIsocurve(_data, u, useV) ); } //The async version of `isocurve` - public function isocurveAsync(u:Float, useV:Bool = false):Promise { + public function isocurveAsync(u : Float, useV : Bool = false) : Promise { return Dispatcher.dispatchMethod(Make, 'surfaceIsocurve', [ _data, u, useV ]) .then(function(x) { return new NurbsCurve(x); }); } @@ -352,15 +352,15 @@ 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 { + 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> { + public function boundariesAsync(options : AdaptiveRefinementOptions = null) : Promise> { return Dispatcher.dispatchMethod(Make, 'surfaceBoundaryCurves', [ _data ]) - .then(function(cs:Array) { + .then(function(cs : Array) { return cs.map(function(x) { return new NurbsCurve(x); }); }); @@ -376,13 +376,13 @@ 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 { + public function tessellateAsync(options : AdaptiveRefinementOptions = null) : Promise { return Dispatcher.dispatchMethod(Tess, 'rationalSurfaceAdaptive', [ _data, options ]); } @@ -396,13 +396,13 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new Surface - public function transform(mat:Matrix):NurbsSurface { + public function transform(mat : Matrix) : NurbsSurface { return new NurbsSurface( Modify.rationalSurfaceTransform(_data, mat) ); } //The async version of `transform` - public function transformAsync(mat:Matrix):Promise { + public function transformAsync(mat : Matrix) : Promise { 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 5d7842b9..3c67951a 100644 --- a/src/verb/geom/RevolvedSurface.hx +++ b/src/verb/geom/RevolvedSurface.hx @@ -18,7 +18,7 @@ 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) { + public function new(profile : NurbsCurve, center : Point, axis : Vector, angle : Float) { super(Make.revolvedSurface(profile.asNurbs(), center, axis, angle)); _profile = profile; @@ -27,25 +27,25 @@ class RevolvedSurface extends NurbsSurface { _angle = angle; } - private var _profile:ICurve; - private var _center:Point; - private var _axis:Vector; - private var _angle:Float; + private var _profile : ICurve; + private var _center : Point; + private var _axis : Vector; + private var _angle : Float; //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 43b65603..82d8bf12 100644 --- a/src/verb/geom/SphericalSurface.hx +++ b/src/verb/geom/SphericalSurface.hx @@ -17,24 +17,24 @@ class SphericalSurface extends NurbsSurface { //* Length 3 array representing the center of the circle //* Radius of the circle - public function new(center:Point, - radius:Float) { + public function new(center : Point, + radius : Float) { super(Make.sphericalSurface(center, [0, 0, 1], [1, 0, 0], radius)); _center = center; _radius = radius; } - private var _center:Point; - private var _radius:Float; + private var _center : Point; + private var _radius : Float; //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 a0e346e4..d27a03f0 100644 --- a/src/verb/geom/SweptSurface.hx +++ b/src/verb/geom/SweptSurface.hx @@ -17,23 +17,23 @@ class SweptSurface extends NurbsSurface { //* The profile curve //* The rail curve - public function new(profile:ICurve, rail:ICurve) { + public function new(profile : ICurve, rail : ICurve) { super(Make.rationalTranslationalSurface(profile.asNurbs(), rail.asNurbs())); _profile = profile; _rail = rail; } - private var _profile:ICurve; - private var _rail:ICurve; + private var _profile : ICurve; + private var _rail : ICurve; //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; } } From ca71c218561249edbbc1e8c15d30382651b2551f Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Tue, 10 Nov 2015 15:38:18 -0500 Subject: [PATCH 10/25] More code clean up --- src/verb/Verb.hx | 4 +- src/verb/core/ArrayExtensions.hx | 66 +- src/verb/core/Binomial.hx | 46 +- src/verb/core/BoundingBox.hx | 80 +-- src/verb/core/Data.hx | 20 +- src/verb/core/Intersections.hx | 20 +- src/verb/core/KdTree.hx | 154 ++--- src/verb/core/LazyCurveBoundingBoxTree.hx | 28 +- src/verb/core/LazyMeshBoundingBoxTree.hx | 26 +- src/verb/core/LazyPolylineBoundingBoxTree.hx | 18 +- src/verb/core/LazySurfaceBoundingBoxTree.hx | 40 +- src/verb/core/Mat.hx | 88 +-- src/verb/core/Mesh.hx | 72 +- src/verb/core/MeshBoundingBoxTree.hx | 28 +- src/verb/core/Minimizer.hx | 100 +-- src/verb/core/Serialization.hx | 12 +- src/verb/core/SurfaceBoundingBoxTree.hx | 48 +- src/verb/core/Trig.hx | 56 +- src/verb/core/Vec.hx | 234 +++---- src/verb/eval/Analyze.hx | 236 +++---- src/verb/eval/Check.hx | 64 +- src/verb/eval/Divide.hx | 78 +-- src/verb/eval/Eval.hx | 586 ++++++++-------- src/verb/eval/Intersect.hx | 678 +++++++++---------- src/verb/eval/Make.hx | 364 +++++----- src/verb/eval/Modify.hx | 274 ++++---- src/verb/eval/Tess.hx | 565 +++++++--------- src/verb/exe/Dispatcher.hx | 16 +- src/verb/exe/ThreadPool.hx | 42 +- src/verb/exe/WorkerPool.hx | 56 +- src/verb/geom/Arc.hx | 26 +- src/verb/geom/BezierCurve.hx | 4 +- src/verb/geom/Circle.hx | 10 +- src/verb/geom/ConicalSurface.hx | 14 +- src/verb/geom/CylindricalSurface.hx | 14 +- src/verb/geom/Ellipse.hx | 8 +- src/verb/geom/EllipseArc.hx | 22 +- src/verb/geom/ExtrudedSurface.hx | 8 +- src/verb/geom/ICurve.hx | 8 +- src/verb/geom/ISurface.hx | 10 +- src/verb/geom/Intersect.hx | 32 +- src/verb/geom/Line.hx | 8 +- src/verb/geom/NurbsCurve.hx | 158 ++--- src/verb/geom/NurbsSurface.hx | 162 ++--- src/verb/geom/RevolvedSurface.hx | 12 +- src/verb/geom/SphericalSurface.hx | 10 +- src/verb/geom/SweptSurface.hx | 8 +- 47 files changed, 2278 insertions(+), 2335 deletions(-) diff --git a/src/verb/Verb.hx b/src/verb/Verb.hx index 89ab84ce..28bcd39d 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.0.0" ); } } \ No newline at end of file diff --git a/src/verb/core/ArrayExtensions.hx b/src/verb/core/ArrayExtensions.hx index f3dcd843..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,7 +46,7 @@ class ArrayExtensions { // //* the last element of the array - public static function last(a : Array) : T { + public static function last( a : Array ) : T { return a[a.length - 1]; } @@ -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,10 +79,10 @@ class ArrayExtensions { // //* the left half - public static function left(arr : Array) : Array { - if (arr.length == 0) return []; - var len = Math.ceil(arr.length / 2); - return arr.slice(0, len); + public static function left( arr : Array ) : Array { + if ( arr.length == 0 ) return []; + var len = Math.ceil( arr.length / 2 ); + return arr.slice( 0, len ); } //Get the second half of an array, not including the pivot @@ -95,10 +95,10 @@ class ArrayExtensions { // //* the right half - public static function right(arr : Array) : Array { - if (arr.length == 0) return []; - var len = Math.ceil(arr.length / 2); - return arr.slice(len); + public static function right( arr : Array ) : Array { + if ( arr.length == 0 ) return []; + var len = Math.ceil( arr.length / 2 ); + return arr.slice( len ); } //Get the second half of an array including the pivot @@ -111,10 +111,10 @@ class ArrayExtensions { // //* the right half - public static function rightWithPivot(arr : Array) : Array { - if (arr.length == 0) return []; - var len = Math.ceil(arr.length / 2); - return arr.slice(len - 1); + public static function rightWithPivot( arr : Array ) : Array { + if ( arr.length == 0 ) return []; + var len = Math.ceil( arr.length / 2 ); + return arr.slice( len - 1 ); } //Obtain the unique set of elements in an array @@ -129,26 +129,26 @@ 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) { - uniques.push(ele); + if ( isUnique ) { + uniques.push( ele ); } } diff --git a/src/verb/core/Binomial.hx b/src/verb/core/Binomial.hx index 493e60ec..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,19 +68,19 @@ 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)) { - memo.set(n, new IntMap()); + private static function memoize( n, k, val ) { + if ( !memo.exists( n ) ) { + memo.set( n, new IntMap() ); } - memo.get(n).set(k, val); + memo.get( n ).set( k, val ); } } \ No newline at end of file diff --git a/src/verb/core/BoundingBox.hx b/src/verb/core/BoundingBox.hx index 94c0f374..a635442c 100644 --- a/src/verb/core/BoundingBox.hx +++ b/src/verb/core/BoundingBox.hx @@ -21,9 +21,9 @@ class BoundingBox { // //* Points to add, if desired. Otherwise, will not be initialized until add is called. - public function new(pts : Array = null) { - if (pts != null) { - this.addRange(pts); + public function new( pts : Array = null ) { + if ( pts != null ) { + this.addRange( pts ); } } @@ -43,7 +43,7 @@ class BoundingBox { // //* This BoundingBox for chaining - public function fromPoint(pt) { + public function fromPoint( pt ) { return new BoundingBox( [ pt ] ); } @@ -58,19 +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; @@ -87,11 +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; @@ -108,13 +108,13 @@ 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; } - return this.intersects(new BoundingBox([point]), tol); + return this.intersects( new BoundingBox([point]), tol ); } //Determines if two intervals on the real number line intersect @@ -130,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) ; } @@ -151,17 +151,17 @@ class BoundingBox { // //* true if the two bounding boxes intersect, otherwise false - public function intersects(bb : BoundingBox, tol : Float = -1) : Bool { + public function intersects( bb : BoundingBox, tol : Float = -1 ) : Bool { - if (!this.initialized || !bb.initialized) return false; + if ( !this.initialized || !bb.initialized ) return false; var a1 = min , a2 = max , 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; @@ -174,7 +174,7 @@ class BoundingBox { // //* this BoundingBox for chaining - public function clear() : BoundingBox { + public function clear( ) : BoundingBox { this.initialized = false; return this; } @@ -185,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; } @@ -211,9 +211,9 @@ 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; - return Math.abs(this.min[i] - this.max[i]); + public function getAxisLength( i : Int ) : Float { + if ( i < 0 || i > this.dim - 1 ) return 0.0; + return Math.abs( this.min[i] - this.max[i] ); } //Compute the boolean intersection of this with another axis-aligned bounding box. If the two @@ -227,23 +227,23 @@ class BoundingBox { // //* The bounding box formed by the intersection or null if there is no intersection. - public function intersect(bb : BoundingBox, tol : Float) : BoundingBox { + public function intersect( bb : BoundingBox, tol : Float ) : BoundingBox { - if (!this.initialized) return null; + if ( !this.initialized ) return null; var a1 = min , a2 = max , b1 = bb.min , b2 = bb.max; - if (!this.intersects(bb, tol)) return null; + if ( !this.intersects( bb, tol ) ) return null; var maxbb = [] , minbb = []; - for (i in 0...dim) { - maxbb.push(Math.min(a2[i], b2[i])); - minbb.push(Math.max(a1[i], b1[i])); + for ( i in 0...dim ) { + maxbb.push( Math.min( a2[i], b2[i] ) ); + minbb.push( Math.max( a1[i], b1[i] ) ); } return new BoundingBox([minbb, maxbb]); diff --git a/src/verb/core/Data.hx b/src/verb/core/Data.hx index 35ac38c7..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,14 +127,14 @@ 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 { + 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 fc0c4878..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,7 +151,7 @@ class SurfacePoint { this.degen = degen; } - public static function fromUv(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 84b31d7b..1dcab98e 100644 --- a/src/verb/core/KdTree.hx +++ b/src/verb/core/KdTree.hx @@ -21,124 +21,124 @@ 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; - 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], + 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(); + 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]; } } - linearDistance = distanceFunction(linearPoint, node.kdPoint.point); + 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; } } - nearestSearch(bestChild); + 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); + 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,20 +206,20 @@ 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. @@ -232,13 +232,13 @@ class BinaryHeap { } } - 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,25 +248,25 @@ 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; @@ -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 7f59fb5c..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 )); } - 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 ab4ac544..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 )); } - public function boundingBox() { - if (_boundingBox == null) { - _boundingBox = Mesh.makeMeshAabb(_mesh, _faceIndices); + 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 832df48e..1ddd2223 100644 --- a/src/verb/core/LazyPolylineBoundingBoxTree.hx +++ b/src/verb/core/LazyPolylineBoundingBoxTree.hx @@ -9,20 +9,20 @@ 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) { + 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 ); @@ -33,23 +33,23 @@ class LazyPolylineBoundingBoxTree implements IBoundingBoxTree { } - 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 21594fca..916103d3 100644 --- a/src/verb/core/LazySurfaceBoundingBoxTree.hx +++ b/src/verb/core/LazySurfaceBoundingBoxTree.hx @@ -16,63 +16,63 @@ 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; var pivot = (min + max) / 2.0; //* dom * 0.01 * Math.random(); - var srfs = Divide.surfaceSplit(_surface, pivot, _splitV); + 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 )); } - 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 4f1b0cef..d085d4f7 100644 --- a/src/verb/core/Mat.hx +++ b/src/verb/core/Mat.hx @@ -10,15 +10,15 @@ 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; @@ -29,21 +29,21 @@ class Mat { var j = 0; var k = 0; - while (i >= 0) { + while ( i >= 0 ) { foo = new Vector(); bar = x[i]; k = r - 1; - while (k >= 0) { + while ( k >= 0 ) { woo = bar[q - 1] * y[q - 1][k]; j = q - 2; - while (j >= 1) { + 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 x = b.copy( ); var P = LUP.P; var Pi, LUi, LUii, tmp; i = n - 1; - while (i != -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,7 +125,7 @@ class Mat { LUi = LU[i]; j = 0; - while (j < i) { + while ( j < i ) { x[i] -= x[j] * LUi[j]; ++j; } @@ -133,10 +133,10 @@ class Mat { } i = n - 1; - while (i >= 0) { + while ( i >= 0 ) { LUi = LU[i]; j = i + 1; - while (j < n) { + while ( j < n ) { x[i] -= x[j] * LUi[j]; ++j; } @@ -150,26 +150,26 @@ class Mat { // Based on methods from numeric.js - private static function LU(A : Matrix) : LUDecomp { + private static function LU( A : Matrix ) : LUDecomp { var abs = Math.abs; var i, j, k, absAjk, Akk, Ak, Pk, Ai; var max; //copy A - A = [ for (i in 0...A.length) A[i].copy() ]; + 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) { + 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]; @@ -186,22 +186,22 @@ class Mat { Akk = Ak[k]; i = k + 1; - while (i < n) { + while ( i < n ) { A[i][k] /= Akk; ++i; } i = k + 1; - while (i < n) { + while ( i < n ) { Ai = A[i]; j = k + 1; - while (j < n1) { + 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; } @@ -220,7 +220,7 @@ 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 40d060ca..f66c05d9 100644 --- a/src/verb/core/Mesh.hx +++ b/src/verb/core/Mesh.hx @@ -22,16 +22,16 @@ class Mesh { //* a normal vector represented by an array of length 3 // - public static function getTriangleNorm(points : Array, tri : Tri) : Point { + public static function getTriangleNorm( points : Array, tri : Tri ) : Point { var v0 = points[ tri[0] ] , v1 = points[ tri[1] ] , v2 = points[ tri[2] ] - , u = Vec.sub(v1, v0) - , v = Vec.sub(v2, v0) - , n = Vec.cross(u, v); + , u = Vec.sub( v1, v0 ) + , v = Vec.sub( v2, v0 ) + , n = Vec.cross( u, v ); - return Vec.mul(1 / Vec.norm(n), n); + return Vec.mul( 1 / Vec.norm( n ), n ); } @@ -47,14 +47,14 @@ class Mesh { //* a BoundingBox containing the mesh // - public static function makeMeshAabb(mesh : MeshData, faceIndices : Array) : BoundingBox { + public static function makeMeshAabb( mesh : MeshData, faceIndices : Array ) : BoundingBox { var bb = new verb.core.BoundingBox(); - 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] ]); + 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] ] ); } return bb; @@ -73,26 +73,26 @@ class Mesh { //* a point represented by an array of length (dim) // - public static function sortTrianglesOnLongestAxis(bb : BoundingBox, mesh : MeshData, faceIndices : Array) : Array { + 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) { - var tri_min = getMinCoordOnAxis(mesh.points, mesh.faces[ faceIndex ], longAxis); - minCoordFaceMap.push(new Pair(tri_min, faceIndex)); + for ( faceIndex in faceIndices ) { + var tri_min = getMinCoordOnAxis( mesh.points, mesh.faces[ faceIndex ], longAxis ); + 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) { - sortedFaceIndices.push(minCoordFaceMap[i].item1); + for ( i in 0...minCoordFaceMap.length ) { + sortedFaceIndices.push( minCoordFaceMap[i].item1 ); } return sortedFaceIndices; @@ -110,13 +110,13 @@ class Mesh { // //* the minimum coordinate - private static function getMinCoordOnAxis(points : Array, tri : Tri, axis : Int) : Float { + private static function getMinCoordOnAxis( points : Array, tri : Tri, axis : Int ) : Float { 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; @@ -134,17 +134,17 @@ class Mesh { //* a point represented by an array of length 3 // - public static function getTriangleCentroid(points : Array, tri : Tri) : Point { + public static function getTriangleCentroid( points : Array, tri : Tri ) : Point { 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; } @@ -163,7 +163,7 @@ class Mesh { // //* the UV on the face - public static function triangleUVFromPoint(mesh : MeshData, faceIndex : Int, f : Point) : UV { + public static function triangleUVFromPoint( mesh : MeshData, faceIndex : Int, f : Point ) : UV { var tri = mesh.faces[faceIndex]; @@ -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 b6113ce2..e7c4d1f5 100644 --- a/src/verb/core/MeshBoundingBoxTree.hx +++ b/src/verb/core/MeshBoundingBoxTree.hx @@ -12,25 +12,25 @@ 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); + _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 as = Mesh.sortTrianglesOnLongestAxis( _boundingBox, mesh, faceIndices ); + var l = as.left( ); + var r = as.right( ); _children = new Pair, IBoundingBoxTree>( new MeshBoundingBoxTree(mesh, l), @@ -38,23 +38,23 @@ class MeshBoundingBoxTree implements IBoundingBoxTree { ); } - 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 b7b40efe..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); + 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); + 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 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,32 +72,32 @@ 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; - 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"; } + if ( it > 20 ) { throw "Numerical gradient fails"; } x0[i] = x[i] + h; - f1 = f(x0); + f1 = f( x0 ); x0[i] = x[i] - h; - f2 = f(x0); + 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; @@ -105,27 +105,27 @@ class Minimizer { 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 ]); + 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) { + while ( i >= 0 ) { Ai = []; xi = x[i]; var j = n - 1; - while (j >= 3) { + 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 ed54a398..45d69fbe 100644 --- a/src/verb/core/SurfaceBoundingBoxTree.hx +++ b/src/verb/core/SurfaceBoundingBoxTree.hx @@ -13,42 +13,42 @@ 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; + if ( !divisible ) return; 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); + var srfs = Divide.surfaceSplit( _surface, pivot, splitV ); _children = new Pair, IBoundingBoxTree>( new SurfaceBoundingBoxTree( srfs[0], !splitV, knotTolU, knotTolV ), @@ -56,29 +56,29 @@ class SurfaceBoundingBoxTree implements IBoundingBoxTree { } - 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 89bdecc9..3687b36d 100644 --- a/src/verb/core/Trig.hx +++ b/src/verb/core/Trig.hx @@ -10,13 +10,13 @@ using verb.core.Vec; @:expose("core.Trig") class Trig { - 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 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) { - var res = segmentClosestPoint(b, a, c, 0.0, 1.0); - return Vec.dist(b, res.pt); + 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 ); } //Find the closest point on a ray @@ -31,10 +31,10 @@ 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)); + 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 ) ); return proj; } @@ -51,11 +51,11 @@ class Trig { // //* the distance - public static function distToRay(pt, o, r) { - var d = rayClosestPoint(pt, o, r); - var dif = Vec.sub(d, pt); + public static function distToRay( pt, o, r ) { + var d = rayClosestPoint( pt, o, r ); + var dif = Vec.sub( d, pt ); - return Vec.norm(dif); + return Vec.norm( dif ); } @@ -81,13 +81,13 @@ class Trig { // //* Whether the triangle passes the test - public static function threePointsAreFlat(p1, p2, p3, tol) { + public static function threePointsAreFlat( p1, p2, p3, tol ) { //find the area of the triangle without using a square root - var p2mp1 = Vec.sub(p2, p1) - , p3mp1 = Vec.sub(p3, p1) - , norm = Vec.cross(p2mp1, p3mp1) - , area = Vec.dot(norm, norm); + var p2mp1 = Vec.sub( p2, p1 ) + , p3mp1 = Vec.sub( p3, p1 ) + , norm = Vec.cross( p2mp1, p3mp1 ) + , area = Vec.dot( norm, norm ); return area < tol; @@ -107,27 +107,27 @@ class Trig { // //* *Object* with u and pt properties - public static function segmentClosestPoint(pt : Point, segpt0 : Point, segpt1 : Point, u0 : Float, u1 : Float) { + public static function segmentClosestPoint( pt : Point, segpt0 : Point, segpt1 : Point, u0 : Float, u1 : Float ) { - var dif = Vec.sub(segpt1, segpt0) - , l = Vec.norm(dif); + 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); + , r = Vec.mul( 1 / l, dif ) + , o2pt = Vec.sub( pt, o ) + , do2ptr = Vec.dot( o2pt, r ); - if (do2ptr < 0) { + if ( do2ptr < 0 ) { return { u: u0, pt : segpt0 }; - } else if (do2ptr > l) { + } 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 d412f662..1124442e 100644 --- a/src/verb/core/Vec.hx +++ b/src/verb/core/Vec.hx @@ -13,266 +13,266 @@ 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 w = Math.atan2( sina, cosa ); + 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 w = Math.atan2( sina, cosa ); + var s = Vec.dot( n, nab ); return s > 0.0 ? w : 2 * Math.PI - w; } - public static function angleBetweenNormalized2d(a : Array, b : Array) : Float { + 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)); + 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 { + 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 addAllMutate(a : Array>) { + public static function addAllMutate( a : Array> ) { var f = a[0]; - for (i in 1...a.length) - addMutate(f, a[i]); + 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) + 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) + 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) + 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) + 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) + 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 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) { - merged.push(b[bi]); + if ( ai >= a.length ) { + merged.push( b[bi] ); bi++; continue; - } else if (bi >= b.length) { - merged.push(a[ai]); + } else if ( bi >= b.length ) { + merged.push( a[ai] ); ai++; continue; } var diff = a[ai] - b[bi]; - if (Math.abs(diff) < Constants.EPSILON) { - merged.push(a[ai]); + 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]); + merged.push( b[bi] ); bi++; continue; } //thus diff < 0.0 - merged.push(a[ai]); + merged.push( a[ai] ); ai++; } @@ -282,27 +282,27 @@ 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) { - result.push(a[ai]); + 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; } - result.push(a[ai]); + result.push( a[ai] ); ai++; } diff --git a/src/verb/eval/Analyze.hx b/src/verb/eval/Analyze.hx index ddcd3c2d..0250503b 100644 --- a/src/verb/eval/Analyze.hx +++ b/src/verb/eval/Analyze.hx @@ -36,18 +36,18 @@ class Analyze { // //* Array of KnotMultiplicity objects - public static function knotMultiplicities(knots : KnotArray) : Array { + public static function knotMultiplicities( knots : KnotArray ) : Array { 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; @@ -88,9 +88,9 @@ class Analyze { // //* The closest point on the surface, bounded by the parametric range of the surface - public static function rationalSurfaceClosestPoint(surface : NurbsSurfaceData, p : Point) : Point { - var uv = Analyze.rationalSurfaceClosestParam(surface, p); - return Eval.rationalSurfacePoint(surface, uv[0], uv[1]); + public static function rationalSurfaceClosestPoint( surface : NurbsSurfaceData, p : Point ) : Point { + var uv = Analyze.rationalSurfaceClosestParam( surface, p ); + return Eval.rationalSurfacePoint( surface, uv[0], uv[1] ); } //Determine the closest parameters on a NURBS surface to a given point. *This is an experimental method and not hightly reliable.* @@ -104,7 +104,7 @@ class Analyze { // //* The closest parameters on the surface, bounded by the parametric domain of the surface - public static function rationalSurfaceClosestParam(surface : NurbsSurfaceData, p : Point) : UV { + public static function rationalSurfaceClosestParam( surface : NurbsSurfaceData, p : Point ) : UV { //for surfaces, we try to minimize the following: // @@ -155,35 +155,35 @@ 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 //approximate closest point with tessellation - var tess = Tess.rationalSurfaceAdaptive(surface, new AdaptiveRefinementOptions()); + var tess = Tess.rationalSurfaceAdaptive( surface, new AdaptiveRefinementOptions() ); 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)); + 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> { - return Eval.rationalSurfaceDerivatives(surface, uv[0], uv[1], 2); + 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 @@ -197,15 +197,15 @@ class Analyze { var Suv = e[1][1]; var Svu = e[1][1]; - var f = Vec.dot(Su, r); - var g = Vec.dot(Sv, r); + var f = Vec.dot( Su, r ); + var g = Vec.dot( Sv, r ); var k = [-f, -g]; - var J00 = Vec.dot(Su, Su) + Vec.dot(Suu, r); - var J01 = Vec.dot(Su, Sv) + Vec.dot(Suv, r); - var J10 = Vec.dot(Su, Sv) + Vec.dot(Svu, r); - var J11 = Vec.dot(Sv, Sv) + Vec.dot(Svv, r); + var J00 = Vec.dot( Su, Su ) + Vec.dot( Suu, r ); + var J01 = Vec.dot( Su, Sv ) + Vec.dot( Suv, r ); + var J10 = Vec.dot( Su, Sv ) + Vec.dot( Svu, r ); + var J11 = Vec.dot( Sv, Sv ) + Vec.dot( Svv, r ); var J = [ [ J00, J01 ], [ J10, J11 ] ]; @@ -216,21 +216,21 @@ class Analyze { // Su*Sv + Svu * r |Sv|^2 + Svv * r // - var d = Mat.solve(J, k); + var d = Mat.solve( J, k ); - return Vec.add(d, uv); + return Vec.add( d, uv ); } - 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 // // |S(u,v) - p| < e1 - var c1v = Vec.norm(dif); + var c1v = Vec.norm( dif ); // // cosine @@ -243,11 +243,11 @@ class Analyze { // ---------------------- < e2 // |Sv(u,v)| |S(u,v) - P| // - var c2an = Vec.dot(e[1][0], dif); - var c2ad = Vec.norm(e[1][0]) * c1v; + 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 c2bd = Vec.norm(e[0][1]) * c1v; + var c2bn = Vec.dot( e[0][1], dif ); + var c2bd = Vec.norm( e[0][1] ) * c1v; var c2av = c2an / c2ad; var c2bv = c2bn / c2bd; @@ -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; } @@ -305,8 +305,8 @@ 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)); + public static function rationalCurveClosestPoint( curve : NurbsCurveData, p : Point ) : Point { + return Eval.rationalCurvePoint( curve, rationalCurveClosestParam( curve, p ) ); } //Determine the closest parameters on a NURBS curve to a given point. @@ -320,7 +320,7 @@ class Analyze { // //* The closest parameter on the curve, bounded by the parametric domain of the curve - public static function rationalCurveClosestParam(curve : NurbsCurveData, p : Point) : Float { + public static function rationalCurveClosestParam( curve : NurbsCurveData, p : Point ) : Float { // We want to solve: // @@ -355,20 +355,20 @@ class Analyze { var min = Math.POSITIVE_INFINITY; var u = 0.0; - var pts = Tess.rationalCurveRegularSample(curve, curve.controlPoints.length * curve.degree, true); + 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 p0 = pts[i].slice(1); - var p1 = pts[i + 1].slice(1); + var p0 = pts[i].slice( 1 ); + var p1 = pts[i + 1].slice( 1 ); - var proj = Trig.segmentClosestPoint(p, p0, p1, u0, u1); - var d = Vec.norm(Vec.sub(p, proj.pt)); + 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,63 +381,63 @@ 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 { - return Eval.rationalCurveDerivatives(curve, u, 2); + 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); + var f = Vec.dot( e[1], d ); // f' = C"(u) * ( C(u) - p ) + C'(u) * C'(u) - var s0 = Vec.dot(e[2], d) - , s1 = Vec.dot(e[1], e[1]) + var s0 = Vec.dot( e[2], d ) + , s1 = Vec.dot( e[1], e[1] ) , df = s0 + s1; return u - f / df; } - while (i < maxits) { + while ( i < maxits ) { - e = f(cu); - dif = Vec.sub(e[0], p); + e = f( cu ); + dif = Vec.sub( e[0], p ); // |C(u) - p| < e1 - var c1v = Vec.norm(dif); + var c1v = Vec.norm( dif ); //C'(u) * (C(u) - P) // ------------------ < e2 // |C'(u)| |C(u) - P| - var c2n = Vec.dot(e[1], dif); - var c2d = Vec.norm(e[1]) * c1v; + 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 +464,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); + 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 +508,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); + 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,17 +556,17 @@ 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) + 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); - sum += rationalBezierCurveArcLength(cc, param, gaussDegIncrease); + 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,21 +585,21 @@ 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); + tan = Eval.rationalCurveDerivatives( curve, cu, 1 ); - sum += Cvalues[gaussDeg][i] * Vec.norm(tan[1]); + sum += Cvalues[gaussDeg][i] * Vec.norm( tan[1] ); } @@ -680,14 +680,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 629a1767..d75585d9 100644 --- a/src/verb/eval/Check.hx +++ b/src/verb/eval/Check.hx @@ -33,24 +33,24 @@ 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); + return isNonDecreasing( vec ); } //Check if an array of floating point numbers is non-decreasing, although there may be repeats. This is an important @@ -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; @@ -83,19 +83,19 @@ class Check { // //* The original, unmodified data - public static function isValidNurbsCurveData(data : NurbsCurveData) : NurbsCurveData { - if (data.controlPoints == null) throw "Control points array cannot be null!"; + 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.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!"; } @@ -112,26 +112,26 @@ class Check { // //* The original, unmodified data - public static function isValidNurbsSurfaceData(data : NurbsSurfaceData) : NurbsSurfaceData { - if (data.controlPoints == null) throw "Control points array cannot be null!"; + 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.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 fc9deb91..2443fa88 100644 --- a/src/verb/eval/Divide.hx +++ b/src/verb/eval/Divide.hx @@ -24,14 +24,14 @@ 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) { - controlPoints = Mat.transpose(surface.controlPoints); + if ( !useV ) { + controlPoints = Mat.transpose( surface.controlPoints ); knots = surface.knotsU; degree = surface.degreeU; } else { @@ -40,35 +40,35 @@ 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>(); - var s = Eval.knotSpan(degree, u, knots); + var s = Eval.knotSpan( degree, u, knots ); var res : NurbsCurveData = null; - for (cps in controlPoints) { - res = Modify.curveKnotRefine(new NurbsCurveData(degree, knots, cps), knots_to_insert); + 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)); + 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); + var knots0 = res.knots.slice( 0, s + degree + 2 ); + var knots1 = res.knots.slice( s + 1 ); - if (!useV) { - newpts0 = Mat.transpose(newpts0); - newpts1 = Mat.transpose(newpts1); + 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 @@ -82,22 +82,22 @@ class Divide { // //* *Array* two new curves, defined by degree, knots, and control points - public static function curveSplit(curve : NurbsCurveData, u : Float) : Array { + public static function curveSplit( curve : NurbsCurveData, u : Float ) : Array { var degree = curve.degree , controlPoints = curve.controlPoints , knots = curve.knots; - var knots_to_insert = [for (i in 0...degree + 1) u]; - var res = Modify.curveKnotRefine(curve, knots_to_insert); + 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 s = Eval.knotSpan( degree, u, knots ); - var knots0 = res.knots.slice(0, s + degree + 2); - var knots1 = res.knots.slice(s + 1); + 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); + var cpts0 = res.controlPoints.slice( 0, s + 1 ); + var cpts1 = res.controlPoints.slice( s + 1 ); return [ new NurbsCurveData( degree, knots0, cpts0 ), @@ -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 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) + var crvs = Modify.decomposeCurveIntoBeziers( curve ) + , 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,15 +155,15 @@ 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]); + u = Analyze.rationalBezierCurveParamAtArcLength( crvs[i], lc - runsum1, Constants.TOLERANCE, crvlens[i] ); - pts.push(new CurveLengthSample( u, lc )); + pts.push( new CurveLengthSample( u, lc ) ); lc += inc; } @@ -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 48665858..41444018 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -33,8 +33,8 @@ class Eval { // //* a Vector represented by an array of length (dim) - public static function rationalCurveTangent(curve : NurbsCurveData, u : Float) : Array { - var derivs = rationalCurveDerivatives(curve, u, 1); + public static function rationalCurveTangent( curve : NurbsCurveData, u : Float ) : Array { + var derivs = rationalCurveDerivatives( curve, u, 1 ); return derivs[1]; } @@ -50,9 +50,9 @@ class Eval { // //* a Vector represented by an array of length (dim) - 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]); + 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] ); } //Compute the derivatives at a point on a NURBS surface @@ -68,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) { - SKL.push(new Array>()); + 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) { - Vec.subMulMutate(v, 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) { - Vec.subMulMutate(v, 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) { - Vec.addMulMutate(v2, 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] ); } - Vec.subMulMutate(v, Binomial.get(k, i), v2); + Vec.subMulMutate( v, Binomial.get( k, i ), v2 ); } - Vec.mulMutate(1 / wders[0][0], v); - SKL[k].push(v); //demogenize + Vec.mulMutate( 1 / wders[0][0], v ); + SKL[k].push( v ); //demogenize } } @@ -126,8 +126,8 @@ class Eval { // //* a point represented by an array of length (dim) - public static function rationalSurfacePoint(surface : NurbsSurfaceData, u : Float, v : Float) : Point { - return dehomogenize(surfacePoint(surface, u, v)); + public static function rationalSurfacePoint( surface : NurbsSurfaceData, u : Float, v : Float ) : Point { + return dehomogenize( surfacePoint( surface, u, v ) ); } //Determine the derivatives of a NURBS curve at a given parameter @@ -142,24 +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) + var ders = curveDerivatives( curve, u, numDerivs ) + , Aders = rational1d( ders ) + , wders = weight1d( ders ) , k = 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) { - Vec.subMulMutate(v, 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] ); } - Vec.mulMutate(1 / wders[0], v); - CK.push(v); //demogenize + Vec.mulMutate( 1 / wders[0], v ); + CK.push( v ); //demogenize } return CK; @@ -180,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 @@ -197,12 +197,12 @@ class Eval { // //* a 2d jagged array representing the derivatives - u derivatives increase by row, v by column - public static function surfaceDerivatives(surface : NurbsSurfaceData, u : Float, v : Float, numDerivs : Int) : Array> { + public static function surfaceDerivatives( surface : NurbsSurfaceData, u : Float, v : Float, numDerivs : Int ) : Array> { var n = surface.knotsU.length - surface.degreeU - 2 , m = surface.knotsV.length - surface.degreeV - 2; - return surfaceDerivativesGivenNM(n, m, surface, u, v, numDerivs); + return surfaceDerivativesGivenNM( n, m, surface, u, v, numDerivs ); } @@ -221,12 +221,12 @@ 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> { + public static function surfaceDerivativesGivenNM( n : Int, + m : Int, + surface : NurbsSurfaceData, + u : Float, + v : Float, + numDerivs : Int ) : Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -234,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'; } @@ -243,31 +243,31 @@ class Eval { var dim = controlPoints[0][0].length , du = numDerivs < degreeU ? numDerivs : degreeU , dv = numDerivs < degreeV ? numDerivs : degreeV - , 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) + , 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 ) , dd = 0; - for (k in 0...du + 1) { - for (s in 0...degreeV + 1) { - temp[s] = Vec.zeros1d(dim); + 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], 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) { - SKL[k][l] = Vec.zeros1d(dim); + for ( l in 0...dd + 1 ) { + SKL[k][l] = Vec.zeros1d( dim ); - for (s in 0...degreeV + 1) { - Vec.addMulMutate(SKL[k][l], vders[l][s], temp[s]); + for ( s in 0...degreeV + 1 ) { + Vec.addMulMutate( SKL[k][l], vders[l][s], temp[s] ); } } } @@ -287,12 +287,12 @@ 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; - return surfacePointGivenNM(n, m, surface, u, v); + return surfacePointGivenNM( n, m, surface, u, v ); } @@ -311,7 +311,7 @@ class Eval { // //* a point represented by an array of length (dim) - public static function surfacePointGivenNM(n : Int, m : Int, surface : NurbsSurfaceData, u : Float, v : Float) : Point { + public static function surfacePointGivenNM( n : Int, m : Int, surface : NurbsSurfaceData, u : Float, v : Float ) : Point { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -319,34 +319,34 @@ 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'; } var dim = controlPoints[0][0].length - , knotSpan_index_u = knotSpanGivenN(n, degreeU, u, knotsU) - , knotSpan_index_v = knotSpanGivenN(m, degreeV, v, knotsV) - , u_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_u, u, degreeU, knotsU) - , v_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_v, v, degreeV, knotsV) + , knotSpan_index_u = knotSpanGivenN( n, degreeU, u, knotsU ) + , knotSpan_index_v = knotSpanGivenN( m, degreeV, v, knotsV ) + , u_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_u, u, degreeU, knotsU ) + , v_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_v, v, degreeV, knotsV ) , uind = knotSpan_index_u - degreeU , vind = knotSpan_index_v - , position = Vec.zeros1d(dim) - , temp = Vec.zeros1d(dim); + , position = Vec.zeros1d( dim ) + , temp = Vec.zeros1d( dim ); - for (l in 0...degreeV + 1) { + for ( l in 0...degreeV + 1 ) { - temp = Vec.zeros1d(dim); + temp = Vec.zeros1d( dim ); vind = knotSpan_index_v - degreeV + l; //sample u isoline - for (k in 0...degreeU + 1) { - Vec.addMulMutate(temp, 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 - Vec.addMulMutate(position, v_basis_vals[l], temp); + Vec.addMulMutate( position, v_basis_vals[l], temp ); } return position; @@ -366,57 +366,57 @@ class Eval { // //* 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) { + public static function rationalSurfaceRegularSampleDerivatives( surface : NurbsSurfaceData, divsU : Int, divsV : Int, numDerivs : Int ) { - var allders = surfaceRegularSampleDerivatives(surface, divsU, divsV, numDerivs); + 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) { + for ( i in 0...divsU1 ) { var rowders = []; - allratders.push(rowders); + allratders.push( rowders ); - for (j in 0...divsV1) { + for ( j in 0...divsV1 ) { var ders = allders[i][j] - , Aders = rational2d(ders) - , wders = weight2d(ders) + , Aders = rational2d( ders ) + , wders = weight2d( ders ) , SKL = new Array>>() , dim = Aders[0][0].length; - for (k in 0...numDerivs1) { - SKL.push(new Array>()); + for ( k in 0...numDerivs1 ) { + SKL.push( new Array>() ); - for (l in 0...numDerivs1 - k) { + 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 ( 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]); + 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) { - Vec.addMulMutate(v2, 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] ); } - Vec.subMulMutate(v, Binomial.get(k, i), v2); + Vec.subMulMutate( v, Binomial.get( k, i ), v2 ); } - Vec.mulMutate(1 / wders[0][0], v); - SKL[k].push(v); //demogenize + Vec.mulMutate( 1 / wders[0][0], v ); + SKL[k].push( v ); //demogenize } } - rowders.push(SKL); + rowders.push( SKL ); } } @@ -436,7 +436,7 @@ class Eval { // //* 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) { + public static function surfaceRegularSampleDerivatives( surface : NurbsSurfaceData, divsU : Int, divsV : Int, numDerivs : Int ) { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -445,24 +445,24 @@ class Eval { , 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) + , 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) + , knotSpansBasesV = regularlySpacedDerivativeBasisFunctions( degreeV, knotsV, divsV ) , knotSpansV = knotSpansBasesV.item0 , basesV = knotSpansBasesV.item1 , pts = [] , divsU1 = divsU + 1 , divsV1 = divsV + 1; - for (i in 0...divsU1) { + for ( i in 0...divsU1 ) { var ptsi = []; - pts.push(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)); + for ( j in 0...divsV1 ) { + ptsi.push( surfaceDerivativesGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim, numDerivs ) ); } } @@ -482,8 +482,8 @@ class Eval { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function rationalSurfaceRegularSamplePoints(surface : NurbsSurfaceData, divsU : Int, divsV : Int) : Array> { - return dehomogenize2d(surfaceRegularSamplePoints(surface, divsU, divsV)); + public static function rationalSurfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + return dehomogenize2d( surfaceRegularSamplePoints( surface, divsU, divsV ) ); } // Compute a regularly spaced grid of points on a non-uniform, non-rational, B spline surface. Generally, this algorithm @@ -499,7 +499,7 @@ class Eval { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function surfaceRegularSamplePoints(surface : NurbsSurfaceData, divsU : Int, divsV : Int) : Array> { + public static function surfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -508,157 +508,157 @@ class Eval { , knotsV = surface.knotsV; var dim = controlPoints[0][0].length - , spanU = (knotsU.last() - knotsU[0]) / divsU - , spanV = (knotsV.last() - knotsV[0]) / divsV - , knotSpansBasesU = regularlySpacedBasisFunctions(degreeU, knotsU, divsU) + , spanU = (knotsU.last( ) - knotsU[0]) / divsU + , spanV = (knotsV.last( ) - knotsV[0]) / divsV + , knotSpansBasesU = regularlySpacedBasisFunctions( degreeU, knotsU, divsU ) , knotSpansU = knotSpansBasesU.item0 , basesU = knotSpansBasesU.item1 - , knotSpansBasesV = regularlySpacedBasisFunctions(degreeV, knotsV, divsV) + , knotSpansBasesV = regularlySpacedBasisFunctions( degreeV, knotsV, divsV ) , knotSpansV = knotSpansBasesV.item0 , basesV = knotSpansBasesV.item1 , pts = [] , divsU1 = divsU + 1 , divsV1 = divsV + 1; - for (i in 0...divsU1) { + for ( i in 0...divsU1 ) { var ptsi = []; - pts.push(ptsi); + pts.push( ptsi ); - for (j in 0...divsV1) { - ptsi.push(surfacePointGivenBasesKnotSpans(degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim)); + for ( j in 0...divsV1 ) { + ptsi.push( surfacePointGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim ) ); } } return pts; } - public static function surfaceRegularSamplePoints2(surface : NurbsSurfaceData, divsU : Int, divsV : Int) : Array> { + public static function surfaceRegularSamplePoints2( 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; + var t = (surface.knotsU.last( ) - surface.knotsU[0]) / divsU; - for (i in 0...divsU) { - var iso = Make.surfaceIsocurve(surface, u, true); - pts.push(rationalCurveRegularSamplePoints(iso, divsV)); + for ( i in 0...divsU ) { + var iso = Make.surfaceIsocurve( surface, u, true ); + pts.push( rationalCurveRegularSamplePoints( iso, divsV ) ); u += t; } return pts; } - private static function regularlySpacedBasisFunctions(degree : Int, knots : KnotArray, divs : Int) : Pair, Array>> { + private 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 span : Float = (knots.last( ) - knots[0]) / divs; var bases = []; var knotspans = []; var u = knots[0]; - var knotIndex = knotSpanGivenN(n, degree, u, knots); + 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)); + 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) { + 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 span : Float = (knots.last( ) - knots[0]) / divs; var bases = []; var knotspans = []; var u = knots[0]; - var knotIndex = knotSpanGivenN(n, degree, u, knots); + 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)); + 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 ); } - private static function surfacePointGivenBasesKnotSpans(degreeU : Int, - degreeV : Int, - controlPoints : Array>, - knotSpanU : Int, - knotSpanV : Int, - basesU : Array, - basesV : Array, - dim : Int) : Point { + private 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) + var position = Vec.zeros1d( dim ) , temp : Array; // could be precomputed var uind = knotSpanU - degreeU; var vind = knotSpanV - degreeV; - for (l in 0...degreeV + 1) { + for ( l in 0...degreeV + 1 ) { - temp = Vec.zeros1d(dim); + temp = Vec.zeros1d( dim ); - for (k in 0...degreeU + 1) { - Vec.addMulMutate(temp, basesU[k], controlPoints[uind + k][vind]); + for ( k in 0...degreeU + 1 ) { + Vec.addMulMutate( temp, basesU[k], controlPoints[uind + k][vind] ); } vind++; - Vec.addMulMutate(position, basesV[l], temp); + 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) { + 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) + , 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 ( 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]); + 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 ( 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]); + for ( s in 0...degreeV + 1 ) { + Vec.addMulMutate( SKL[k][l], basesV[l][s], temp[s] ); } } } @@ -678,10 +678,10 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curveDerivatives(crv : NurbsCurveData, u : Float, numDerivs : Int) : Array { + 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 ); } @@ -698,27 +698,27 @@ class Eval { // //* a point represented by an array of length (dim) - public static function curveDerivativesGivenN(n : Int, curve : NurbsCurveData, u : Float, numDerivs : Int) : Array { + public static function curveDerivativesGivenN( n : Int, curve : NurbsCurveData, u : Float, numDerivs : Int ) : Array { var degree = curve.degree , controlPoints = curve.controlPoints , knots = curve.knots; - if (!areValidRelations(degree, controlPoints.length, knots.length)) { + if ( !areValidRelations( degree, controlPoints.length, knots.length ) ) { throw 'Invalid relations between control points, knot vector, and n'; } var dim = controlPoints[0].length , du = numDerivs < degree ? numDerivs : degree - , CK = Vec.zeros2d(du + 1, dim) - , knotSpan_index = knotSpanGivenN(n, degree, u, knots) - , nders = derivativeBasisFunctionsGivenNI(knotSpan_index, u, degree, du, knots) + , CK = Vec.zeros2d( du + 1, dim ) + , knotSpan_index = knotSpanGivenN( n, degree, u, knots ) + , nders = derivativeBasisFunctionsGivenNI( knotSpan_index, u, degree, du, knots ) , k = 0 , j = 0; - for (k in 0...du + 1) { - for (j in 0...degree + 1) { - Vec.addMulMutate(CK[k], 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; @@ -735,9 +735,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) @@ -753,7 +753,7 @@ class Eval { // //* whether the values are correct - public static function areValidRelations(degree : Int, num_controlPoints : Int, knots_length : Int) : Bool { + public static function areValidRelations( degree : Int, num_controlPoints : Int, knots_length : Int ) : Bool { return num_controlPoints + degree + 1 - knots_length == 0; } @@ -770,23 +770,23 @@ 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; - if (!areValidRelations(degree, controlPoints.length, knots.length)) { + if ( !areValidRelations( degree, controlPoints.length, knots.length ) ) { throw 'Invalid relations between control points, knot Array, and n'; return null; } - var knotSpan_index = knotSpanGivenN(n, degree, u, knots); - var basis_values = basisFunctionsGivenKnotSpanIndex(knotSpan_index, u, degree, knots); - var position = Vec.zeros1d(controlPoints[0].length); + var knotSpan_index = knotSpanGivenN( n, degree, u, knots ); + var basis_values = basisFunctionsGivenKnotSpanIndex( knotSpan_index, u, degree, knots ); + var position = Vec.zeros1d( controlPoints[0].length ); - for (j in 0...degree + 1) { - Vec.addMulMutate(position, 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; @@ -805,12 +805,12 @@ class Eval { // //* a point represented by an array of length (dim) - public static function volumePoint(volume : VolumeData, u : Float, v : Float, w : Float) : Point { + public static function volumePoint( volume : VolumeData, u : Float, v : Float, w : Float ) : Point { var n = volume.knotsU.length - volume.degreeU - 2 , m = volume.knotsV.length - volume.degreeV - 2 , l = volume.knotsW.length - volume.degreeW - 2; - return volumePointGivenNML(volume, n, m, l, u, v, w); + return volumePointGivenNML( volume, n, m, l, u, v, w ); } //Compute a point in a non-uniform, non-rational B spline volume @@ -826,17 +826,17 @@ class Eval { // //* a point represented by an array of length (dim) - public static function volumePointGivenNML(volume : VolumeData, - n : Int, - m : Int, - l : Int, - u : Float, - v : Float, - 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)) { + public static function volumePointGivenNML( volume : VolumeData, + n : Int, + m : Int, + l : Int, + u : Float, + v : Float, + 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 ) ) { throw 'Invalid relations between control points and knot vector'; } @@ -849,37 +849,37 @@ class Eval { , knotsW = volume.knotsW; var dim = controlPoints[0][0][0].length - , knotSpan_index_u = knotSpanGivenN(n, degreeU, u, knotsU) - , knotSpan_index_v = knotSpanGivenN(m, degreeV, v, knotsV) - , knotSpan_index_w = knotSpanGivenN(l, degreeW, w, knotsW) - , u_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_u, u, degreeU, knotsU) - , v_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_v, v, degreeV, knotsV) - , w_basis_vals = basisFunctionsGivenKnotSpanIndex(knotSpan_index_w, w, degreeW, knotsW) + , knotSpan_index_u = knotSpanGivenN( n, degreeU, u, knotsU ) + , knotSpan_index_v = knotSpanGivenN( m, degreeV, v, knotsV ) + , knotSpan_index_w = knotSpanGivenN( l, degreeW, w, knotsW ) + , u_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_u, u, degreeU, knotsU ) + , v_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_v, v, degreeV, knotsV ) + , w_basis_vals = basisFunctionsGivenKnotSpanIndex( knotSpan_index_w, w, degreeW, knotsW ) , uind = knotSpan_index_u - degreeU - , position = Vec.zeros1d(dim) - , temp = Vec.zeros1d(dim) - , temp2 = Vec.zeros1d(dim); + , position = Vec.zeros1d( dim ) + , temp = Vec.zeros1d( dim ) + , temp2 = Vec.zeros1d( dim ); - for (i in 0...degreeW + 1) { + for ( i in 0...degreeW + 1 ) { - temp2 = Vec.zeros1d(dim); + 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); + temp = Vec.zeros1d( dim ); var vind = knotSpan_index_v - degreeV + j; - for (k in 0...degreeU + 1) { - Vec.addMulMutate(temp, 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 - Vec.addMulMutate(temp2, v_basis_vals[j], temp); + Vec.addMulMutate( temp2, v_basis_vals[j], temp ); } //add weighted contribution from uv isosurfaces - Vec.addMulMutate(position, w_basis_vals[i], temp2); + Vec.addMulMutate( position, w_basis_vals[i], temp2 ); } return position; @@ -897,12 +897,12 @@ 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> { - var knotSpan_index = knotSpan(degree, u, knots) + 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; - return derivativeBasisFunctionsGivenNI(knotSpan_index, u, degree, n, knots); + return derivativeBasisFunctionsGivenNI( knotSpan_index, u, degree, n, knots ); } // Compute the non-vanishing basis functions and their derivatives @@ -920,22 +920,22 @@ 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(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) + 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 , temp = 0.0; ndu[0][0] = 1.0; - for (j in 1...p + 1) { + 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) { + for ( r in 0...j ) { ndu[j][r] = right[r + 1] + left[j - r]; temp = ndu[r][j - 1] / ndu[j][r]; @@ -946,8 +946,8 @@ class Eval { ndu[j][j] = saved; } - var ders = Vec.zeros2d(n + 1, p + 1) - , a = Vec.zeros2d(2, 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 @@ -956,43 +956,43 @@ class Eval { , j1 : Int = 0 , j2 : Int = 0; - for (j in 0...p + 1) { + 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) { + 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) { + 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]; } - if (r <= pk) { + if ( r <= pk ) { a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r]; d += a[s2][k] * ndu[r][pk]; } @@ -1006,8 +1006,8 @@ 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); @@ -1030,9 +1030,9 @@ class Eval { //* list of non-vanishing basis functions // - 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); + 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 ); } //Compute the non-vanishing basis functions @@ -1050,24 +1050,24 @@ class Eval { //* list of non-vanishing basis functions // - public static function basisFunctionsGivenKnotSpanIndex(knotSpan_index : Int, - 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); + public static function basisFunctionsGivenKnotSpanIndex( knotSpan_index : Int, + 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 ); var saved : Float = 0; var temp : Float = 0; basisFunctions[0] = 1.0; - for (j in 1...degree + 1) { + 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) { + 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; @@ -1092,8 +1092,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 @@ -1111,27 +1111,27 @@ 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); + , 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 { low = mid; } - mid = Math.floor((low + high) / 2); + mid = Math.floor( (low + high) / 2 ); } return mid; @@ -1147,15 +1147,15 @@ class Eval { // //* a point represented by an array pi with length (dim) - public static function dehomogenize(homoPoint : Point) : Point { + public static function dehomogenize( homoPoint : Point ) : Point { var dim = homoPoint.length , point = [] , wt = homoPoint[dim - 1] , l = homoPoint.length - 1; - for (i in 0...l) { - point.push(homoPoint[i] / wt); + for ( i in 0...l ) { + point.push( homoPoint[i] / wt ); } return point; @@ -1172,9 +1172,9 @@ class Eval { // //* array of points represented by an array (wi*pi) with length (dim) - public static function rational1d(homoPoints : Array) : Array { + 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 @@ -1188,8 +1188,8 @@ 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); + public static function rational2d( homoPoints : Array> ) : Array> { + return homoPoints.map( rational1d ); } //Obtain the weight from a collection of points in homogeneous space, assuming all @@ -1203,9 +1203,9 @@ class Eval { // //* a point represented by an array pi with length (dim) - public static function weight1d(homoPoints : Array) : Array { + 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 @@ -1219,8 +1219,8 @@ 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); + public static function weight2d( homoPoints : Array> ) : Array> { + return homoPoints.map( weight1d ); } //Dehomogenize an array of points @@ -1233,8 +1233,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 @@ -1247,8 +1247,8 @@ class Eval { // //* array of arrays of points, each of length dim - public static function dehomogenize2d(homoPoints : Array>) : Array> { - return homoPoints.map(dehomogenize1d); + public static function dehomogenize2d( homoPoints : Array> ) : Array> { + return homoPoints.map( dehomogenize1d ); } //Transform a 1d array of points into their homogeneous equivalents @@ -1264,29 +1264,29 @@ 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 , homo_controlPoints = new Array() , wt : Float = 0.0 , ref_pt = new Point() - , weights = weights != null ? weights : Vec.rep(controlPoints.length, 1.0); + , 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) { - pt.push(ref_pt[k] * wt); + 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; @@ -1304,14 +1304,14 @@ class Eval { //i the ith control point weight and pi is the ith control point, the size is // (m x n x dim+1) - public static function homogenize2d(controlPoints : Array>, - weights : Array> = null) : Array> { + public static function homogenize2d( controlPoints : 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 f92bac55..e2d2f74d 100644 --- a/src/verb/eval/Intersect.hx +++ b/src/verb/eval/Intersect.hx @@ -46,26 +46,26 @@ 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); - var tess2 = Tess.rationalSurfaceAdaptive(surface1); + var tess1 = Tess.rationalSurfaceAdaptive( surface0 ); + var tess2 = Tess.rationalSurfaceAdaptive( surface1 ); // 2) intersect the two meshes, yielding a list of polylines - var resApprox = Intersect.meshes(tess1, tess2); + 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) { - return Intersect.surfacesAtPointWithEstimate(surface0, surface1, inter.uv0, inter.uv1, tol); - }); - }); + 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; @@ -94,61 +94,61 @@ class Intersect { do { // 1) eval normals, pts on respective surfaces (p, q, pn, qn) - pds = Eval.rationalSurfaceDerivatives(surface0, uv1[0], uv1[1], 1); + pds = Eval.rationalSurfaceDerivatives( surface0, uv1[0], uv1[1], 1 ); p = pds[0][0]; pu = pds[1][0]; pv = pds[0][1]; - pn = Vec.normalized(Vec.cross(pu, pv)); - pd = Vec.dot(pn, p); + pn = Vec.normalized( Vec.cross( pu, pv ) ); + pd = Vec.dot( pn, p ); - qds = Eval.rationalSurfaceDerivatives(surface1, uv2[0], uv2[1], 1); + qds = Eval.rationalSurfaceDerivatives( surface1, uv2[0], uv2[1], 1 ); q = qds[0][0]; qu = qds[1][0]; qv = qds[0][1]; - qn = Vec.normalized(Vec.cross(qu, qv)); - qd = Vec.dot(qn, q); + qn = Vec.normalized( Vec.cross( qu, qv ) ); + 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; } // 2) construct plane perp to both that passes through p (fn) - var fn = Vec.normalized(Vec.cross(pn, qn)); - var fd = Vec.dot(fn, p); + var fn = Vec.normalized( Vec.cross( pn, qn ) ); + var fd = Vec.dot( fn, p ); // 3) x = intersection of all 3 planes - var x = Intersect.threePlanes(pn, pd, qn, qd, fn, fd); + 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) - var pdif = Vec.sub(x, p); - var qdif = Vec.sub(x, q); + var pdif = Vec.sub( x, p ); + var qdif = Vec.sub( x, q ); - var rw = Vec.cross(pu, pn); - var rt = Vec.cross(pv, pn); + var rw = Vec.cross( pu, pn ); + var rt = Vec.cross( pv, pn ); - var su = Vec.cross(qu, qn); - var sv = Vec.cross(qv, qn); + var su = Vec.cross( qu, qn ); + var sv = Vec.cross( qv, qn ); - var dw = Vec.dot(rt, pdif) / Vec.dot(rt, pu); - var dt = Vec.dot(rw, pdif) / Vec.dot(rw, pv); + var dw = Vec.dot( rt, pdif ) / Vec.dot( rt, pu ); + var dt = Vec.dot( rw, pdif ) / Vec.dot( rw, pv ); - var du = Vec.dot(sv, qdif) / Vec.dot(sv, qu); - var dv = Vec.dot(su, qdif) / Vec.dot(su, qv); + var du = Vec.dot( sv, qdif ) / Vec.dot( sv, qu ); + var dv = Vec.dot( su, qdif ) / Vec.dot( su, qv ); - uv1 = Vec.add([dw, dt], uv1); - uv2 = Vec.add([du, dv], uv2); + uv1 = Vec.add( [dw, dt], uv1 ); + uv2 = Vec.add( [du, dv], uv2 ); //repeat its++; - } while (its < maxits); + } while ( its < maxits ); return new SurfaceSurfaceIntersectionPoint(uv1, uv2, p, dist); } @@ -166,47 +166,47 @@ class Intersect { // //* array of array of MeshIntersectionPoints - public static function meshes(mesh0 : MeshData, - mesh1 : MeshData, - bbtree0 : IBoundingBoxTree = null, - bbtree1 : IBoundingBoxTree = null) : Array> { + public static function meshes( mesh0 : MeshData, + mesh1 : MeshData, + 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); + var bbints = Intersect.boundingBoxTrees( bbtree0, bbtree1, 0 ); //get the segments of the intersection crv with uvs - var segments = bbints.map(function(ids : Pair) { - return Intersect.triangles(mesh0, ids.item0, mesh1, ids.item1); - }).filter(function(x) { + var segments = bbints.map( function( ids : Pair ) { + return Intersect.triangles( mesh0, ids.item0, mesh1, ids.item1 ); + } ).filter( function( x ) { return x != null; - }).filter(function(x) { - return Vec.distSquared(x.min.point, x.max.point) > Constants.EPSILON; - }).unique(function(a, b) { + } ).filter( function( x ) { + return Vec.distSquared( x.min.point, x.max.point ) > Constants.EPSILON; + } ).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 // these computations - var s1 = Vec.sub(a.min.uv0, b.min.uv0); - var d1 = Vec.dot(s1, s1); + var s1 = Vec.sub( a.min.uv0, b.min.uv0 ); + var d1 = Vec.dot( s1, s1 ); - var s2 = Vec.sub(a.max.uv0, b.max.uv0); - var d2 = Vec.dot(s2, s2); + var s2 = Vec.sub( a.max.uv0, b.max.uv0 ); + var d2 = Vec.dot( s2, s2 ); - var s3 = Vec.sub(a.min.uv0, b.max.uv0); - var d3 = Vec.dot(s3, s3); + var s3 = Vec.sub( a.min.uv0, b.max.uv0 ); + var d3 = Vec.dot( s3, s3 ); - var s4 = Vec.sub(a.max.uv0, b.min.uv0); - var d4 = Vec.dot(s4, s4); + var s4 = Vec.sub( a.max.uv0, b.min.uv0 ); + var d4 = Vec.dot( s4, s4 ); return ( d1 < Constants.EPSILON && d2 < Constants.EPSILON ) || ( d3 < Constants.EPSILON && d4 < Constants.EPSILON ); - }); + } ); - return makeMeshIntersectionPolylines(segments); + return makeMeshIntersectionPolylines( segments ); } //Slice a mesh by repeated planar intersections yielding a sequence of polylines. Each plane @@ -224,9 +224,9 @@ class Intersect { //* array of array of array of MeshIntersectionPoints - corresponding to the collection of polylines formed with // each slice - public static function meshSlices(mesh : MeshData, min : Float, max : Float, step : Float) : Array>> { + 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]; @@ -234,16 +234,16 @@ class Intersect { var x1 = bb.max[0]; var y1 = bb.max[1]; - var span = Vec.span(min, max, step); + var span = Vec.span( min, max, step ); var slices = []; - for (z in span) { + 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)); + slices.push( Intersect.meshes( mesh, plane, bbtree ) ); } return slices; @@ -259,46 +259,46 @@ class Intersect { // //* array of array of MeshIntersectionPoint - public static function makeMeshIntersectionPolylines(segments : Array>) : Array> { + 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; } //construct a tree for fast lookup - var tree = kdTreeFromSegments(segments); + var tree = kdTreeFromSegments( segments ); //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); + 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,27 +327,27 @@ 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); - pls.push(pl); + 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(); - freeEnds.push(e); + 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; @@ -414,43 +414,43 @@ 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 { + public static function curveAndSurface( curve : NurbsCurveData, + 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); + 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 Vec.distSquared(x.curvePoint, x.surfacePoint) < tol * tol; - }).unique(function(a, b) { - return Math.abs(a.u - b.u) < 0.5 * tol; - }); + 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; + } ); } //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]) - , p2 = Eval.rationalSurfacePoint(surface, x[1], x[2]) - , p1_p2 = Vec.sub(p1, p2); + 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 ); - 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); + var dc = Eval.rationalCurveDerivatives( curve, x[0], 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 @@ -532,29 +532,29 @@ class Intersect { // //* an array of PolylineMeshIntersection object - public static function polylineAndMesh(polyline : PolylineData, - mesh : MeshData, - tol : Float) : Array { + public static function polylineAndMesh( polyline : PolylineData, + mesh : MeshData, + tol : Float ) : Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline ), - new LazyMeshBoundingBoxTree( mesh ), tol); + new LazyMeshBoundingBoxTree( mesh ), tol ); var finalResults = []; - for (event in res) { + for ( event in res ) { var polid = event.item0; var faceid = event.item1; - var inter = Intersect.segmentWithTriangle(polyline.points[polid], polyline.points[polid + 1], mesh.points, mesh.faces[ faceid ]); - if (inter == null) continue; + var inter = Intersect.segmentWithTriangle( polyline.points[polid], polyline.points[polid + 1], mesh.points, mesh.faces[ faceid ] ); + 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 ) ); } @@ -574,66 +574,66 @@ 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) + private static function boundingBoxTrees( ai : IBoundingBoxTree, bi : IBoundingBoxTree, tol : Float = 1e-9 ) : 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.item1 ); - atrees.push(a); - btrees.push(bs.item0); + 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.item1 ); + btrees.push( b ); - atrees.push(as.item0); - 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.item1 ); - atrees.push(as.item1); - btrees.push(bs.item0); + atrees.push( as.item1 ); + btrees.push( bs.item0 ); - atrees.push(as.item0); - btrees.push(bs.item1); + atrees.push( as.item0 ); + btrees.push( bs.item1 ); - atrees.push(as.item0); - btrees.push(bs.item0); + atrees.push( as.item0 ); + btrees.push( bs.item0 ); } @@ -652,19 +652,19 @@ class Intersect { // //* the intersections - public static function curves(curve1 : NurbsCurveData, curve2 : NurbsCurveData, tolerance : Float) : Array { + public static function curves( curve1 : NurbsCurveData, curve2 : NurbsCurveData, tolerance : Float ) : Array { var ints = Intersect.boundingBoxTrees( 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 Vec.distSquared(x.point0, x.point1) < tolerance; - }).unique(function(a, b) { - return Math.abs(a.u0 - b.u0) < tolerance * 5; - }); + 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 Vec.distSquared( x.point0, x.point1 ) < tolerance; + } ).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, @@ -682,17 +682,17 @@ class Intersect { // //* array of CurveCurveIntersection objects - private static function curvesWithEstimate(curve0 : NurbsCurveData, - 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); - - return Vec.dot(p1_p2, p1_p2); + private static function curvesWithEstimate( curve0 : NurbsCurveData, + 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 ); + + return Vec.dot( p1_p2, p1_p2 ); } // 2 params @@ -708,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 dc0 = Eval.rationalCurveDerivatives(curve0, x[0], 1) - , dc1 = Eval.rationalCurveDerivatives(curve1, x[1], 1); + 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 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 sol_obj = Minimizer.uncmin( objective, [u0, u1], tolerance * tolerance, grad ); var u1 = sol_obj.solution[0] , 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); } @@ -745,32 +745,32 @@ 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]; // 0) get the plane rep of the two triangles - var n0 = Mesh.getTriangleNorm(mesh0.points, tri0); - var n1 = Mesh.getTriangleNorm(mesh1.points, tri1); + var n0 = Mesh.getTriangleNorm( mesh0.points, tri0 ); + var n1 = Mesh.getTriangleNorm( mesh1.points, tri1 ); var o0 = mesh0.points[ tri0[0] ]; 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; + var clip1 = clipRayInCoplanarTriangle( ray, mesh0, faceIndex0 ); + if ( clip1 == null ) return null; // 3) clip the ray within tri1 - var clip2 = clipRayInCoplanarTriangle(ray, mesh1, faceIndex1); - if (clip2 == null) return null; + var clip2 = clipRayInCoplanarTriangle( ray, mesh1, faceIndex1 ); + 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 ), @@ -778,29 +778,29 @@ class Intersect { } - 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]) ] - , 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); + , 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 ); // 1) for each tri ray, if intersects and in segment interval, store minU, maxU var minU : CurveTriPoint = null; 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); + var res = Intersect.rays( o0, d0, ray.origin, ray.dir ); - if (res == null) { + if ( res == null ) { continue; } @@ -808,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; } @@ -829,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) { + if ( clip2.min.u > clip1.max.u + Constants.EPSILON + || clip1.min.u > clip2.max.u + Constants.EPSILON ) { return null; } @@ -846,19 +846,19 @@ class Intersect { 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); + res.min.uv1 = Mesh.triangleUVFromPoint( mesh2, faceIndex2, min.item0.point ); } else { - res.min.uv0 = Mesh.triangleUVFromPoint(mesh1, faceIndex1, min.item0.point); + res.min.uv0 = Mesh.triangleUVFromPoint( mesh1, faceIndex1, min.item0.point ); 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); + res.max.uv1 = Mesh.triangleUVFromPoint( mesh2, faceIndex2, max.item0.point ); } else { - res.max.uv0 = Mesh.triangleUVFromPoint(mesh1, faceIndex1, max.item0.point); + res.max.uv0 = Mesh.triangleUVFromPoint( mesh1, faceIndex1, max.item0.point ); res.max.uv1 = max.item0.uv; } @@ -878,36 +878,36 @@ 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; - var mi = Math.abs(d[0]); - var m1 = Math.abs(d[1]); - var m2 = Math.abs(d[2]); + var mi = Math.abs( d[0] ); + 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]; @@ -920,8 +920,8 @@ class Intersect { } //n dot X = d - var d1 = -Vec.dot(origin0, normal0); - var d2 = -Vec.dot(origin1, normal1); + var d1 = -Vec.dot( origin0, normal0 ); + var d2 = -Vec.dot( origin1, normal1 ); var den = a1 * b2 - b1 * a2; @@ -929,15 +929,15 @@ class Intersect { var y = (d1 * a2 - a1 * d2) / den; var p; - if (li == 0) { + if ( li == 0 ) { p = [0, x, y]; - } else if (li == 1) { + } else if ( li == 1 ) { p = [x, 0, y]; } else { p = [x, y, 0]; } - return new Ray( p, Vec.normalized(d) ); + return new Ray( p, Vec.normalized( d ) ); } //Intersect three planes, expects the planes to form a single point of @@ -956,17 +956,17 @@ 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); + 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 diff = Vec.sub( Vec.mul( d2, n1 ), Vec.mul( d1, n2 ) ); + var num = Vec.add( Vec.mul( d0, u ), Vec.cross( n0, diff ) ); - return Vec.mul(1 / den, num); + return Vec.mul( 1 / den, num ); } @@ -982,29 +982,29 @@ class Intersect { // //* array of parameter pairs representing the intersection of the two parameteric polylines - public static function polylines(polyline0 : PolylineData, polyline1 : PolylineData, tol : Float) + public static function polylines( polyline0 : PolylineData, polyline1 : PolylineData, tol : Float ) : Array { var res = Intersect.boundingBoxTrees( new LazyPolylineBoundingBoxTree( polyline0 ), - new LazyPolylineBoundingBoxTree( polyline1 ), tol); + new LazyPolylineBoundingBoxTree( polyline1 ), tol ); 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; + 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; @@ -1024,25 +1024,25 @@ class Intersect { // //* a CurveCurveIntersection object - public static function segments(a0 : Point, a1 : Point, b0 : Point, b1 : Point, tol : Float) : CurveCurveIntersection { + 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) { + 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 ); } } @@ -1063,19 +1063,19 @@ class Intersect { // //* a CurveCurveIntersection object - public static function rays(a0 : Point, a : Point, b0 : Point, b : Point) : CurveCurveIntersection { + public static function rays( a0 : Point, a : Point, b0 : Point, b : Point ) : CurveCurveIntersection { - var dab = Vec.dot(a, b), - dab0 = Vec.dot(a, b0), - daa0 = Vec.dot(a, a0), - dbb0 = Vec.dot(b, b0), - dba0 = Vec.dot(b, a0), - daa = Vec.dot(a, a), - dbb = Vec.dot(b, b), + var dab = Vec.dot( a, b ), + dab0 = Vec.dot( a, b0 ), + daa0 = Vec.dot( a, a0 ), + dbb0 = Vec.dot( b, b0 ), + dba0 = Vec.dot( b, a0 ), + daa = Vec.dot( a, a ), + dbb = Vec.dot( b, b ), div = daa * dbb - dab * dab; //parallel case - if (Math.abs(div) < Constants.EPSILON) { + if ( Math.abs( div ) < Constants.EPSILON ) { return null; } @@ -1083,8 +1083,8 @@ class Intersect { w = num / div, t = (dab0 - daa0 + w * dab) / daa; - var p0 = Vec.onRay(a0, a, t); - var p1 = Vec.onRay(b0, b, w); + var p0 = Vec.onRay( a0, a, t ); + var p1 = Vec.onRay( b0, b, w ); return new CurveCurveIntersection( p0, p1, t, w ); } @@ -1102,52 +1102,52 @@ class Intersect { // //* a TriangleSegmentIntersection or null if failed - public static function segmentWithTriangle(p0 : Point, p1 : Point, points : Array, tri : Tri) : TriSegmentIntersection { + public static function segmentWithTriangle( p0 : Point, p1 : Point, points : Array, tri : Tri ) : TriSegmentIntersection { var v0 = points[ tri[0] ] , v1 = points[ tri[1] ] , v2 = points[ tri[2] ] - , u = Vec.sub(v1, v0) - , v = Vec.sub(v2, v0) - , n = Vec.cross(u, v); + , u = Vec.sub( v1, v0 ) + , v = Vec.sub( v2, v0 ) + , n = Vec.cross( u, v ); - var dir = Vec.sub(p1, p0) - , w0 = Vec.sub(p0, v0) - , a = -Vec.dot(n, w0) - , b = Vec.dot(n, dir); + var dir = Vec.sub( p1, p0 ) + , w0 = Vec.sub( p0, v0 ) + , a = -Vec.dot( n, w0 ) + , 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; } //get proposed intersection - var pt = Vec.add(p0, Vec.mul(r, dir)); + 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) - , w = Vec.sub(pt, v0) - , wu = Vec.dot(w, u) - , wv = Vec.dot(w, 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; } @@ -1170,21 +1170,21 @@ class Intersect { //**returns** //null or an object with a p property representing the param on the segment - public static function segmentAndPlane(p0 : Point, p1 : Point, v0 : Point, n : Point) { + 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) { + 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 }; @@ -1193,9 +1193,9 @@ class Intersect { } interface IBoundingBoxTree { - 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 boundingBox( ) : BoundingBox; + public function split( ) : Pair, IBoundingBoxTree>; + public function yield( ) : T; + public function indivisible( tolerance : Float ) : Bool; + public function empty( ) : Bool; } diff --git a/src/verb/eval/Make.hx b/src/verb/eval/Make.hx index 33bdeaf4..c0ec6bc7 100644 --- a/src/verb/eval/Make.hx +++ b/src/verb/eval/Make.hx @@ -40,26 +40,26 @@ class Make { // //* NurbsSurfaceData object - public static function rationalTranslationalSurface(profile : NurbsCurveData, rail : NurbsCurveData) : NurbsSurfaceData { + 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() + 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 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]]); - crvs.push(crv); + 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 ); } - return Make.loftedSurface(crvs); + return Make.loftedSurface( crvs ); } //Extract the boundary curves from a surface @@ -68,66 +68,66 @@ 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]; } - public static function surfaceIsocurve(surface : NurbsSurfaceData, u : Float, useV : Bool = false) : NurbsCurveData { + public static function surfaceIsocurve( surface : NurbsSurfaceData, u : Float, useV : Bool = false ) : NurbsCurveData { var knots = useV ? surface.knotsV : surface.knotsU; var degree = useV ? surface.degreeV : surface.degreeU; - var knotMults = Analyze.knotMultiplicities(knots); + var knotMults = Analyze.knotMultiplicities( knots ); //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); + 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] ); } - public static function loftedSurface(curves : Array, degreeV : Int = null) : NurbsSurfaceData { + public static function loftedSurface( curves : Array, degreeV : Int = null ) : NurbsSurfaceData { - curves = Modify.unifyCurveKnotVectors(curves); + curves = Modify.unifyCurveKnotVectors( curves ); //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,24 +136,24 @@ 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 - var c = Make.rationalInterpCurve(points, degreeV, true); - controlPoints.push(c.controlPoints); + var c = Make.rationalInterpCurve( points, degreeV, true ); + controlPoints.push( c.controlPoints ); knotsV = c.knots; //redundant computation } return new NurbsSurfaceData( degreeU, degreeV, knotsU, knotsV, controlPoints ); } - public static function clonedCurve(curve : NurbsCurveData) : NurbsCurveData { - return new NurbsCurveData( curve.degree, curve.knots.copy(), curve.controlPoints.map(function(x) { return x.copy(); }) ); + public static function clonedCurve( curve : NurbsCurveData ) : NurbsCurveData { + return new NurbsCurveData( curve.degree, curve.knots.copy( ), curve.controlPoints.map( function( x ) { return x.copy( ); } ) ); } //Generate the control points, weights, and knots for a bezier curve of any degree @@ -169,18 +169,18 @@ class Make { // //* NurbsSurfaceData object - public static function rationalBezierCurve(controlPoints : Array, weights : Array = null) : NurbsCurveData { + public static function rationalBezierCurve( controlPoints : Array, weights : Array = null ) : NurbsCurveData { 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)); + return new NurbsCurveData( degree, knots, Eval.homogenize1d( controlPoints, weights )); } //Generate the control points, weights, and knots of a surface defined by 4 points @@ -196,33 +196,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 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 + var res = Vec.lerp( 1.0 - j / degreeFloat, p1p2, p4p3 ); + res.push( 1.0 ); //add the weight - row.push(res); + row.push( res ); } - pts.push(row); + 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 ); } @@ -240,27 +240,27 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - public static function ellipseArc(center : Point, xaxis : Point, yaxis : Point, startAngle : Float, endAngle : Float) : NurbsCurveData { + public static function ellipseArc( center : Point, xaxis : Point, yaxis : Point, startAngle : Float, endAngle : Float ) : NurbsCurveData { - var xradius = Vec.norm(xaxis); - var yradius = Vec.norm(yaxis); + var xradius = Vec.norm( xaxis ); + var yradius = Vec.norm( yaxis ); - xaxis = Vec.normalized(xaxis); - yaxis = Vec.normalized(yaxis); + xaxis = Vec.normalized( xaxis ); + 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,38 +269,38 @@ 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); + , weights = Vec.zeros1d( numArcs * 2 ); 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))); + var P2 = Vec.add( center, + Vec.add( Vec.mul( xradius * Math.cos( angle ), xaxis ), Vec.mul( yradius * Math.sin( angle ), yaxis ) ) ); 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; index += 2; - if (i < numArcs) { + if ( i < numArcs ) { P0 = P2; T0 = T2; } @@ -308,7 +308,7 @@ 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; } @@ -325,7 +325,7 @@ class Make { knots[7] = knots[8] = 0.75; } - return new NurbsCurveData( 2, knots, Eval.homogenize1d(controlPoints, weights)); + return new NurbsCurveData( 2, knots, Eval.homogenize1d( controlPoints, weights )); } @@ -345,9 +345,9 @@ class Make { // //* a NurbsCurveData object representing a NURBS curve - 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); + 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 ); } //Generate the control points, weights, and knots of a polyline curve @@ -360,23 +360,23 @@ 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 lsum = 0.0; - for (i in 0...pts.length - 1) { - lsum += Vec.dist(pts[i], pts[i + 1]); - knots.push(lsum); + for ( i in 0...pts.length - 1 ) { + lsum += Vec.dist( pts[i], pts[i + 1] ); + knots.push( lsum ); } - knots.push(lsum); + knots.push( lsum ); //normalize the knot array - knots = Vec.mul(1 / lsum, knots); + 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 )); } @@ -392,30 +392,30 @@ class Make { // //* an object with the following properties: controlPoints, weights, knots, degree - public static function extrudedSurface(axis : Point, length : Float, profile : NurbsCurveData) : NurbsSurfaceData { + public static function extrudedSurface( axis : Point, length : Float, profile : NurbsCurveData ) : NurbsSurfaceData { var controlPoints = [[], [], []] , weights = [[], [], []]; - var prof_controlPoints = Eval.dehomogenize1d(profile.controlPoints); - var prof_weights = Eval.weight1d(profile.controlPoints); + var prof_controlPoints = Eval.dehomogenize1d( profile.controlPoints ); + var prof_weights = Eval.weight1d( profile.controlPoints ); - var translation = Vec.mul(length, axis); - var halfTranslation = Vec.mul(0.5 * length, axis); + var translation = Vec.mul( length, axis ); + 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]); - controlPoints[0][j] = Vec.add(translation, prof_controlPoints[j]); + controlPoints[1][j] = Vec.add( halfTranslation, prof_controlPoints[j] ); + controlPoints[0][j] = 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 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 @@ -432,13 +432,13 @@ class Make { // //* an object with the following properties: controlPoints, weights, knotsU, knotsV, degreeU, degreeV - public static function cylindricalSurface(axis : Point, xaxis : Point, base : Point, height : Float, radius : Float) : NurbsSurfaceData { + public static function cylindricalSurface( axis : Point, xaxis : Point, base : Point, height : Float, radius : Float ) : NurbsSurfaceData { - var yaxis = Vec.cross(axis, xaxis) + var yaxis = Vec.cross( axis, xaxis ) , angle = 2.0 * Math.PI - , circ = Make.arc(base, xaxis, yaxis, radius, 0.0, 2 * Math.PI); + , circ = Make.arc( base, xaxis, yaxis, radius, 0.0, 2 * Math.PI ); - return Make.extrudedSurface(axis, height, circ); + return Make.extrudedSurface( axis, height, circ ); } @@ -458,29 +458,29 @@ class Make { // //* an object with the following properties: controlPoints, weights, knots, degree - public static function revolvedSurface(profile : NurbsCurveData, center : Point, axis : Point, theta : Float) : NurbsSurfaceData { + 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); + var prof_controlPoints = Eval.dehomogenize1d( 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 = Vec.zeros1d( 6 + 2 * (narcs - 1) ); knotsU[3] = knotsU[4] = 0.5; - } else if (theta <= 3 * Math.PI / 2) { //between 180 and 270 + } else if ( theta <= 3 * Math.PI / 2 ) { //between 180 and 270 narcs = 3; - knotsU = Vec.zeros1d(6 + 2 * (narcs - 1)); + 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 = Vec.zeros1d( 6 + 2 * (narcs - 1) ); knotsU[3] = knotsU[4] = 1 / 4; knotsU[5] = knotsU[6] = 1 / 2; knotsU[7] = knotsU[8] = 3 / 4; @@ -492,43 +492,43 @@ class Make { //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; } //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) + 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) + , X = Vec.sub( prof_controlPoints[j], O ) //radius at that height - , r = Vec.norm(X) + , r = Vec.norm( X ) //Y is perpendicular to X and axis, and complete the coordinate system - , Y = Vec.cross(axis, X); + , Y = Vec.cross( axis, X ); - if (r > Constants.EPSILON) { - X = Vec.mul(1 / r, X); - Y = Vec.mul(1 / r, Y); + 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,25 +542,25 @@ 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]; //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) { + 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; } @@ -569,14 +569,14 @@ class Make { index += 2; - if (i < narcs) { + if ( i < narcs ) { P0 = P2; T0 = T2; } } } - return new NurbsSurfaceData( 2, profile.degree, knotsU, profile.knots, Eval.homogenize2d(controlPoints, weights) ); + return new NurbsSurfaceData( 2, profile.degree, knotsU, profile.knots, Eval.homogenize2d( controlPoints, weights ) ); } @@ -594,10 +594,10 @@ 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); - return revolvedSurface(arc, center, axis, 2 * 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 ); } @@ -615,24 +615,24 @@ class Make { //* an object with the following properties: controlPoints, weights, knots, degree // - public static function conicalSurface(axis : Point, xaxis : Point, base : Point, height : Float, radius : Float) : NurbsSurfaceData { + public static function conicalSurface( axis : Point, xaxis : Point, base : Point, height : Float, radius : Float ) : NurbsSurfaceData { 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_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 = new NurbsCurveData( prof_degree, prof_knots, Eval.homogenize1d(prof_ctrl_pts, prof_weights) ); + , 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 ); } - public static function rationalInterpCurve(points : Array>, - degree : Int = 3, - homogeneousPoints : Bool = false, - start_tangent : Point = null, - end_tangent : Point = null) : NurbsCurveData { + public static function rationalInterpCurve( points : Array>, + degree : Int = 3, + homogeneousPoints : Bool = false, + start_tangent : Point = null, + end_tangent : Point = null ) : NurbsCurveData { // 0) build knot vector for curve by normalized chord length // 1) construct effective basis function in square matrix (W) @@ -643,24 +643,24 @@ 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); + us.push( last + chord ); } //normalize var max = us[us.length - 1]; - for (i in 0...us.length) { + for ( i in 0...us.length ) { us[i] = us[i] / max; } - var knotsStart = Vec.rep(degree + 1, 0.0); + var knotsStart = Vec.rep( degree + 1, 0.0 ); //we need two more control points, two more knots @@ -668,16 +668,16 @@ 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]; } - knotsStart.push((1 / degree) * weightSums); + knotsStart.push( (1 / degree) * weightSums ); } - var knots = knotsStart.concat(Vec.rep(degree + 1, 1.0)); + var knots = knotsStart.concat( Vec.rep( degree + 1, 1.0 ) ); //build matrix of basis function coeffs (TODO: use sparse rep) var A = []; @@ -686,26 +686,26 @@ class Make { var lst = hasTangents ? 1 : 0; var ld = hasTangents ? points.length - (degree - 1) : points.length - (degree + 1); - for (u in us) { - var span = Eval.knotSpanGivenN(n, degree, u, knots); - var basisFuncs = Eval.basisFunctionsGivenKnotSpanIndex(span, u, degree, knots); + for ( u in us ) { + var span = Eval.knotSpanGivenN( n, degree, u, knots ); + var basisFuncs = Eval.basisFunctionsGivenKnotSpanIndex( span, u, degree, knots ); var ls = span - degree; - var rowstart = Vec.zeros1d(ls); - var rowend = Vec.zeros1d(ld - ls); + 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( 1, 0, tanRow0 ); + A.spliceAndInsert( A.length - 1, 0, tanRow1 ); } //for each dimension, solve @@ -715,31 +715,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(mult1 * end_tangent[i]); - b.push(points.last()[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] ); } - var x = Mat.solve(A, b); - xs.push(x); + var x = Mat.solve( A, b ); + 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 83f854f7..6adeb781 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -35,8 +35,8 @@ 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() ); + public static function curveReverse( curve : NurbsCurveData ) : NurbsCurveData { + 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. @@ -50,15 +50,15 @@ 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() ]); + 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( ) ]); } - 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 @@ -71,14 +71,14 @@ class Modify { // //* The reversed array of knots - public static function knotsReverse(knots : KnotArray) : KnotArray { - var min = knots.first(); - var max = knots.last(); + public static function knotsReverse( knots : KnotArray ) : KnotArray { + 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; @@ -94,56 +94,56 @@ 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); + public static function unifyCurveKnotVectors( curves : Array ) : Array { + 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) { - curves[i] = Modify.curveElevateDegree(curves[i], 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) { - var rem = Vec.sortedSetSub(mergedKnots, curves[i].knots); - if (rem.length == 0) { + for ( i in 0...curves.length ) { + var rem = Vec.sortedSetSub( mergedKnots, curves[i].knots ); + if ( rem.length == 0 ) { curves[i] = curves[i]; } - curves[i] = Modify.curveKnotRefine(curves[i], rem); + curves[i] = Modify.curveKnotRefine( curves[i], rem ); } return curves; } - private static function imin(a : Int, b : Int) : Int { + private static function imin( a : Int, b : Int ) : Int { return a < b ? a : b; } - private static function imax(a : Int, b : Int) : Int { + private static function imax( a : Int, b : Int ) : Int { return a > b ? a : b; } @@ -158,9 +158,9 @@ class Modify { // //* The NURBS curve after degree elevation - if the supplied degree is <= the curve is returned unmodified - public static function curveElevateDegree(curve : NurbsCurveData, finalDegree : Int) : NurbsCurveData { + 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,16 +190,16 @@ class Modify { bezalfs[0][0] = 1.0; bezalfs[ph][newDegree] = 1.0; - 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); + 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 ); } } - for (i in ph2 + 1...ph) { - var mpi = imin(newDegree, i); - for (j in imax(0, i - degreeInc)...mpi + 1) { + 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]; } } @@ -211,15 +211,15 @@ class Modify { 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]) { + while ( b < m && knots[b] == knots[b + 1] ) { b = b + 1; } var mul = b - i + 1; @@ -228,57 +228,57 @@ class Modify { var oldr = r; 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 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) { + while ( k > mul ) { alfs[k - mul - 1] = numer / (knots[a + k] - ua); //integer arithmetic? k--; } - for (j in 1...r + 1) { + 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) { - 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])); + 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] ) ); } } - if (oldr > 1) { + 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) { + for ( tr in 1...oldr ) { var i = first; var j = last; var kj = j - kind + 1; - while (j - i > tr) { - if (i < cind) { + 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]); + Qw[i] = Vec.lerp( alf, Qw[i], Qw[i - 1] ); } - if (j >= lbz) { - if (j - tr <= kind - ph + oldr) { + 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]); + 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; @@ -289,23 +289,23 @@ class Modify { } } - if (a != newDegree) { - for (i in 0...ph - oldr) { + if ( a != newDegree ) { + for ( i in 0...ph - oldr ) { Uh[kind] = ua; 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) { + for ( j in r...newDegree + 1 ) { bpts[j] = controlPoints[b - newDegree + j]; } a = b; @@ -313,7 +313,7 @@ class Modify { ua = ub; } else { - for (i in 0...ph + 1) { + for ( i in 0...ph + 1 ) { Uh[kind + i] = ub; } } @@ -334,20 +334,20 @@ class Modify { // //* A new NURBS surface after transformation - public static function rationalSurfaceTransform(surface : NurbsSurfaceData, mat : Matrix) : NurbsSurfaceData { + public static function rationalSurfaceTransform( surface : NurbsSurfaceData, mat : Matrix ) : NurbsSurfaceData { - var pts = Eval.dehomogenize2d(surface.controlPoints); + 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); + 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 @@ -361,19 +361,19 @@ class Modify { // //* A new NURBS surface after transformation - public static function rationalCurveTransform(curve : NurbsCurveData, mat : Matrix) : NurbsCurveData { + public static function rationalCurveTransform( curve : NurbsCurveData, mat : Matrix ) : NurbsCurveData { - var pts = Eval.dehomogenize1d(curve.controlPoints); + 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); + 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 ) ) ); } @@ -389,7 +389,7 @@ class Modify { // //* A new NURBS surface with the knots inserted - public static function surfaceKnotRefine(surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool) : NurbsSurfaceData { + 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 @@ -400,8 +400,8 @@ class Modify { , ctrlPts; //u dir - if (!useV) { - ctrlPts = Mat.transpose(surface.controlPoints); + if ( !useV ) { + ctrlPts = Mat.transpose( surface.controlPoints ); knots = surface.knotsU; degree = surface.degreeU; //v dir @@ -413,20 +413,20 @@ class Modify { //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 ( cptrow in ctrlPts ) { + c = curveKnotRefine( new NurbsCurveData(degree, knots, cptrow), knotsToInsert ); + newPts.push( c.controlPoints ); } var newknots = c.knots; //u dir - if (!useV) { - newPts = Mat.transpose(newPts); - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy(), newPts ); + if ( !useV ) { + newPts = Mat.transpose( newPts ); + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy( ), newPts ); //v dir } else { - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy(), newknots, newPts ); + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), newknots, newPts ); } } @@ -442,7 +442,7 @@ class Modify { // //* *Array* of NurbsCurveData objects, defined by degree, knots, and control points - public static function decomposeCurveIntoBeziers(curve : NurbsCurveData) : Array { + public static function decomposeCurveIntoBeziers( curve : NurbsCurveData ) : Array { var degree = curve.degree , controlPoints = curve.controlPoints @@ -451,15 +451,15 @@ class Modify { //find all of the unique knot values and their multiplicity //for each, increase their multiplicity to degree + 1 - var knotmults = Analyze.knotMultiplicities(knots); + var knotmults = Analyze.knotMultiplicities( knots ); var reqMult = degree + 1; //insert the knots - for (knotmult in knotmults) { - if (knotmult.mult < reqMult) { + for ( knotmult in knotmults ) { + if ( knotmult.mult < reqMult ) { - var knotsInsert = Vec.rep(reqMult - knotmult.mult, knotmult.knot); - var res = curveKnotRefine(new NurbsCurveData(degree, knots, controlPoints), knotsInsert); + var knotsInsert = Vec.rep( reqMult - knotmult.mult, knotmult.knot ); + var res = curveKnotRefine( new NurbsCurveData(degree, knots, controlPoints), knotsInsert ); knots = res.knots; controlPoints = res.controlPoints; @@ -472,11 +472,11 @@ class Modify { var crvs = []; var i = 0; - while (i < controlPoints.length) { - var kts = knots.slice(i, i + crvKnotLength); - var pts = controlPoints.slice(i, i + reqMult); + while ( i < controlPoints.length ) { + var kts = knots.slice( i, i + crvKnotLength ); + var pts = controlPoints.slice( i, i + reqMult ); - crvs.push(new NurbsCurveData(degree, kts, pts )); + crvs.push( new NurbsCurveData(degree, kts, pts ) ); i += reqMult; } @@ -499,9 +499,9 @@ class Modify { //* NurbsCurveData object representing the curve // - public static function curveKnotRefine(curve : NurbsCurveData, knotsToInsert : Array) : NurbsCurveData { + 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 @@ -510,26 +510,26 @@ class Modify { var n = 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) + , 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 - 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) { + 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) { + for ( i in b + degree...m + 1 ) { knots_post[i + r + 1] = knots[i]; } @@ -537,9 +537,9 @@ class Modify { var k = b + degree + r; var j = r; - while (j >= 0) { + while ( j >= 0 ) { - while (knotsToInsert[j] <= knots[i] && i > a) { + while ( knotsToInsert[j] <= knots[i] && i > a ) { controlPoints_post[k - degree - 1] = controlPoints[i - degree - 1]; knots_post[k] = knots[i]; k = k - 1; @@ -548,19 +548,19 @@ class Modify { 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]; - if (Math.abs(alfa) < Constants.EPSILON) { + if ( Math.abs( alfa ) < Constants.EPSILON ) { controlPoints_post[ind - 1] = controlPoints_post[ind]; } else { 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])); + Vec.mul( alfa, controlPoints_post[ind - 1] ), + Vec.mul( (1.0 - alfa), controlPoints_post[ind] ) ); } } @@ -595,7 +595,7 @@ class Modify { //* *Object* the new curve, defined by knots and controlPoints // - public static function curveKnotInsert(curve : NurbsCurveData, u : Float, r : Int) : NurbsCurveData { + public static function curveKnotInsert( curve : NurbsCurveData, u : Float, r : Int ) : NurbsCurveData { var degree = curve.degree , controlPoints = curve.controlPoints @@ -610,7 +610,7 @@ class Modify { var s = 0; //assume original multiplicity is 0 - TODO add check for multiplicity in knots var num_pts = controlPoints.length - , k = Eval.knotSpan(degree, u, knots) //the span in which the knot will be inserted + , k = Eval.knotSpan( degree, u, knots ) //the span in which the knot will be inserted , num_pts_post = num_pts + r //a new control pt for every new knot , controlPoints_temp = new Array() //new Array( degree - s ) , knots_post = new KnotArray() //new Array( knots.length + r ) //r new knots @@ -620,34 +620,34 @@ 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) { + for ( i in 1...r + 1 ) { knots_post[k + i] = u; } //insert the rest of the knots - for (i in k + 1...knots.length) { + 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) { + 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) { + for ( i in 0...degree - s + 1 ) { controlPoints_temp[i] = controlPoints[k - degree + i]; } @@ -655,17 +655,17 @@ class Modify { , alpha : Float = 0; //insert knot r times - for (j in 1...r + 1) { + for ( j in 1...r + 1 ) { 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] ); controlPoints_temp[i] = Vec.add( - Vec.mul((1.0 - alpha), controlPoints_temp[i]), - Vec.mul(alpha, controlPoints_temp[i + 1]) + Vec.mul( (1.0 - alpha), controlPoints_temp[i] ), + Vec.mul( alpha, controlPoints_temp[i + 1] ) ); } @@ -675,7 +675,7 @@ class Modify { } //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 898930b9..6d78ec87 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -24,93 +24,36 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { - // 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 representing the curve - //* number of divisions - // - //**returns** - // - //* an array of (divs+1) points - - public static function rationalCurveRegularSamplePoints2(crv : NurbsCurveData, tol : Float) : Array { - - var range = crv.knots.last() - crv.knots[0]; - var beziers = Modify.decomposeCurveIntoBeziers(crv); - var pts = [], step; - - for (i in 0...beziers.length) { - - step = rationalBezierCurveStepLength(beziers[i], tol) - - rationalBezierCurveRegularSamplePointsMutate(beziers[i], pts, currentU, step, bsteps + 1); - - currentU = nextU + step; - } + public static function rationalCurveRegularSample2( crv : NurbsCurveData, tol : Float ) : Array { - return pts; - } - - // 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 representing the curve - //* number of divisions - // - //**returns** - // - //* an array of (divs+1) points + var beziers = Modify.decomposeCurveIntoBeziers( crv ); - public static function rationalCurveRegularSamplePoints(crv : NurbsCurveData, divs : Int) : Array { + var pts = [], steps, domain; - var range = crv.knots.last() - crv.knots[0]; - var beziers = Modify.decomposeCurveIntoBeziers(crv); - var pts = []; - var brange, fraction; + for ( i in 0...beziers.length ) { - var currentU = crv.knots[0]; - var step = range / divs; - var brange, bsteps, nextU; + domain = beziers[i].knots.last( ) - beziers[i].knots[0]; - 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--; - } + steps = Math.ceil( domain / rationalBezierCurveStepLength( beziers[i], tol ) ); - rationalBezierCurveRegularSamplePointsMutate(beziers[i], pts, currentU, step, bsteps + 1); + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, steps ); - currentU = nextU + step; + if ( i != beziers.length - 1 ) break; + pts.pop( ); } return pts; } - private static function rationalBezierCurveRegularSamplePointsMutate(crv : NurbsCurveData, - pts : Array, - startU : Float, - step : Float, - numSteps : Int) { + private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, + pts : Array, + numSteps : Int ) { var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; - if (numSteps <= crv.degree + 1) { - for (i in 0...numSteps) { - pts.push(rationalCurvePoint(crv, u)); + if ( numSteps <= crv.degree + 1 ) { + for ( i in 0...numSteps ) { + pts.push( rationalCurvePoint( crv, u ) ); u += step; } return; @@ -118,8 +61,8 @@ class Tess { // initialize forward differencing - for (i in 0...degree1) { - its.push(curvePoint(crv, u)); + for ( i in 0...degree1 ) { + its.push( curvePoint( crv, u ) ); u += step; } @@ -127,40 +70,40 @@ class Tess { var prev; - for (i in 1...degree1) { + for ( i in 1...degree1 ) { its = []; - ts.push(its); + ts.push( its ); prev = ts[i - 1]; - for (j in 1...prev.length) { - its.push(Vec.sub(prev[j], prev[j - 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(dehomogenize(pt)); + for ( pt in ts[0] ) { + pts.push( dehomogenize( pt ) ); } // evaluate the rest of the points - var front = [ for (r in ts) r.last() ], k; + var front = [ for ( r in ts ) r.last( ) ], k; var frlen2 = front.length - 2; - for (i in 0...numSteps - degree1) { + for ( i in 0...numSteps - degree1 ) { // Rright = R + Rdown // compute the new forward difference front - for (j in 0...front.length - 1) { + for ( j in 0...front.length - 1 ) { k = frlen2 - j; // invert - Vec.addMutate(front[k], front[k + 1]); + Vec.addMutate( front[k], front[k + 1] ); } // add the new pt - pts.push(dehomogenize(front[0])); + pts.push( dehomogenize( front[0] ) ); } } @@ -175,79 +118,79 @@ class Tess { // //* The step length - domain / step length yields the number of steps to take within the curve - public static function rationalBezierCurveStepLength(curve : NurbsCurveData, tol : Float) : Float { + public static function rationalBezierCurveStepLength( curve : NurbsCurveData, tol : Float ) : Float { // get average pt - var dehomo = Eval.dehomogenize1d(curve.controlPoints); + var dehomo = Eval.dehomogenize1d( curve.controlPoints ); var bb = new BoundingBox( dehomo ); - var avgPt = Vec.mul(0.5, Vec.add(bb.min, bb.max)); + var avgPt = Vec.mul( 0.5, Vec.add( bb.min, bb.max ) ); // clone and translate all control pts - var m = Mat.identity(4); + var m = Mat.identity( 4 ); m[0][3] = -avgPt[0]; m[1][3] = -avgPt[1]; m[2][3] = -avgPt[2]; - var tc = Modify.rationalCurveTransform(curve, m); // todo util methods for translation - dehomo = Eval.dehomogenize1d(tc.controlPoints); + var tc = Modify.rationalCurveTransform( curve, m ); // todo util methods for translation + dehomo = Eval.dehomogenize1d( tc.controlPoints ); // compute r = max( || Pi || ) var r = 0.0, n; - for (i in 0...dehomo.length) { - n = Vec.norm(dehomo[i]); - if (n > r) r = 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]; + var wts = Eval.weight1d( curve.controlPoints ); + var w = Vec.min( wts ); + var domain = curve.knots.last( ) - curve.knots[0]; - if (tol < r) { + 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 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); + return domain * Math.sqrt( numer / denom ); - } else if (r >= tol && tol < 2.0 * r) { + } else if ( r >= tol && tol < 2.0 * r ) { 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 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); + return domain * Math.sqrt( numer / denom ); } else { return domain; } } - private static function secondForwardDiff(array : Array) { + 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]); + 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) { + 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]))); + while ( i < array.length - 2 ) { + res.push( Vec.add( array[i + 2], Vec.add( Vec.mul( -2.0, array[i + 1] ), array[i] ) ) ); i++; } @@ -266,8 +209,8 @@ class Tess { // //* an array of points, prepended by the point param if required - public static function rationalCurveRegularSample(curve : NurbsCurveData, numSamples : Int, includeU : Bool) : Array { - return rationalCurveRegularSampleRange(curve, curve.knots[0], curve.knots.last(), numSamples, includeU); + public static function rationalCurveRegularSample( curve : NurbsCurveData, numSamples : Int, includeU : Bool ) : Array { + return rationalCurveRegularSampleRange( curve, curve.knots[0], curve.knots.last( ), numSamples, includeU ); } //Sample a range of a NURBS curve at equally spaced parametric intervals @@ -284,10 +227,10 @@ class Tess { // //* an dictionary of parameter - point pairs - public static function rationalCurveRegularSampleRange(curve : NurbsCurveData, start : Float, end : Float, - numSamples : Int, includeU : Bool) : Array { + public static function rationalCurveRegularSampleRange( curve : NurbsCurveData, start : Float, end : Float, + numSamples : Int, includeU : Bool ) : Array { - if (numSamples < 1) { + if ( numSamples < 1 ) { numSamples = 2; } @@ -295,14 +238,14 @@ class Tess { var span : Float = (end - start) / (numSamples - 1); var u : Float = 0; - for (i in 0...numSamples) { + for ( i in 0...numSamples ) { u = start + span * i; - if (includeU) { - p.push([u].concat(Eval.rationalCurvePoint(curve, u))); + if ( includeU ) { + p.push( [u].concat( Eval.rationalCurvePoint( curve, u ) ) ); } else { - p.push(Eval.rationalCurvePoint(curve, u)); + p.push( Eval.rationalCurvePoint( curve, u ) ); } } @@ -323,20 +266,20 @@ class Tess { // //* 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 { + 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); + 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])) ]; + return [ for ( i in 0...curve.controlPoints.length ) + [ curve.knots[i + 1] ].concat( Eval.dehomogenize( curve.controlPoints[i] ) ) ]; } } - return rationalCurveAdaptiveSampleRange(curve, curve.knots[0], curve.knots.last(), tol, includeU); + return rationalCurveAdaptiveSampleRange( curve, curve.knots[0], curve.knots.last( ), tol, includeU ); } //Sample a NURBS curve at 3 points, facilitating adaptive sampling @@ -352,35 +295,35 @@ class Tess { // //* 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 rationalCurveAdaptiveSampleRange(curve : NurbsCurveData, start, end, tol, includeU) : Array { + public static function rationalCurveAdaptiveSampleRange( curve : NurbsCurveData, start, end, tol, includeU ) : Array { //sample curve at three pts - var p1 = Eval.rationalCurvePoint(curve, start), - p3 = Eval.rationalCurvePoint(curve, end), - t = 0.5 + 0.2 * Math.random(), + 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); + p2 = Eval.rationalCurvePoint( curve, mid ); //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 diff = Vec.sub( p1, p3 ); + var diff2 = Vec.sub( p1, p2 ); //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)) { + if ( ( Vec.dot( diff, diff ) < tol && Vec.dot( diff2, diff2 ) > tol ) || !Trig.threePointsAreFlat( p1, p2, p3, tol ) ) { //get the exact middle var exact_mid = start + (end - start) * 0.5; //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 left_pts = rationalCurveAdaptiveSampleRange( curve, start, exact_mid, tol, includeU ) + , right_pts = rationalCurveAdaptiveSampleRange( curve, exact_mid, end, tol, includeU ); //concatenate the two - return left_pts.slice(0, -1).concat(right_pts); + return left_pts.slice( 0, -1 ).concat( right_pts ); } else { - if (includeU) { - return [ [ start ].concat(p1), [end].concat(p3) ]; + if ( includeU ) { + return [ [ start ].concat( p1 ), [end].concat( p3 ) ]; } else { return [ p1, p3 ]; } @@ -399,10 +342,10 @@ class Tess { // //* 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 @@ -410,8 +353,8 @@ class Tess { , 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; @@ -420,28 +363,28 @@ class Tess { 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; - uvs.push([pt_u, pt_v]); + uvs.push( [pt_u, pt_v] ); - var derivs = Eval.rationalSurfaceDerivatives(surface, pt_u, pt_v, 1); + 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 = []; - for (i in 0...divs_u) { - for (j in 0...divs_v) { + 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, @@ -449,8 +392,8 @@ class Tess { 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 ); } } @@ -469,9 +412,9 @@ class Tess { // //* 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; @@ -486,9 +429,9 @@ class Tess { var divsV = options.minDivsV = options.minDivsV > minV ? options.minDivsV : minV; //get necessary intervals - var umax = surface.knotsU.last(); + var umax = surface.knotsU.last( ); var umin = surface.knotsU[0]; - var vmax = surface.knotsV.last(); + var vmax = surface.knotsV.last( ); var vmin = surface.knotsV[0]; var du = (umax - umin) / divsU @@ -498,92 +441,92 @@ class Tess { var pts = []; // 1) evaluate all of the corners - for (i in 0...divsV + 1) { + for ( i in 0...divsV + 1 ) { var ptrow = []; - for (j in 0...divsU + 1) { + for ( j in 0...divsU + 1 ) { 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); + 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) )); + 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); + pts.push( ptrow ); } // 2) make all of the nodes - for (i in 0...divsV) { - for (j in 0...divsU) { + 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) { + 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); + , 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].divide( options ); } } return divs; } - private static function north(index, i, j, divsU, divsV, divs) { - if (i == 0) return null; + 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; + 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; + 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; + private static function west( index, i, j, divsU, divsV, divs ) { + if ( j == 0 ) return null; return divs[ index - 1 ]; } - private static function triangulateAdaptiveRefinementNodeTree(arrTree : Array) : MeshData { + private static function triangulateAdaptiveRefinementNodeTree( arrTree : Array ) : MeshData { //triangulate all of the nodes of the tree - var mesh = MeshData.empty(); - for (x in arrTree) x.triangulate(mesh); + var mesh = MeshData.empty( ); + for ( x in arrTree ) x.triangulate( mesh ); return mesh; } - public static function rationalSurfaceAdaptive(surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null) : MeshData { + public static function rationalSurfaceAdaptive( surface : NurbsSurfaceData, options : AdaptiveRefinementOptions = null ) : MeshData { options = options != null ? options : new AdaptiveRefinementOptions(); //adaptive divide - var arrTrees = divideRationalSurfaceAdaptive(surface, options); + var arrTrees = divideRationalSurfaceAdaptive( surface, options ); //triangulation - return triangulateAdaptiveRefinementNodeTree(arrTrees); + return triangulateAdaptiveRefinementNodeTree( arrTrees ); } } @@ -597,7 +540,7 @@ class AdaptiveRefinementOptions { public var minDivsU : Int = 1; public var minDivsV : Int = 1; - public function new() {} + public function new( ) {} } @@ -640,7 +583,7 @@ class AdaptiveRefinementNode { var u05 : Float; var v05 : Float; - public function new(srf : NurbsSurfaceData, corners : Array, neighbors : Array = null) { + public function new( srf : NurbsSurfaceData, corners : Array, neighbors : Array = null ) { this.srf = srf; @@ -649,56 +592,56 @@ 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() { - return this.centerPoint != null ? this.centerPoint : this.evalSrf(this.u05, this.v05); + public function center( ) { + return this.centerPoint != null ? this.centerPoint : this.evalSrf( this.u05, this.v05 ); } - public function evalCorners() { + public function evalCorners( ) { //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) { + for ( i in 0...4 ) { //if it's not already evaluated - if (this.corners[i].point == null) { + if ( this.corners[i].point == null ) { //evaluate it var c = this.corners[i]; - this.evalSrf(c.uv[0], c.uv[1], c); + this.evalSrf( c.uv[0], c.uv[1], c ); } } } - public function evalSrf(u : Float, v : Float, srfPt : SurfacePoint = null) : SurfacePoint { + public function evalSrf( u : Float, v : Float, srfPt : SurfacePoint = null ) : SurfacePoint { - var derivs = Eval.rationalSurfaceDerivatives(this.srf, u, v, 1); + 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 degen = Vec.isZero(norm); + 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; @@ -708,22 +651,22 @@ class AdaptiveRefinementNode { } } - public function getEdgeCorners(edgeIndex : Int) : Array { + 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 ( this.isLeaf( ) ) return [ this.corners[ edgeIndex ] ]; - if (this.horizontal) { + if ( this.horizontal ) { switch (edgeIndex){ case 0: - return this.children[0].getEdgeCorners(0); + return this.children[0].getEdgeCorners( 0 ); case 1: - return this.children[0].getEdgeCorners(1).concat(this.children[1].getEdgeCorners(1)); + return this.children[0].getEdgeCorners( 1 ).concat( this.children[1].getEdgeCorners( 1 ) ); case 2: - return this.children[1].getEdgeCorners(2); + return this.children[1].getEdgeCorners( 2 ); case 3: - return this.children[1].getEdgeCorners(3).concat(this.children[0].getEdgeCorners(3)); + return this.children[1].getEdgeCorners( 3 ).concat( this.children[0].getEdgeCorners( 3 ) ); } } @@ -731,28 +674,28 @@ class AdaptiveRefinementNode { //vertical case switch (edgeIndex) { case 0: - return this.children[0].getEdgeCorners(0).concat(this.children[1].getEdgeCorners(0)); + return this.children[0].getEdgeCorners( 0 ).concat( this.children[1].getEdgeCorners( 0 ) ); case 1: - return this.children[1].getEdgeCorners(1); + return this.children[1].getEdgeCorners( 1 ); case 2: - return this.children[1].getEdgeCorners(2).concat(this.children[0].getEdgeCorners(2)); + return this.children[1].getEdgeCorners( 2 ).concat( this.children[0].getEdgeCorners( 2 ) ); case 3: - return this.children[0].getEdgeCorners(3); + return this.children[0].getEdgeCorners( 3 ); } return null; } - public function getAllCorners(edgeIndex : Int) : Array { + public function getAllCorners( edgeIndex : Int ) : Array { var baseArr = [ this.corners[edgeIndex] ]; - if (this.neighbors[edgeIndex] == null) { + if ( this.neighbors[edgeIndex] == null ) { return baseArr; } //get opposite edges uvs - var corners = this.neighbors[edgeIndex].getEdgeCorners(( edgeIndex + 2 ) % 4); + var corners = this.neighbors[edgeIndex].getEdgeCorners( ( edgeIndex + 2 ) % 4 ); var funcIndex = edgeIndex % 2; @@ -761,48 +704,48 @@ class AdaptiveRefinementNode { //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 - var cornercopy = corners.filter(rangeFuncMap[ funcIndex ]); - cornercopy.reverse(); - return baseArr.concat(cornercopy); + var cornercopy = corners.filter( rangeFuncMap[ funcIndex ] ); + 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: - this.midPoints[0] = this.evalSrf(this.u05, this.corners[0].uv[1]); + this.midPoints[0] = this.evalSrf( this.u05, this.corners[0].uv[1] ); case 1: - this.midPoints[1] = this.evalSrf(this.corners[1].uv[0], this.v05); + this.midPoints[1] = this.evalSrf( this.corners[1].uv[0], this.v05 ); case 2: - this.midPoints[2] = this.evalSrf(this.u05, this.corners[2].uv[1]); + this.midPoints[2] = this.evalSrf( this.u05, this.corners[2].uv[1] ); case 3: - this.midPoints[3] = this.evalSrf(this.corners[0].uv[0], this.v05); + this.midPoints[3] = this.evalSrf( this.corners[0].uv[0], this.v05 ); } return this.midPoints[index]; } - 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) { + if ( this.corners[i].degen ) { //get neighbors var v1 = this.corners[(i + 1) % l]; var v2 = this.corners[(i + 3) % l]; @@ -813,65 +756,65 @@ class AdaptiveRefinementNode { } } - 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 ( currentDepth < options.minDepth ) return true; + if ( currentDepth >= options.maxDepth ) return false; - if (this.hasBadNormals()) { - this.fixNormals(); + if ( this.hasBadNormals( ) ) { + this.fixNormals( ); //don't divide any further when encountering a degenerate normal return false; } - this.splitVert = Vec.normSquared(Vec.sub(this.corners[0].normal, this.corners[1].normal)) > options.normTol || - Vec.normSquared(Vec.sub(this.corners[2].normal, this.corners[3].normal)) > options.normTol; + this.splitVert = Vec.normSquared( Vec.sub( this.corners[0].normal, this.corners[1].normal ) ) > options.normTol || + Vec.normSquared( Vec.sub( this.corners[2].normal, this.corners[3].normal ) ) > options.normTol; - this.splitHoriz = Vec.normSquared(Vec.sub(this.corners[1].normal, this.corners[2].normal)) > options.normTol || - Vec.normSquared(Vec.sub(this.corners[3].normal, this.corners[0].normal)) > options.normTol; + this.splitHoriz = Vec.normSquared( Vec.sub( this.corners[1].normal, this.corners[2].normal ) ) > options.normTol || + Vec.normSquared( Vec.sub( this.corners[3].normal, this.corners[0].normal ) ) > options.normTol; - if (this.splitVert || this.splitHoriz) return true; + 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 || - Vec.normSquared(Vec.sub(center.normal, this.corners[2].normal)) > options.normTol || - Vec.normSquared(Vec.sub(center.normal, this.corners[3].normal)) > options.normTol; + 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 || + Vec.normSquared( Vec.sub( center.normal, this.corners[2].normal ) ) > options.normTol || + Vec.normSquared( Vec.sub( center.normal, this.corners[3].normal ) ) > options.normTol; } - public function divide(options : AdaptiveRefinementOptions = null) : Void { - if (options == null) options = new AdaptiveRefinementOptions(); + 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; + 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); + this._divide( options, 0, true ); } - private function _divide(options : AdaptiveRefinementOptions, currentDepth : Int, horiz : Bool) : Void { + 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) { + 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 ) ]; @@ -883,8 +826,8 @@ class AdaptiveRefinementNode { } 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 ) ]; @@ -894,28 +837,28 @@ class AdaptiveRefinementNode { } //divide all children recursively - for (child in this.children) { - child._divide(options, currentDepth, !horiz); + for ( child in this.children ) { + child._divide( options, currentDepth, !horiz ); } } - public function triangulate(mesh : MeshData = null) : MeshData { + 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; - x.triangulate(mesh); + 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 = [] @@ -923,66 +866,66 @@ class AdaptiveRefinementNode { , splitid = 0; //enumerate all uvs in counter clockwise direction - for (i in 0...4) { + 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; + 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 ( corner.id != -1 ) { + ids.push( corner.id ); continue; } - mesh.uvs.push(corner.uv); - mesh.points.push(corner.point); - mesh.normals.push(corner.normal); + mesh.uvs.push( corner.uv ); + mesh.points.push( corner.point ); + mesh.normals.push( corner.normal ); corner.id = baseIndex; - ids.push(baseIndex); + ids.push( baseIndex ); 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 - mesh.faces.push([ ids[0], ids[3], ids[1] ]); - mesh.faces.push([ ids[3], ids[2], ids[1] ]); + mesh.faces.push( [ ids[0], ids[3], ids[1] ] ); + mesh.faces.push( [ ids[3], ids[2], ids[1] ] ); //all done return mesh; - } else if (uvs.length == 5) { + } else if ( uvs.length == 5 ) { //use the splitcorner to triangulate var il = ids.length; //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 ], 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; } //make point at center of face - var center = this.center(); + var center = this.center( ); - mesh.uvs.push(center.uv); - mesh.points.push(center.point); - mesh.normals.push(center.normal); + mesh.uvs.push( center.uv ); + mesh.points.push( center.point ); + mesh.normals.push( center.normal ); //get index var centerIndex = mesh.points.length - 1; @@ -990,8 +933,8 @@ class AdaptiveRefinementNode { //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++; } diff --git a/src/verb/exe/Dispatcher.hx b/src/verb/exe/Dispatcher.hx index f8698739..3cd19d79 100644 --- a/src/verb/exe/Dispatcher.hx +++ b/src/verb/exe/Dispatcher.hx @@ -22,9 +22,9 @@ class Dispatcher { 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 ); @@ -35,20 +35,20 @@ class Dispatcher { _init = true; } - public static function dispatchMethod(classType : Class, methodName : String, args : Array) : Promise { + public static function dispatchMethod( classType : Class, methodName : String, args : Array ) : Promise { - init(); + init( ); var def = new Deferred(); - var callback = function(x) { - def.resolve(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 57e61566..5a8093d5 100644 --- a/src/verb/exe/ThreadPool.hx +++ b/src/verb/exe/ThreadPool.hx @@ -17,41 +17,41 @@ private class PoolThread { private var _done : Bool; public var done(get, never) : Bool; - private function get_done() : Bool { - mutex.acquire(); + private function get_done( ) : Bool { + mutex.acquire( ); var d : Bool = _done; - mutex.release(); + mutex.release( ); return d; } private var _result : Dynamic; public var result(get, never) : Dynamic; - private function get_result() : Dynamic { - mutex.acquire(); + private function get_result( ) : Dynamic { + mutex.acquire( ); var r : Dynamic = _result; - mutex.release(); + mutex.release( ); return r; } - public function new() { + public function new( ) { mutex = new Mutex(); } - public function start(task : Dynamic -> Dynamic, arg : Dynamic) : Void { + public function start( task : Dynamic -> Dynamic, arg : Dynamic ) : Void { this.task = task; started = true; _done = false; - thread = Thread.create(doWork); - thread.sendMessage(arg); + thread = Thread.create( doWork ); + thread.sendMessage( arg ); } - private function doWork() : Void { - var arg : Dynamic = Thread.readMessage(true); - var ret : Dynamic = task(arg); - mutex.acquire(); + private function doWork( ) : Void { + var arg : Dynamic = Thread.readMessage( true ); + var ret : Dynamic = task( arg ); + mutex.acquire( ); _result = ret; _done = true; - mutex.release(); + mutex.release( ); } } #end @@ -80,24 +80,24 @@ class ThreadPool { private var tasks : Array; private var nextID : Int = 0; - public function new(numThreads : Int) { + 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()); + for ( i in 0...this.numThreads ) { + threads.push( new PoolThread() ); } #end } - 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 } ); + 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++; } #if (neko || cpp) - private function allTasksAreDone():Bool + private function allTasksAreDone( ):Bool { for (task in tasks) if (!task.done) diff --git a/src/verb/exe/WorkerPool.hx b/src/verb/exe/WorkerPool.hx index 233528b8..3a89c1a0 100644 --- a/src/verb/exe/WorkerPool.hx +++ b/src/verb/exe/WorkerPool.hx @@ -23,17 +23,17 @@ class WorkerPool { //* the number of `Worker` threads to form //* the filename of verb's javascript file - defaults to "verb.js". The final path is formed by concatenating `WorkerPool.basePath` and this. - public function new(numThreads : Int = 1, fileName : String = "verb.js") { + 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 ); } } @@ -43,48 +43,48 @@ class WorkerPool { // Add work to perform to the queue - public function addWork(className : String, - methodName : String, - args : Array, - callback : Dynamic) : Void { + public function addWork( className : String, + methodName : String, + args : Array, + callback : Dynamic ) : Void { var work = new Work( className, methodName, args ); - _callbacks.set(work.id, callback); - _queue.push(work); + _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); + _working.remove( workId ); + _pool.push( worker ); try { - if (_callbacks.exists(workId)) { - _callbacks.get(workId)(e.data.result); - _callbacks.remove(workId); + if ( _callbacks.exists( workId ) ) { + _callbacks.get( workId )( e.data.result ); + _callbacks.remove( workId ); } - } catch (error : Dynamic) { - trace(error); + } catch ( error : Dynamic ) { + trace( error ); } - processQueue(); + processQueue( ); }; - worker.postMessage(work); + worker.postMessage( work ); } } @@ -99,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 72ef2813..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; @@ -49,26 +49,26 @@ class Arc extends NurbsCurve { //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/BezierCurve.hx b/src/verb/geom/BezierCurve.hx index a880ab10..3e7e2241 100644 --- a/src/verb/geom/BezierCurve.hx +++ b/src/verb/geom/BezierCurve.hx @@ -17,7 +17,7 @@ class BezierCurve extends NurbsCurve { //* Array of control points //* Array of control point weights (optional) - public function new(points : Array, weights : Array = null) { - super(Make.rationalBezierCurve(points, weights)); + public function new( points : Array, weights : Array = null ) { + super( Make.rationalBezierCurve( points, weights ) ); } } \ No newline at end of file diff --git a/src/verb/geom/Circle.hx b/src/verb/geom/Circle.hx index 4f8187dc..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) { - super(center, xaxis, yaxis, radius, 0, Math.PI * 2); + 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 8f657b58..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; @@ -37,22 +37,22 @@ class ConicalSurface extends NurbsSurface { //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 b7c8a989..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; @@ -39,21 +39,21 @@ class CylindricalSurface extends NurbsSurface { //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 13066b2b..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) { - super(center, xaxis, yaxis, 0, Math.PI * 2); + 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 75cb9f4b..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; @@ -42,23 +42,23 @@ class EllipseArc extends NurbsCurve { //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 5772bbe1..b98815f4 100644 --- a/src/verb/geom/ExtrudedSurface.hx +++ b/src/verb/geom/ExtrudedSurface.hx @@ -15,8 +15,8 @@ class ExtrudedSurface extends NurbsSurface { //* The profile curve //* 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())); + public function new( profile : ICurve, direction : Vector ) { + 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 38cabe4f..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 ]); + 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 ] ); } //Determine the intersection of a curve and a surface @@ -50,14 +50,14 @@ 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); + public static function curveAndSurface( curve : ICurve, surface : ISurface, tol : Float = 1e-3 ) : Array { + 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 ]); + 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 ] ); } //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 b10f05e1..6fc7dade 100644 --- a/src/verb/geom/Line.hx +++ b/src/verb/geom/Line.hx @@ -17,8 +17,8 @@ class Line extends NurbsCurve { //* Length 3 array representing the start point //* Length 3 array representing the end point - public function new(start : Point, end : Point) { - super(Make.polyline([ start, end ])); + public function new( start : Point, end : Point ) { + super( Make.polyline( [ start, end ] ) ); _start = start; _end = end; @@ -29,10 +29,10 @@ class Line extends NurbsCurve { //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 d3bd5c2c..7aad8795 100644 --- a/src/verb/geom/NurbsCurve.hx +++ b/src/verb/geom/NurbsCurve.hx @@ -42,8 +42,8 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public function new(data : NurbsCurveData) { - this._data = Check.isValidNurbsCurveData(data); + public function new( data : NurbsCurveData ) { + this._data = Check.isValidNurbsCurveData( data ); } //Construct a NurbsCurve by degree, knots, control points, weights @@ -59,11 +59,11 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A new NurbsCurve - public static function byKnotsControlPointsWeights(degree : Int, - knots : KnotArray, - controlPoints : Array, - weights : Array = null) : NurbsCurve { - return new NurbsCurve( new NurbsCurveData( degree, knots.copy(), Eval.homogenize1d(controlPoints, weights) ) ); + public static function byKnotsControlPointsWeights( degree : Int, + knots : KnotArray, + controlPoints : Array, + weights : Array = null ) : NurbsCurve { + return new NurbsCurve( new NurbsCurveData( degree, knots.copy( ), Eval.homogenize1d( controlPoints, weights ) ) ); } //Construct a NurbsCurve by interpolating a collection of points. The resultant curve @@ -78,8 +78,8 @@ 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) ); + public static function byPoints( points : Array, degree : Int = 3 ) : NurbsCurve { + return new NurbsCurve( Make.rationalInterpCurve( points, degree ) ); } //underlying serializable, data object @@ -87,19 +87,19 @@ class NurbsCurve extends SerializableBase implements ICurve { //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. // @@ -107,8 +107,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 @@ -117,7 +117,7 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The copied curve - public function clone() { + public function clone( ) { return new NurbsCurve( this._data ); } @@ -127,8 +127,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. @@ -141,15 +141,15 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function transform(mat : Matrix) : NurbsCurve { - return new NurbsCurve( Modify.rationalCurveTransform(_data, mat) ); + public function transform( mat : Matrix ) : NurbsCurve { + return new NurbsCurve( Modify.rationalCurveTransform( _data, mat ) ); } //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); }); + public function transformAsync( mat : Matrix ) : Promise { + return Dispatcher.dispatchMethod( Modify, 'rationalCurveTransform', [ _data, mat ] ) + .then( function( x ) { return new NurbsCurve(x); } ); } //Sample a point at the given parameter @@ -162,14 +162,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function point(u : Float) : Point { - return Eval.rationalCurvePoint(_data, u); + public function point( u : Float ) : Point { + return Eval.rationalCurvePoint( _data, u ); } //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 @@ -183,14 +183,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function tangent(u : Float) : Vector { - return Eval.rationalCurveTangent(_data, u); + public function tangent( u : Float ) : Vector { + return Eval.rationalCurveTangent( _data, u ); } //The async version of `tangent` - public function tangentAsync(u : Float) : Promise { - return Dispatcher.dispatchMethod(Eval, 'rationalCurveTangent', [ _data, u ]); + public function tangentAsync( u : Float ) : Promise { + return Dispatcher.dispatchMethod( Eval, 'rationalCurveTangent', [ _data, u ] ); } //Get derivatives at a given parameter @@ -204,14 +204,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function derivatives(u : Float, numDerivs : Int = 1) : Array { - return Eval.rationalCurveDerivatives(_data, u, numDerivs); + public function derivatives( u : Float, numDerivs : Int = 1 ) : Array { + return Eval.rationalCurveDerivatives( _data, u, numDerivs ); } //The async version of `derivatives` - public function derivativesAsync(u : Float, numDerivs : Int = 1) : Promise> { - return Dispatcher.dispatchMethod(Eval, 'rationalCurveDerivatives', [ _data, u, numDerivs ]); + public function derivativesAsync( u : Float, numDerivs : Int = 1 ) : Promise> { + return Dispatcher.dispatchMethod( Eval, 'rationalCurveDerivatives', [ _data, u, numDerivs ] ); } //Determine the closest point on the curve to the given point @@ -224,14 +224,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The closest point - public function closestPoint(pt : Point) : Point { - return Analyze.rationalCurveClosestPoint(_data, pt); + public function closestPoint( pt : Point ) : Point { + return Analyze.rationalCurveClosestPoint( _data, pt ); } //The async version of `closestPoint` - public function closestPointAsync(pt : Point) : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalCurveClosestPoint', [ _data, pt ]); + public function closestPointAsync( pt : Point ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestPoint', [ _data, pt ] ); } //Determine the closest parameter on the curve to the given point @@ -244,14 +244,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The closest parameter - public function closestParam(pt : Point) : Float { - return Analyze.rationalCurveClosestParam(_data, pt); + public function closestParam( pt : Point ) : Float { + return Analyze.rationalCurveClosestParam( _data, pt ); } //The async version of `length` - public function closestParamAsync(pt : Dynamic) : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalCurveClosestParam', [ _data, pt ]); + public function closestParamAsync( pt : Dynamic ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveClosestParam', [ _data, pt ] ); } //Determine the arc length of the curve @@ -260,14 +260,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve - public function length() : Float { - return Analyze.rationalCurveArcLength(_data); + public function length( ) : Float { + return Analyze.rationalCurveArcLength( _data ); } //The async version of `length` - public function lengthAsync() : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalCurveArcLength', [ _data ]); + public function lengthAsync( ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveArcLength', [ _data ] ); } //Determine the arc length of the curve at the given parameter @@ -280,14 +280,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve at the given parameter - public function lengthAtParam(u : Float) : Float { - return Analyze.rationalCurveArcLength(_data, u); + public function lengthAtParam( u : Float ) : Float { + return Analyze.rationalCurveArcLength( _data, u ); } //The async version of `lengthAtParam` - public function lengthAtParamAsync() : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalCurveArcLength', [ _data ]); + public function lengthAtParamAsync( ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveArcLength', [ _data ] ); } //Determine the parameter of the curve at the given arc length @@ -300,14 +300,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* The length of the curve at the given parameter - public function paramAtLength(len : Float, tolerance : Float = null) : Float { - return Analyze.rationalCurveParamAtArcLength(_data, len, tolerance); + public function paramAtLength( len : Float, tolerance : Float = null ) : Float { + return Analyze.rationalCurveParamAtArcLength( _data, len, tolerance ); } //The async version of `paramAtLength` - public function paramAtLengthAsync(len : Float, tolerance : Float = null) : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalCurveParamAtArcLength', [ _data, len, tolerance ]); + public function paramAtLengthAsync( len : Float, tolerance : Float = null ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalCurveParamAtArcLength', [ _data, len, tolerance ] ); } //Determine the parameters necessary to divide the curve into equal arc length segments @@ -320,14 +320,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A collection of parameters - public function divideByEqualArcLength(divisions : Int) : Array { - return Divide.rationalCurveByEqualArcLength(_data, divisions); + public function divideByEqualArcLength( divisions : Int ) : Array { + return Divide.rationalCurveByEqualArcLength( _data, divisions ); } //The async version of `divideByEqualArcLength`` - public function divideByEqualArcLengthAsync(divisions : Int) : Promise> { - return Dispatcher.dispatchMethod(Divide, 'rationalCurveByEqualArcLength', [ _data, divisions ]); + public function divideByEqualArcLengthAsync( divisions : Int ) : Promise> { + return Dispatcher.dispatchMethod( Divide, 'rationalCurveByEqualArcLength', [ _data, divisions ] ); } //Given the distance to divide the curve, determine the parameters necessary to divide the curve into equal arc length segments @@ -340,14 +340,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A collection of parameters - public function divideByArcLength(arcLength : Float) : Array { - return Divide.rationalCurveByArcLength(_data, arcLength); + public function divideByArcLength( arcLength : Float ) : Array { + return Divide.rationalCurveByArcLength( _data, arcLength ); } //The async version of `divideByArcLength` - public function divideByArcLengthAsync(divisions : Int) : Promise> { - return Dispatcher.dispatchMethod(Divide, 'rationalCurveByArcLength', [ _data, divisions ]); + public function divideByArcLengthAsync( divisions : Int ) : Promise> { + return Dispatcher.dispatchMethod( Divide, 'rationalCurveByArcLength', [ _data, divisions ] ); } //Split the curve at the given parameter @@ -360,17 +360,17 @@ 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); }); + public function split( u : Float ) : Array { + 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); }); - }); + 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); } ); + } ); } //Reverse the parameterization of the curve @@ -379,15 +379,15 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A reversed curve - public function reverse() : NurbsCurve { - return new NurbsCurve( Modify.curveReverse(_data) ); + 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 @@ -400,14 +400,14 @@ class NurbsCurve extends SerializableBase implements ICurve { // //* A point represented as an array - public function tessellate(tolerance : Float = null) : Array { - return Tess.rationalCurveAdaptiveSample(_data, tolerance, false); + public function tessellate( tolerance : Float = null ) : Array { + return Tess.rationalCurveAdaptiveSample( _data, tolerance, false ); } // The async version of `tessellate` - public function tessellateAsync(tolerance : Float = null) : Promise> { - return Dispatcher.dispatchMethod(Tess, 'rationalCurveAdaptiveSample', [ _data, tolerance, false ]); + public function tessellateAsync( tolerance : Float = null ) : Promise> { + return Dispatcher.dispatchMethod( Tess, 'rationalCurveAdaptiveSample', [ _data, tolerance, false ] ); } } diff --git a/src/verb/geom/NurbsSurface.hx b/src/verb/geom/NurbsSurface.hx index d1008370..6caf9c69 100644 --- a/src/verb/geom/NurbsSurface.hx +++ b/src/verb/geom/NurbsSurface.hx @@ -40,8 +40,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public function new(data : NurbsSurfaceData) { - _data = Check.isValidNurbsSurfaceData(data); + public function new( data : NurbsSurfaceData ) { + _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 @@ -82,8 +82,8 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new NurbsSurface - public static function byCorners(point0 : Point, point1 : Point, point2 : Point, point3 : Point) : NurbsSurface { - return new NurbsSurface( Make.fourPointSurface(point0, point1, point2, point3) ); + public static function byCorners( point0 : Point, point1 : Point, point2 : Point, point3 : Point ) : NurbsSurface { + return new NurbsSurface( Make.fourPointSurface( point0, point1, point2, point3 ) ); } //Construct a NurbsSurface by lofting between a collection of curves @@ -96,8 +96,8 @@ 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)); + public static function byLoftingCurves( curves : Array, degreeV : Int = null ) : NurbsSurface { + 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 @@ -180,14 +180,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A point on the surface - public function point(u : Float, v : Float) : Point { - return Eval.rationalSurfacePoint(_data, u, v); + public function point( u : Float, v : Float ) : Point { + return Eval.rationalSurfacePoint( _data, u, v ); } //The async version of `point` - public function pointAsync(u : Float, v : Float) : Promise { - return Dispatcher.dispatchMethod(Eval, 'rationalSurfacePoint', [ _data, u, v ]); + public function pointAsync( u : Float, v : Float ) : Promise { + return Dispatcher.dispatchMethod( Eval, 'rationalSurfacePoint', [ _data, u, v ] ); } //Obtain the normal to the surface at the given parameter @@ -201,14 +201,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A normalized vector normal to the surface - public function normal(u : Float, v : Float) : Point { - return Eval.rationalSurfaceNormal(_data, u, v); + public function normal( u : Float, v : Float ) : Point { + return Eval.rationalSurfaceNormal( _data, u, v ); } //The async version of `normal` - public function normalAsync(u : Float, v : Float) : Promise>> { - return Dispatcher.dispatchMethod(Eval, 'rationalSurfaceNormal', [ _data, u, v ]); + public function normalAsync( u : Float, v : Float ) : Promise>> { + return Dispatcher.dispatchMethod( Eval, 'rationalSurfaceNormal', [ _data, u, v ] ); } //Obtain the derivatives of the NurbsSurface. Returns a two dimensional array @@ -227,14 +227,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A two dimensional array of vectors - public function derivatives(u : Float, v : Float, numDerivs : Int = 1) : Array> { - return Eval.rationalSurfaceDerivatives(_data, u, v, numDerivs); + public function derivatives( u : Float, v : Float, numDerivs : Int = 1 ) : Array> { + return Eval.rationalSurfaceDerivatives( _data, u, v, numDerivs ); } //The async version of `derivatives` - public function derivativesAsync(u : Float, v : Float, numDerivs : Int = 1) : Promise>> { - return Dispatcher.dispatchMethod(Eval, 'rationalSurfaceDerivatives', [ _data, u, v, numDerivs ]); + public function derivativesAsync( u : Float, v : Float, numDerivs : Int = 1 ) : Promise>> { + return Dispatcher.dispatchMethod( Eval, 'rationalSurfaceDerivatives', [ _data, u, v, numDerivs ] ); } @@ -248,14 +248,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The closest point - public function closestParam(pt : Point) : UV { - return Analyze.rationalSurfaceClosestParam(_data, pt); + public function closestParam( pt : Point ) : UV { + return Analyze.rationalSurfaceClosestParam( _data, pt ); } //The async version of `closestParam` - public function closestParamAsync(pt : Point) : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalSurfaceClosestParam', [ _data, pt ]); + public function closestParamAsync( pt : Point ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalSurfaceClosestParam', [ _data, pt ] ); } //Get the closest point on the surface to a point @@ -268,14 +268,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The closest point - public function closestPoint(pt : Point) : Point { - return Analyze.rationalSurfaceClosestPoint(_data, pt); + public function closestPoint( pt : Point ) : Point { + return Analyze.rationalSurfaceClosestPoint( _data, pt ); } //The async version of `closestParam` - public function closestPointAsync(pt : Point) : Promise { - return Dispatcher.dispatchMethod(Analyze, 'rationalSurfaceClosestPoint', [ _data, pt ]); + public function closestPointAsync( pt : Point ) : Promise { + return Dispatcher.dispatchMethod( Analyze, 'rationalSurfaceClosestPoint', [ _data, pt ] ); } //Split a surface @@ -289,18 +289,18 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A length 2 array with two new NurbsSurface objects - public function split(u : Float, useV : Bool = false) : Array { - return Divide.surfaceSplit(_data, u, useV) - .map(function(x) { return new NurbsSurface(x); }); + public function split( u : Float, useV : Bool = false ) : Array { + return Divide.surfaceSplit( _data, u, useV ) + .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); }); - }); + 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); } ); + } ); } //Reverse the parameterization of the curve @@ -313,15 +313,15 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* The reversed surface - public function reverse(useV : Bool = false) : NurbsSurface { - return new NurbsSurface( Modify.surfaceReverse(_data, useV) ); + public function reverse( useV : Bool = false ) : NurbsSurface { + return new NurbsSurface( Modify.surfaceReverse( _data, useV ) ); } //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); }); + public function reverseAsync( useV : Bool = false ) : Promise { + return Dispatcher.dispatchMethod( Modify, 'surfaceReverse', [ _data, useV ] ) + .then( function( c ) { return new NurbsSurface(c); } ); } //Extract an isocurve from a surface @@ -335,15 +335,15 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A NurbsCurve in the provided direction - public function isocurve(u : Float, useV : Bool = false) : NurbsCurve { - return new NurbsCurve( Make.surfaceIsocurve(_data, u, useV) ); + public function isocurve( u : Float, useV : Bool = false ) : NurbsCurve { + return new NurbsCurve( Make.surfaceIsocurve( _data, u, useV ) ); } //The async version of `isocurve` - public function isocurveAsync(u : Float, useV : Bool = false) : Promise { - return Dispatcher.dispatchMethod(Make, 'surfaceIsocurve', [ _data, u, useV ]) - .then(function(x) { return new NurbsCurve(x); }); + public function isocurveAsync( u : Float, useV : Bool = false ) : Promise { + return Dispatcher.dispatchMethod( Make, 'surfaceIsocurve', [ _data, u, useV ] ) + .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); }); - }); + 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); } ); + } ); } @@ -376,14 +376,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A MeshData object - public function tessellate(options : AdaptiveRefinementOptions = null) : MeshData { - return Tess.rationalSurfaceAdaptive(_data, options); + 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 ]); + public function tessellateAsync( options : AdaptiveRefinementOptions = null ) : Promise { + return Dispatcher.dispatchMethod( Tess, 'rationalSurfaceAdaptive', [ _data, options ] ); } //Transform a Surface with the given matrix. @@ -396,14 +396,14 @@ class NurbsSurface extends SerializableBase implements ISurface { // //* A new Surface - public function transform(mat : Matrix) : NurbsSurface { - return new NurbsSurface( Modify.rationalSurfaceTransform(_data, mat) ); + public function transform( mat : Matrix ) : NurbsSurface { + return new NurbsSurface( Modify.rationalSurfaceTransform( _data, mat ) ); } //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); }); + public function transformAsync( mat : Matrix ) : Promise { + 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 3c67951a..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 82d8bf12..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 d27a03f0..6bbc69c4 100644 --- a/src/verb/geom/SweptSurface.hx +++ b/src/verb/geom/SweptSurface.hx @@ -17,8 +17,8 @@ class SweptSurface extends NurbsSurface { //* The profile curve //* The rail curve - public function new(profile : ICurve, rail : ICurve) { - super(Make.rationalTranslationalSurface(profile.asNurbs(), rail.asNurbs())); + public function new( profile : ICurve, rail : ICurve ) { + 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; } } From 8421780c22aaa25af039690260b45125b6851465 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Wed, 11 Nov 2015 10:11:30 -0500 Subject: [PATCH 11/25] Almost done with tolerant sampling --- build/js/verb.js | 303 ++++++++++++++++++---------------- build/js/verbHaxe.js | 303 ++++++++++++++++++---------------- examples/curveStepLength.html | 21 +-- src/verb/eval/Eval.hx | 84 +--------- src/verb/eval/Tess.hx | 133 +++++++++++++-- test/testEval.js | 6 +- 6 files changed, 464 insertions(+), 386 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index 9ffac30b..e0621433 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -4269,99 +4269,6 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { } return position; }; -verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { - var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; - var 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 _g1 = 0; - var _g = beziers.length; - while(_g1 < _g) { - var i = _g1++; - brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; - bsteps = Math.ceil(brange1 / step); - nextU = currentU + bsteps * step; - if(nextU > verb_core_ArrayExtensions.last(beziers[i].knots) + verb_core_Constants.TOLERANCE) { - nextU -= step; - bsteps--; - } - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],pts,currentU,step,bsteps + 1); - currentU = nextU + step; - } - return pts; -}; -verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps) { - 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])); - } -}; verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); var allratders = []; @@ -4450,53 +4357,6 @@ verb_eval_Eval.surfaceRegularSampleDerivatives = function(surface,divsU,divsV,nu } return pts; }; -verb_eval_Eval.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { - return verb_eval_Eval.dehomogenize2d(verb_eval_Eval.surfaceRegularSamplePoints(surface,divsU,divsV)); -}; -verb_eval_Eval.surfaceRegularSamplePoints = 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_Eval.surfaceRegularSamplePoints2 = 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_Eval.rationalCurveRegularSamplePoints(iso,divsV)); - u += t; - } - 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; @@ -6432,6 +6292,122 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalCurveTolerantSample = 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 = 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); + 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); @@ -6700,6 +6676,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.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSamplePoints(surface,divsU,divsV)); +}; +verb_eval_Tess.surfaceRegularSamplePoints = 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.surfaceRegularSamplePoints2 = 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.rationalCurveTolerantSample(iso,divsV)); + u += t; + } + return pts; +}; var verb_eval_AdaptiveRefinementOptions = $hx_exports.core.AdaptiveRefinementOptions = function() { this.minDivsV = 1; this.minDivsU = 1; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 0329616d..15b2fd4f 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -4200,99 +4200,6 @@ verb_eval_Eval.surfacePointGivenNM = function(n,m,surface,u,v) { } return position; }; -verb_eval_Eval.rationalCurveRegularSamplePoints = function(crv,divs) { - var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; - var 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 _g1 = 0; - var _g = beziers.length; - while(_g1 < _g) { - var i = _g1++; - brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; - bsteps = Math.ceil(brange1 / step); - nextU = currentU + bsteps * step; - if(nextU > verb_core_ArrayExtensions.last(beziers[i].knots) + verb_core_Constants.TOLERANCE) { - nextU -= step; - bsteps--; - } - verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate(beziers[i],pts,currentU,step,bsteps + 1); - currentU = nextU + step; - } - return pts; -}; -verb_eval_Eval.rationalBezierCurveRegularSamplePointsMutate = function(crv,pts,startU,step,numSteps) { - 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])); - } -}; verb_eval_Eval.rationalSurfaceRegularSampleDerivatives = function(surface,divsU,divsV,numDerivs) { var allders = verb_eval_Eval.surfaceRegularSampleDerivatives(surface,divsU,divsV,numDerivs); var allratders = []; @@ -4381,53 +4288,6 @@ verb_eval_Eval.surfaceRegularSampleDerivatives = function(surface,divsU,divsV,nu } return pts; }; -verb_eval_Eval.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { - return verb_eval_Eval.dehomogenize2d(verb_eval_Eval.surfaceRegularSamplePoints(surface,divsU,divsV)); -}; -verb_eval_Eval.surfaceRegularSamplePoints = 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_Eval.surfaceRegularSamplePoints2 = 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_Eval.rationalCurveRegularSamplePoints(iso,divsV)); - u += t; - } - 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; @@ -6363,6 +6223,122 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalCurveTolerantSample = 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 = 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); + 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); @@ -6631,6 +6607,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.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSamplePoints(surface,divsU,divsV)); +}; +verb_eval_Tess.surfaceRegularSamplePoints = 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.surfaceRegularSamplePoints2 = 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.rationalCurveTolerantSample(iso,divsV)); + u += t; + } + return pts; +}; var verb_eval_AdaptiveRefinementOptions = $hx_exports.core.AdaptiveRefinementOptions = function() { this.minDivsV = 1; this.minDivsU = 1; diff --git a/examples/curveStepLength.html b/examples/curveStepLength.html index 13f50643..759c3c26 100644 --- a/examples/curveStepLength.html +++ b/examples/curveStepLength.html @@ -42,26 +42,27 @@ return geometry; } - function tessellateRegular( crv, c ){ - return asGeometry( asVector3( verb.eval.Eval.rationalCurveRegularSamplePoints( crv, c ) ) ); - } + function tessellateRegular( crv, tol ){ - var pts = [ [0, 0, 0], [10, 20, 0], [20, 0, 0], [30, 0, 0] ]; - var crv = verb.eval.Make.rationalInterpCurve( pts, 3, false ); + var pts = verb.eval.Tess.rationalCurveTolerantSample( crv, tol ); + console.log( pts.length ); - var tol = 1; + return asGeometry( asVector3( verb.eval.Tess.rationalCurveTolerantSample( crv, tol ) ) ); + } - var l = verb.eval.Tess.rationalBezierCurveStepLength( crv, tol ); + var pts = [ [0, 0, 0], [10, 20, 0], [20, 0, 0], [30, 0, 0], [60,20,0] ]; + var crv = verb.eval.Make.rationalInterpCurve( pts, 3, false ); - addCurveToScene( tessellateRegular(crv, Math.ceil(1 / l)) ); + var tol = 0.01; + addCurveToScene( tessellateRegular(crv, tol ) ); var nc = new verb.geom.NurbsCurve( crv ); - var lineMat2 = new THREE.LineBasicMaterial({ linewidth: 1, color: 0xaaaa00}); + var lineMat2 = new THREE.LineBasicMaterial({ linewidth: 0.1, color: 0xaaaa00}); addCurveToScene( nc.toThreeGeometry(), lineMat2 ); // display the tolerance length - var pts = [ [-5, 0, 0], [-5, tol, 0 ] ]; + var pts = [ [50, 0, 0], [50, tol, 0 ] ]; var tolcrv = verb.geom.NurbsCurve.byPoints( pts, 1 ); addCurveToScene( tolcrv.toThreeGeometry() ); diff --git a/src/verb/eval/Eval.hx b/src/verb/eval/Eval.hx index 41444018..0ac12a18 100644 --- a/src/verb/eval/Eval.hx +++ b/src/verb/eval/Eval.hx @@ -469,87 +469,7 @@ class Eval { return pts; } - // 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 rationalSurfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { - return dehomogenize2d( surfaceRegularSamplePoints( 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 surfaceRegularSamplePoints( 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 = regularlySpacedBasisFunctions( degreeU, knotsU, divsU ) - , knotSpansU = knotSpansBasesU.item0 - , basesU = knotSpansBasesU.item1 - , knotSpansBasesV = 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( surfacePointGivenBasesKnotSpans( degreeU, degreeV, controlPoints, knotSpansU[i], knotSpansV[j], basesU[i], basesV[j], dim ) ); - } - } - - return pts; - } - - public static function surfaceRegularSamplePoints2( 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( rationalCurveRegularSamplePoints( iso, divsV ) ); - u += t; - } - - return pts; - } - - private static function regularlySpacedBasisFunctions( degree : Int, knots : KnotArray, divs : Int ) : Pair, Array>> { + 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; @@ -593,7 +513,7 @@ class Eval { return new Pair, Array>>>( knotspans, bases ); } - private static function surfacePointGivenBasesKnotSpans( degreeU : Int, + public static function surfacePointGivenBasesKnotSpans( degreeU : Int, degreeV : Int, controlPoints : Array>, knotSpanU : Int, diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 6d78ec87..a5fda293 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -24,21 +24,36 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { - public static function rationalCurveRegularSample2( crv : NurbsCurveData, tol : Float ) : Array { + public static function rationalCurveTolerantSample( 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 = Modify.decomposeCurveIntoBeziers( crv ); - var pts = [], steps, domain; + 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; - steps = Math.ceil( domain / rationalBezierCurveStepLength( beziers[i], tol ) ); - - rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, steps ); + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, beziers[i].knots[0], len, steps+1 ); - if ( i != beziers.length - 1 ) break; + if ( i == beziers.length - 1 ) break; pts.pop( ); } @@ -47,13 +62,16 @@ class Tess { private static function rationalBezierCurveRegularSamplePointsMutate( crv : NurbsCurveData, pts : Array, - numSteps : Int ) { + startU : Float, + step : Float, + numSteps : Int, + includeU : Bool = false) : Void { var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; if ( numSteps <= crv.degree + 1 ) { for ( i in 0...numSteps ) { - pts.push( rationalCurvePoint( crv, u ) ); + pts.push( Eval.rationalCurvePoint( crv, u ) ); u += step; } return; @@ -62,7 +80,7 @@ class Tess { // initialize forward differencing for ( i in 0...degree1 ) { - its.push( curvePoint( crv, u ) ); + its.push( Eval.curvePoint( crv, u ) ); u += step; } @@ -83,7 +101,7 @@ class Tess { // evaluate the intial points for ( pt in ts[0] ) { - pts.push( dehomogenize( pt ) ); + pts.push( Eval.dehomogenize( pt ) ); } // evaluate the rest of the points @@ -103,7 +121,17 @@ class Tess { } // add the new pt - pts.push( dehomogenize( front[0] ) ); + pts.push( Eval.dehomogenize( front[0] ) ); + } + + // add the parameters if required + + u = startU; + if (includeU){ + for (pt in pts){ + pt.push(u); + u += step; + } } } @@ -529,6 +557,87 @@ class Tess { 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 rationalSurfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + return Eval.dehomogenize2d( surfaceRegularSamplePoints( 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 surfaceRegularSamplePoints( 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 surfaceRegularSamplePoints2( 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( rationalCurveTolerantSample( iso, divsV ) ); + u += t; + } + + return pts; + } + + } @:expose("core.AdaptiveRefinementOptions") @@ -942,3 +1051,5 @@ class AdaptiveRefinementNode { } } + + diff --git a/test/testEval.js b/test/testEval.js index 5d577485..e5b0c37a 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -3948,12 +3948,12 @@ describe("verb.eval.Modify.decomposeCurveIntoBeziers",() => { }); }); -describe("verb.eval.Eval.rationalCurveRegularSamplePoints",() => { +describe("verb.eval.Tess.rationalCurveRegularSample",() => { function evalAndCompare(crv){ var divs = 100; - var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, divs ); + var p = verb.eval.Tess.rationalCurveRegularSample( crv, divs ); var p2 = []; var sp = 1 / divs; @@ -4000,7 +4000,7 @@ describe("verb.eval.Eval.rationalCurveRegularSamplePoints",() => { }); -describe("verb.eval.Eval.rationalBezierCurveStepLength",() => { +describe("verb.eval.Tess.rationalBezierCurveStepLength",() => { it('works for simple cases', () => { var pts = [ [0, 0, 0], [1, 2, 0], [2, 0, 0], [3, 0, 0] ]; From 801533688e8c9e7375f26dff89aa0f5ae251298c Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Wed, 11 Nov 2015 11:08:57 -0500 Subject: [PATCH 12/25] Fix tests for new adaptive sampling code --- Gruntfile.js | 4 +- build/js/verb.js | 92 +++++++---------- build/js/verbHaxe.js | 92 +++++++---------- examples/curveStepLength.html | 4 +- src/verb/eval/Analyze.hx | 8 +- src/verb/eval/Tess.hx | 184 +++++++++------------------------- src/verb/geom/NurbsCurve.hx | 6 +- test/testEval.js | 30 +++--- test/testGeom.js | 2 +- 9 files changed, 147 insertions(+), 275 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 0c847989..ddf145da 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -43,8 +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/testEval.js'] + src: ['test/testCore.js', 'test/testEval.js', 'test/testGeom.js'] +// src: ['test/testEval.js'] } }, diff --git a/build/js/verb.js b/build/js/verb.js index e0621433..5d14fd0d 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -3790,10 +3790,10 @@ 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 u0 = pts[i1].pop(); + var u11 = pts[i1 + 1].pop(); + var p0 = pts[i1]; + var p1 = pts[i1 + 1]; var proj = verb_core_Trig.segmentClosestPoint(p,p0,p1,u0,u11); var d1 = verb_core_Vec.norm(verb_core_Vec.sub(p,proj.pt)); if(d1 < min) { @@ -6292,7 +6292,35 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalCurveTolerantSample = function(crv,tol,includeU) { +verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { + if(includeU == null) includeU = false; + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var 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 _g1 = 0; + var _g = beziers.length; + while(_g1 < _g) { + var i = _g1++; + brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i],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 = []; @@ -6325,7 +6353,7 @@ verb_eval_Tess.rationalCurveTolerantSample = function(crv,tol,includeU) { 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); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,beziers[i2].knots[0],len,steps + 1,includeU); if(i2 == beziers.length - 1) break; pts.pop(); } @@ -6481,54 +6509,6 @@ verb_eval_Tess.secondForwardDiff2 = function(array) { } return res; }; -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; - var _g = 0; - while(_g < numSamples) { - 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)); - } - return p; -}; -verb_eval_Tess.rationalCurveAdaptiveSample = function(curve,tol,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]))); - } - 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]; -}; verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { if(divs_u < 1) divs_u = 1; if(divs_v < 1) divs_v = 1; @@ -6718,7 +6698,7 @@ verb_eval_Tess.surfaceRegularSamplePoints2 = function(surface,divsU,divsV) { while(_g < divsU) { var i = _g++; var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); - pts.push(verb_eval_Tess.rationalCurveTolerantSample(iso,divsV)); + pts.push(verb_eval_Tess.rationalCurveRegularSample(iso,divsV)); u += t; } return pts; @@ -7194,9 +7174,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/verbHaxe.js b/build/js/verbHaxe.js index 15b2fd4f..2f4c2c43 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -3721,10 +3721,10 @@ 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 u0 = pts[i1].pop(); + var u11 = pts[i1 + 1].pop(); + var p0 = pts[i1]; + var p1 = pts[i1 + 1]; var proj = verb_core_Trig.segmentClosestPoint(p,p0,p1,u0,u11); var d1 = verb_core_Vec.norm(verb_core_Vec.sub(p,proj.pt)); if(d1 < min) { @@ -6223,7 +6223,35 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalCurveTolerantSample = function(crv,tol,includeU) { +verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { + if(includeU == null) includeU = false; + var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; + var 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 _g1 = 0; + var _g = beziers.length; + while(_g1 < _g) { + var i = _g1++; + brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; + bsteps = Math.ceil(brange1 / step); + nextU = currentU + bsteps * step; + if(nextU > verb_core_ArrayExtensions.last(beziers[i].knots) + verb_core_Constants.TOLERANCE) { + nextU -= step; + bsteps--; + } + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i],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 = []; @@ -6256,7 +6284,7 @@ verb_eval_Tess.rationalCurveTolerantSample = function(crv,tol,includeU) { 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); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,beziers[i2].knots[0],len,steps + 1,includeU); if(i2 == beziers.length - 1) break; pts.pop(); } @@ -6412,54 +6440,6 @@ verb_eval_Tess.secondForwardDiff2 = function(array) { } return res; }; -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; - var _g = 0; - while(_g < numSamples) { - 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)); - } - return p; -}; -verb_eval_Tess.rationalCurveAdaptiveSample = function(curve,tol,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]))); - } - 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]; -}; verb_eval_Tess.rationalSurfaceNaive = function(surface,divs_u,divs_v) { if(divs_u < 1) divs_u = 1; if(divs_v < 1) divs_v = 1; @@ -6649,7 +6629,7 @@ verb_eval_Tess.surfaceRegularSamplePoints2 = function(surface,divsU,divsV) { while(_g < divsU) { var i = _g++; var iso = verb_eval_Make.surfaceIsocurve(surface,u,true); - pts.push(verb_eval_Tess.rationalCurveTolerantSample(iso,divsV)); + pts.push(verb_eval_Tess.rationalCurveRegularSample(iso,divsV)); u += t; } return pts; @@ -7125,9 +7105,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/curveStepLength.html b/examples/curveStepLength.html index 759c3c26..d1829aba 100644 --- a/examples/curveStepLength.html +++ b/examples/curveStepLength.html @@ -44,10 +44,10 @@ function tessellateRegular( crv, tol ){ - var pts = verb.eval.Tess.rationalCurveTolerantSample( crv, tol ); + var pts = verb.eval.Tess.rationalCurveRegularSample( crv, 20 ); console.log( pts.length ); - return asGeometry( asVector3( verb.eval.Tess.rationalCurveTolerantSample( crv, tol ) ) ); + return asGeometry( asVector3( verb.eval.Tess.rationalCurveRegularSample( crv, 20 ) ) ); } var pts = [ [0, 0, 0], [10, 20, 0], [20, 0, 0], [30, 0, 0], [60,20,0] ]; diff --git a/src/verb/eval/Analyze.hx b/src/verb/eval/Analyze.hx index 0250503b..60f6cec5 100644 --- a/src/verb/eval/Analyze.hx +++ b/src/verb/eval/Analyze.hx @@ -359,11 +359,11 @@ class Analyze { 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 p1 = pts[i + 1]; var proj = Trig.segmentClosestPoint( p, p0, p1, u0, u1 ); var d = Vec.norm( Vec.sub( p, proj.pt ) ); diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index a5fda293..58fb5ae4 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -5,6 +5,7 @@ using verb.core.ArrayExtensions; import verb.eval.Eval; +import verb.core.Constants; import verb.core.Mat; import verb.core.BoundingBox; import verb.core.Intersections; @@ -24,7 +25,51 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { - public static function rationalCurveTolerantSample( crv : NurbsCurveData, tol : Float, includeU : Bool = false ) : Array { + // 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 representing the curve + //* number of divisions + // + //**returns** + // + //* an array of (divs+1) points + + public static function rationalCurveRegularSample(crv:NurbsCurveData, divs:Int, includeU : Bool = false ):Array { + + var range = crv.knots.last() - crv.knots[0]; + var beziers = 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 ) { @@ -51,7 +96,7 @@ class Tess { steps = Math.ceil( domain / len ); len = domain / steps; - rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, beziers[i].knots[0], len, steps+1 ); + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, beziers[i].knots[0], len, steps+1, includeU ); if ( i == beziers.length - 1 ) break; pts.pop( ); @@ -225,139 +270,6 @@ class Tess { return res; } - //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 rationalCurveRegularSample( curve : NurbsCurveData, numSamples : Int, includeU : Bool ) : Array { - return rationalCurveRegularSampleRange( curve, curve.knots[0], curve.knots.last( ), numSamples, includeU ); - } - - //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 - - public static function rationalCurveRegularSampleRange( curve : NurbsCurveData, start : Float, end : Float, - numSamples : Int, includeU : Bool ) : Array { - - if ( numSamples < 1 ) { - numSamples = 2; - } - - var p = []; - var span : Float = (end - start) / (numSamples - 1); - var u : Float = 0; - - for ( i in 0...numSamples ) { - - u = start + span * i; - - if ( includeU ) { - p.push( [u].concat( Eval.rationalCurvePoint( curve, u ) ) ); - } else { - p.push( Eval.rationalCurvePoint( curve, u ) ); - } - - } - - return p; - } - - - //Sample a NURBS curve over its entire domain, corresponds to [this algorithm](http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf) - // - //**params** - // - //* NurbsCurveData object - //* tol for the adaptive scheme - //* whether to prefix the point with the parameter - // - //**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] ) ) ]; - } - } - - return rationalCurveAdaptiveSampleRange( curve, curve.knots[0], curve.knots.last( ), tol, includeU ); - } - - //Sample a NURBS curve at 3 points, facilitating adaptive sampling - // - //**params** - // - //* NurbsCurveData object - //* start parameter for sampling - //* end parameter for sampling - //* whether to prefix the point with the parameter - // - //**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 rationalCurveAdaptiveSampleRange( curve : NurbsCurveData, start, end, tol, includeU ) : Array { - - //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 ); - - //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 ); - - //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 ) ) { - - //get the exact middle - var exact_mid = start + (end - start) * 0.5; - - //recurse on the two halves - var left_pts = rationalCurveAdaptiveSampleRange( curve, start, exact_mid, tol, includeU ) - , right_pts = rationalCurveAdaptiveSampleRange( curve, exact_mid, end, tol, includeU ); - - //concatenate the two - return left_pts.slice( 0, -1 ).concat( right_pts ); - - } else { - if ( includeU ) { - return [ [ start ].concat( p1 ), [end].concat( p3 ) ]; - } else { - return [ p1, p3 ]; - } - } - } - //Tessellate a NURBS surface on equal spaced intervals in the parametric domain // //**params** @@ -630,7 +542,7 @@ class Tess { for ( i in 0...divsU ) { var iso = Make.surfaceIsocurve( surface, u, true ); - pts.push( rationalCurveTolerantSample( iso, divsV ) ); + pts.push( rationalCurveRegularSample( iso, divsV ) ); u += t; } diff --git a/src/verb/geom/NurbsCurve.hx b/src/verb/geom/NurbsCurve.hx index 7aad8795..2da05f1d 100644 --- a/src/verb/geom/NurbsCurve.hx +++ b/src/verb/geom/NurbsCurve.hx @@ -394,19 +394,19 @@ class NurbsCurve extends SerializableBase implements ICurve { // //**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/test/testEval.js b/test/testEval.js index e5b0c37a..3371f277 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,7 +20,6 @@ function last(a){ return a[a.length-1]; } -/* describe("verb.eval.Eval.knotSpanGivenN",function(){ @@ -1068,7 +1067,7 @@ describe("verb.eval.Divide.surfaceSplit", () => { }); describe("verb.eval.Eval.rationalCurveRegularSample",() => { - it('should return 10 samples when asked to', () => { + it('should return 11 samples when asked to', () => { var degree = 2 , knots = [0, 0, 0, 1, 1, 1 ] @@ -1078,7 +1077,7 @@ describe("verb.eval.Eval.rationalCurveRegularSample",() => { var p = verb.eval.Tess.rationalCurveRegularSample( curve, numSamples); - should.equal(p.length, 10); + should.equal(p.length, 11); p.map( function(e){ e.length.should.be.equal(3); }); @@ -1149,17 +1148,17 @@ describe("verb.eval.Tess.rationalCurveAdaptiveSample",() => { 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[i][3].should.be.above(prev); + p[i][3].should.be.within(-1e-8, 1 + 1e-8); + prev = p[i][3]; } p.should.be.instanceof(Array).and.not.have.lengthOf(0); p2.should.be.instanceof(Array).and.not.have.lengthOf(0); p.should.be.instanceof(Array).and.not.have.lengthOf(p2.length); - should.equal(p[p.length-1][0], 1.0); - should.equal(p2[p2.length-1][0], 1.0); + p[p.length-1][3].should.be.approximately(1.0, 1e-6); + p2[p2.length-1][3].should.be.approximately(1.0, 1e-6); p.map( function(e){ e.length.should.be.equal(4); }); p2.map( function(e){ e.length.should.be.equal(4); }); @@ -1862,7 +1861,7 @@ describe("verb.eval.Analyze.rationalCurveArcLength",() => { var gaussLen = verb.eval.Analyze.rationalCurveArcLength( curve ); // sample the curve with 10,000 pts - var samples = verb.eval.Tess.rationalCurveRegularSampleRange( curve, 0, 1, 10000 ); + var samples = verb.eval.Tess.rationalCurveRegularSample( curve, 10000 ); var red = samples.reduce(function(acc, v){ return { pt: v, l : acc.l + verb.core.Vec.norm( verb.core.Vec.sub( acc.pt, v ) ) }; @@ -3732,8 +3731,8 @@ describe("verb.eval.Make.rationalInterpCurve",() => { 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++){ @@ -3749,7 +3748,6 @@ describe("verb.eval.Make.rationalInterpCurve",() => { if (dist < min) { min = dist; } - } min.should.be.lessThan( 1e-3 ); @@ -3760,13 +3758,12 @@ describe("verb.eval.Make.rationalInterpCurve",() => { it('can compute valid cubic interpolating curve for 4 points', () => { - var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0], [-4,-3, 0] ]; + var pts = [ [0, 0, 1], [3,4, 0], [-1,4, 0], [-4,0, 0] ]; 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] ]; @@ -3827,7 +3824,7 @@ describe("verb.eval.Make.rationalInterpCurve",() => { -describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { +describe("verb.eval.Tess.surfaceRegularSamplePoints",() => { function getComplexSurface(){ @@ -3863,7 +3860,7 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { it('returns correct result for complex surface', () => { - var p = verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 10, 10 ); + var p = verb.eval.Tess.surfaceRegularSamplePoints( complexSurface, 10, 10 ); var ar = []; var sp = 1 / 10; @@ -3891,7 +3888,6 @@ describe("verb.eval.Eval.surfaceRegularSamplePoints",() => { }); }); -*/ describe("verb.eval.Modify.decomposeCurveIntoBeziers",() => { diff --git a/test/testGeom.js b/test/testGeom.js index 6d9b22a0..e0a04105 100755 --- a/test/testGeom.js +++ b/test/testGeom.js @@ -1227,7 +1227,7 @@ 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++){ From ec418faedaaa5e0dd7b764cf230883f477b80969 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Wed, 11 Nov 2015 11:28:41 -0500 Subject: [PATCH 13/25] Some cleanup --- benchmark/regularCurveSampling.js | 4 ++-- benchmark/regularSurfaceSampling.js | 8 ++++---- build/js/verb.js | 8 ++++---- build/js/verbHaxe.js | 8 ++++---- examples/curveStepLength.html | 10 +++------- src/verb/eval/Tess.hx | 8 ++++---- test/testEval.js | 4 ++-- 7 files changed, 23 insertions(+), 27 deletions(-) diff --git a/benchmark/regularCurveSampling.js b/benchmark/regularCurveSampling.js index 075c154e..fc4904d6 100644 --- a/benchmark/regularCurveSampling.js +++ b/benchmark/regularCurveSampling.js @@ -6,8 +6,8 @@ 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: { - 'rationalCurveRegularSamplePoints (6560)': function() { - var p = verb.eval.Eval.rationalCurveRegularSamplePoints( crv, 6560 ); + 'rationalCurveRegularSample (6560)': function() { + var p = verb.eval.Tess.rationalCurveRegularSample( crv, 6560 ); }, 'direct evaluation (6560)': function() { var p = []; diff --git a/benchmark/regularSurfaceSampling.js b/benchmark/regularSurfaceSampling.js index e0ea5e96..04e425e7 100644 --- a/benchmark/regularSurfaceSampling.js +++ b/benchmark/regularSurfaceSampling.js @@ -36,11 +36,11 @@ var complexSurface = getComplexSurface(); module.exports = { name: 'Regular surface sampling', tests: { - 'surfaceRegularSamplePoints2 (80 x 80)': function() { - verb.eval.Eval.surfaceRegularSamplePoints2( complexSurface, 80, 80 ); + 'surfaceRegularSample2 (80 x 80)': function() { + verb.eval.Tess.surfaceRegularSample2( complexSurface, 80, 80 ); }, - 'surfaceRegularSamplePoints (80 x 80)': function() { - verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 80, 80 ); + 'surfaceRegularSample (80 x 80)': function() { + verb.eval.Tess.surfaceRegularSample( complexSurface, 80, 80 ); }, 'direct evaluation (80 x 80)': function() { var ar = []; diff --git a/build/js/verb.js b/build/js/verb.js index 5d14fd0d..26564429 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -6656,10 +6656,10 @@ verb_eval_Tess.rationalSurfaceAdaptive = function(surface,options) { var arrTrees = verb_eval_Tess.divideRationalSurfaceAdaptive(surface,options); return verb_eval_Tess.triangulateAdaptiveRefinementNodeTree(arrTrees); }; -verb_eval_Tess.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { - return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSamplePoints(surface,divsU,divsV)); +verb_eval_Tess.rationalSurfaceRegularSample = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSample(surface,divsU,divsV)); }; -verb_eval_Tess.surfaceRegularSamplePoints = function(surface,divsU,divsV) { +verb_eval_Tess.surfaceRegularSample = function(surface,divsU,divsV) { var degreeU = surface.degreeU; var degreeV = surface.degreeV; var controlPoints = surface.controlPoints; @@ -6690,7 +6690,7 @@ verb_eval_Tess.surfaceRegularSamplePoints = function(surface,divsU,divsV) { } return pts; }; -verb_eval_Tess.surfaceRegularSamplePoints2 = function(surface,divsU,divsV) { +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; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 2f4c2c43..4d632a11 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -6587,10 +6587,10 @@ verb_eval_Tess.rationalSurfaceAdaptive = function(surface,options) { var arrTrees = verb_eval_Tess.divideRationalSurfaceAdaptive(surface,options); return verb_eval_Tess.triangulateAdaptiveRefinementNodeTree(arrTrees); }; -verb_eval_Tess.rationalSurfaceRegularSamplePoints = function(surface,divsU,divsV) { - return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSamplePoints(surface,divsU,divsV)); +verb_eval_Tess.rationalSurfaceRegularSample = function(surface,divsU,divsV) { + return verb_eval_Eval.dehomogenize2d(verb_eval_Tess.surfaceRegularSample(surface,divsU,divsV)); }; -verb_eval_Tess.surfaceRegularSamplePoints = function(surface,divsU,divsV) { +verb_eval_Tess.surfaceRegularSample = function(surface,divsU,divsV) { var degreeU = surface.degreeU; var degreeV = surface.degreeV; var controlPoints = surface.controlPoints; @@ -6621,7 +6621,7 @@ verb_eval_Tess.surfaceRegularSamplePoints = function(surface,divsU,divsV) { } return pts; }; -verb_eval_Tess.surfaceRegularSamplePoints2 = function(surface,divsU,divsV) { +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; diff --git a/examples/curveStepLength.html b/examples/curveStepLength.html index d1829aba..55ee0e8c 100644 --- a/examples/curveStepLength.html +++ b/examples/curveStepLength.html @@ -43,22 +43,18 @@ } function tessellateRegular( crv, tol ){ - - var pts = verb.eval.Tess.rationalCurveRegularSample( crv, 20 ); - console.log( pts.length ); - - return asGeometry( asVector3( verb.eval.Tess.rationalCurveRegularSample( crv, 20 ) ) ); + return asGeometry( asVector3( verb.eval.Tess.rationalCurveAdaptiveSample( crv, tol ) ) ); } var pts = [ [0, 0, 0], [10, 20, 0], [20, 0, 0], [30, 0, 0], [60,20,0] ]; var crv = verb.eval.Make.rationalInterpCurve( pts, 3, false ); - var tol = 0.01; + var tol = 2; addCurveToScene( tessellateRegular(crv, tol ) ); var nc = new verb.geom.NurbsCurve( crv ); - var lineMat2 = new THREE.LineBasicMaterial({ linewidth: 0.1, color: 0xaaaa00}); + var lineMat2 = new THREE.LineBasicMaterial({ linewidth: 1, color: 0xaaaa00}); addCurveToScene( nc.toThreeGeometry(), lineMat2 ); // display the tolerance length diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 58fb5ae4..48d02eed 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -482,8 +482,8 @@ class Tess { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function rationalSurfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { - return Eval.dehomogenize2d( surfaceRegularSamplePoints( surface, divsU, divsV ) ); + 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 @@ -499,7 +499,7 @@ class Tess { // //* a 2d array of dimension (divsU+1, divsV+1) of points - public static function surfaceRegularSamplePoints( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + public static function surfaceRegularSample( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { var degreeU = surface.degreeU , degreeV = surface.degreeV @@ -532,7 +532,7 @@ class Tess { return pts; } - public static function surfaceRegularSamplePoints2( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { + public static function surfaceRegularSample2( surface : NurbsSurfaceData, divsU : Int, divsV : Int ) : Array> { var pts = []; diff --git a/test/testEval.js b/test/testEval.js index 3371f277..a0bfd39b 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -3824,7 +3824,7 @@ describe("verb.eval.Make.rationalInterpCurve",() => { -describe("verb.eval.Tess.surfaceRegularSamplePoints",() => { +describe("verb.eval.Tess.surfaceRegularSample",() => { function getComplexSurface(){ @@ -3860,7 +3860,7 @@ describe("verb.eval.Tess.surfaceRegularSamplePoints",() => { it('returns correct result for complex surface', () => { - var p = verb.eval.Tess.surfaceRegularSamplePoints( complexSurface, 10, 10 ); + var p = verb.eval.Tess.surfaceRegularSample( complexSurface, 10, 10 ); var ar = []; var sp = 1 / 10; From c56474cd76804f2de489da30ea95c3fbfb9713f7 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Thu, 12 Nov 2015 18:07:47 -0500 Subject: [PATCH 14/25] rationalBezierSurfaceStepLength --- Gruntfile.js | 4 +- build/js/verb.js | 118 +++++++++++++++++++++++ build/js/verbHaxe.js | 118 +++++++++++++++++++++++ examples/js/verbToThreeConversion.js | 2 +- examples/surfaceStepLength.html | 115 ++++++++++++++++++++++ src/verb/eval/Tess.hx | 136 +++++++++++++++++++++++++++ test/testEval.js | 42 +++++++++ 7 files changed, 532 insertions(+), 3 deletions(-) create mode 100644 examples/surfaceStepLength.html diff --git a/Gruntfile.js b/Gruntfile.js index ddf145da..8d9b7094 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -43,8 +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/testEval.js'] + //src: ['test/testCore.js', 'test/testEval.js', 'test/testGeom.js'] + src: ['test/testEval.js'] } }, diff --git a/build/js/verb.js b/build/js/verb.js index 26564429..d9344c7f 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -6292,6 +6292,124 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalSurfaceAdaptiveSample = function(surface,divs,includeU) { + if(includeU == null) includeU = false; + return null; +}; +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; var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 4d632a11..6fbe6603 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -6223,6 +6223,124 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalSurfaceAdaptiveSample = function(surface,divs,includeU) { + if(includeU == null) includeU = false; + return null; +}; +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; var range = verb_core_ArrayExtensions.last(crv.knots) - crv.knots[0]; diff --git a/examples/js/verbToThreeConversion.js b/examples/js/verbToThreeConversion.js index 36e2f0c5..69382b00 100644 --- a/examples/js/verbToThreeConversion.js +++ b/examples/js/verbToThreeConversion.js @@ -28,7 +28,7 @@ function tessellateSurface(srf) { - var tess = srf.tessellate(); + var tess = srf.tessellate({ normTol : 0.0001 }); var geometry = new THREE.Geometry(); var threePts = asVector3( tess.points ); 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/eval/Tess.hx b/src/verb/eval/Tess.hx index 48d02eed..50969e0a 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -25,6 +25,142 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { + + public static function rationalSurfaceAdaptiveSample(surface:NurbsSurfaceData, divs:Int, includeU : Bool = false ) : MeshData { + + return null; + + } + + 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 ); + } + + // 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 diff --git a/test/testEval.js b/test/testEval.js index a0bfd39b..bfa2b24d 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,6 +20,7 @@ function last(a){ return a[a.length-1]; } +/* describe("verb.eval.Eval.knotSpanGivenN",function(){ @@ -4008,3 +4009,44 @@ describe("verb.eval.Tess.rationalBezierCurveStepLength",() => { }); }); +*/ + +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 ); + + }); +}); + + + From 7722fdf121161d246e7ea1a9c465da4bf1af2457 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Thu, 12 Nov 2015 22:33:05 -0500 Subject: [PATCH 15/25] Improved surface knot refinement --- benchmark/surfaceKnotRefinement.js | 33 +++ benchmark/surfaceTessellation.js | 59 +++++ build/js/verb.js | 165 ++++++++++++- build/js/verbHaxe.js | 165 ++++++++++++- examples/js/threeBasic.js | 2 +- src/verb/eval/Modify.hx | 159 +++++++++++- src/verb/eval/Tess.hx | 8 +- test/testEval.js | 375 +++++++++++++++++++---------- 8 files changed, 809 insertions(+), 157 deletions(-) create mode 100644 benchmark/surfaceKnotRefinement.js create mode 100644 benchmark/surfaceTessellation.js diff --git a/benchmark/surfaceKnotRefinement.js b/benchmark/surfaceKnotRefinement.js new file mode 100644 index 00000000..45185c35 --- /dev/null +++ b/benchmark/surfaceKnotRefinement.js @@ -0,0 +1,33 @@ + +var Benchmark = require('benchmark') + , verb = require('../build/js/verb.js'); + +function getComplexSurface(){ + + 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 ); + + + return surface; +} + +module.exports = { + name: 'Surface knot refinement', + tests: { + 'surfaceKnotRefine2': function() { + verb.eval.Modify.surfaceKnotRefine2( getComplexSurface(), [0.2], false ); + }, + 'surfaceKnotRefine': function() { + verb.eval.Modify.surfaceKnotRefine( getComplexSurface(), [0.2], false ); + } + } +}; + diff --git a/benchmark/surfaceTessellation.js b/benchmark/surfaceTessellation.js new file mode 100644 index 00000000..04e425e7 --- /dev/null +++ b/benchmark/surfaceTessellation.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/build/js/verb.js b/build/js/verb.js index d9344c7f..01e4efb5 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -6101,14 +6101,14 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { var knots; var degree; var ctrlPts; - if(!useV) { - ctrlPts = verb_core_Mat.transpose(surface.controlPoints); - knots = surface.knotsU; - degree = surface.degreeU; - } else { + if(useV) { ctrlPts = surface.controlPoints; knots = surface.knotsV; degree = surface.degreeV; + } else { + ctrlPts = verb_core_Mat.transpose(surface.controlPoints); + knots = surface.knotsU; + degree = surface.degreeU; } var c = null; var _g = 0; @@ -6119,10 +6119,156 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { newPts.push(c.controlPoints); } var newknots = c.knots; - if(!useV) { + if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),newknots,newPts); else { 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); + } +}; +verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { + 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 _g1 = 0; + var _g = n + r; + 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.length; + while(_g17 < _g9) { + var ci1 = _g17++; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi]; + } + } else controlPoints_post[wi] = controlPoints[xi].slice(0); + knots_post[k] = knots[i]; + k--; + i--; + } + if(useV) { + var _g18 = 0; + var _g10 = controlPoints.length; + while(_g18 < _g10) { + var ci2 = _g18++; + controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree]; + } + } 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.length; + while(_g32 < _g23) { + var ci3 = _g32++; + controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; + } + } else controlPoints_post[ind - 1] = controlPoints_post[ind]; + } else { + alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); + if(useV) { + var _g33 = 0; + var _g24 = controlPoints.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 - 1].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) { + return null; }; verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { var degree = curve.degree; @@ -6208,7 +6354,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]; @@ -6292,8 +6438,7 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalSurfaceAdaptiveSample = function(surface,divs,includeU) { - if(includeU == null) includeU = false; +verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { return null; }; verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 6fbe6603..09200f26 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -6032,14 +6032,14 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { var knots; var degree; var ctrlPts; - if(!useV) { - ctrlPts = verb_core_Mat.transpose(surface.controlPoints); - knots = surface.knotsU; - degree = surface.degreeU; - } else { + if(useV) { ctrlPts = surface.controlPoints; knots = surface.knotsV; degree = surface.degreeV; + } else { + ctrlPts = verb_core_Mat.transpose(surface.controlPoints); + knots = surface.knotsU; + degree = surface.degreeU; } var c = null; var _g = 0; @@ -6050,10 +6050,156 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { newPts.push(c.controlPoints); } var newknots = c.knots; - if(!useV) { + if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),newknots,newPts); else { 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); + } +}; +verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { + 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 _g1 = 0; + var _g = n + r; + 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.length; + while(_g17 < _g9) { + var ci1 = _g17++; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi]; + } + } else controlPoints_post[wi] = controlPoints[xi].slice(0); + knots_post[k] = knots[i]; + k--; + i--; + } + if(useV) { + var _g18 = 0; + var _g10 = controlPoints.length; + while(_g18 < _g10) { + var ci2 = _g18++; + controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree]; + } + } 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.length; + while(_g32 < _g23) { + var ci3 = _g32++; + controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; + } + } else controlPoints_post[ind - 1] = controlPoints_post[ind]; + } else { + alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); + if(useV) { + var _g33 = 0; + var _g24 = controlPoints.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 - 1].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) { + return null; }; verb_eval_Modify.decomposeCurveIntoBeziers = function(curve) { var degree = curve.degree; @@ -6139,7 +6285,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]; @@ -6223,8 +6369,7 @@ verb_eval_Modify.curveKnotInsert = function(curve,u,r) { 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.rationalSurfaceAdaptiveSample = function(surface,divs,includeU) { - if(includeU == null) includeU = false; +verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { return null; }; verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { 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/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index 6adeb781..fae5e53a 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -400,15 +400,14 @@ class Modify { , ctrlPts; //u dir - if ( !useV ) { - ctrlPts = Mat.transpose( surface.controlPoints ); - knots = surface.knotsU; - degree = surface.degreeU; - //v dir - } else { + if ( useV ) { ctrlPts = surface.controlPoints; knots = surface.knotsV; degree = surface.degreeV; + } else { + ctrlPts = Mat.transpose( surface.controlPoints ); + knots = surface.knotsU; + degree = surface.degreeU; } //do knot refinement on every row @@ -420,14 +419,150 @@ class Modify { var newknots = c.knots; - //u dir - if ( !useV ) { + if ( useV ) { + return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), newknots, newPts ); + } else { newPts = Mat.transpose( newPts ); return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy( ), newPts ); - //v dir + } + } + + public static function surfaceKnotRefine2( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { + +// if ( knotsToInsert.length == 0 ) return Make.clonedCurve( curve ); + + var degree, controlPoints = surface.controlPoints, knots; + + if (useV){ + degree = surface.degreeV; + knots = surface.knotsV; } else { - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), newknots, newPts ); + degree = surface.degreeU; + 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){ + for (i in 0...n+r){ + 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 { + 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]; } + + for ( i in b + degree...m + 1 ) { + knots_post[i + r + 1] = knots[i]; + } + + 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.length){ + controlPoints_post[ci][wi] = controlPoints[ci][xi]; + } + } else { + controlPoints_post[wi] = controlPoints[xi].slice(0); + } + + knots_post[k] = knots[i]; + k--; + i--; + } + + if (useV){ + for (ci in 0...controlPoints.length){ + controlPoints_post[ci][k - degree - 1] = controlPoints_post[ci][k - degree]; + } + } 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 ) { + if (useV){ + for (ci in 0...controlPoints.length){ + controlPoints_post[ci][ind - 1] = controlPoints_post[ci][ind]; + } + } else { + controlPoints_post[ind - 1] = controlPoints_post[ind]; + } + } else { + alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); + + if (useV){ + for (wi in 0...controlPoints.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 - 1].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, knots_post, surface.knotsV.copy(), controlPoints_post ); + } + } + + public static function decomposeSurfaceIntoBeziers( surface : NurbsSurfaceData ) : Array> { + return null; } //Decompose a NURBS curve into a collection of bezier's. Useful @@ -558,9 +693,7 @@ class Modify { } else { 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] ); } } diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 50969e0a..fe84f41e 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -25,8 +25,13 @@ import verb.core.Trig; @:expose("eval.Tess") class Tess { + public static function rationalSurfaceAdaptiveSample(surface:NurbsSurfaceData, tol : Float ) : MeshData { - public static function rationalSurfaceAdaptiveSample(surface:NurbsSurfaceData, divs:Int, includeU : Bool = false ) : MeshData { + // split into bezier patches + + // get step lengths for patches + + // tessellate patches, merging into a single mesh return null; @@ -160,7 +165,6 @@ class Tess { return new Pair( stepu, stepv ); } - // 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 diff --git a/test/testEval.js b/test/testEval.js index bfa2b24d..f3cce547 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -779,57 +779,6 @@ describe("verb.eval.Modify.curveKnotInsert",() => { }); }); -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.Divide.curveSplit",() => { @@ -911,76 +860,6 @@ describe("verb.core.Mat.transpose",() => { }); }); -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 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); - - - }); -}); describe("verb.eval.Divide.surfaceSplit", () => { @@ -4050,3 +3929,257 @@ describe("verb.eval.Tess.rationalBezierSurfaceStepLength",() => { +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 ); + + console.log( res.controlPoints[0].length, res.controlPoints.length ); + + 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.surfaceKnotRefine2",() => { + + 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.surfaceKnotRefine2( surface, new_knots, false ); + console.log( res.controlPoints[0].length, res.controlPoints.length ); + + 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 = 2; + var u = 0.2; + var new_knots = []; + + for (var i = 0; i < r; i++){ + new_knots.push(u); + } + + var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, false ); + console.log( res.controlPoints[0].length, res.controlPoints.length ); + + 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.surfaceKnotRefine2( 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 = 2; + var u = 0.2; + var new_knots = []; + + for (var i = 0; i < r; i++){ + new_knots.push(u); + } + + var res = verb.eval.Modify.surfaceKnotRefine2( 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); + + }); +}); \ No newline at end of file From c12e15cd81efb221746c73e4dd629965b6dcf2f8 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Fri, 13 Nov 2015 17:01:50 -0500 Subject: [PATCH 16/25] Fixed issue with surfaceKnotRefine2 --- build/js/verb.js | 124 ++++++++++++++++++++------------------- build/js/verbHaxe.js | 124 ++++++++++++++++++++------------------- src/verb/eval/Analyze.hx | 1 + src/verb/eval/Modify.hx | 37 +++++++----- test/testEval.js | 8 +-- 5 files changed, 150 insertions(+), 144 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index 01e4efb5..4ccd9327 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -3793,8 +3793,9 @@ verb_eval_Analyze.rationalCurveClosestParam = function(curve,p) { 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,p0,p1,u0,u11); + 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; @@ -6143,62 +6144,63 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); var controlPoints_post = []; var knots_post = []; + var _g1 = 0; + var _g = a + 1; + while(_g1 < _g) { + var i1 = _g1++; + knots_post[i1] = knots[i1]; + } + var _g11 = b + degree; + var _g2 = m + 1; + while(_g11 < _g2) { + var i2 = _g11++; + knots_post[i2 + r + 1] = knots[i2]; + } if(useV) { - var _g1 = 0; - var _g = n + r; - while(_g1 < _g) { - var i1 = _g1++; + var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); + var _g12 = 0; + var _g3 = n + km.length - 1; + while(_g12 < _g3) { + var i3 = _g12++; controlPoints_post.push([]); } - var _g11 = 0; - var _g2 = a - degree + 1; - while(_g11 < _g2) { - var i2 = _g11++; - var _g3 = 0; + var _g13 = 0; + var _g4 = a - degree + 1; + while(_g13 < _g4) { + var i4 = _g13++; + var _g31 = 0; var _g21 = controlPoints.length; - while(_g3 < _g21) { - var j1 = _g3++; - controlPoints_post[j1][i2] = controlPoints[j1][i2]; + while(_g31 < _g21) { + var j1 = _g31++; + controlPoints_post[j1][i4] = controlPoints[j1][i4]; } } - var _g12 = b - 1; - var _g4 = n + 1; - while(_g12 < _g4) { - var i3 = _g12++; - var l = i3 + r + 1; - var _g31 = 0; + var _g14 = b - 1; + var _g5 = n + 1; + while(_g14 < _g5) { + var i5 = _g14++; + var l = i5 + r + 1; + var _g32 = 0; var _g22 = controlPoints.length; - while(_g31 < _g22) { - var j2 = _g31++; - controlPoints_post[j2][l] = controlPoints[j2][i3]; + while(_g32 < _g22) { + var j2 = _g32++; + controlPoints_post[j2][l] = controlPoints[j2][i5]; } } } else { - var _g13 = 0; - var _g5 = a - degree + 1; - while(_g13 < _g5) { - var i4 = _g13++; - controlPoints_post[i4] = controlPoints[i4].slice(0); + var _g15 = 0; + var _g6 = a - degree + 1; + while(_g15 < _g6) { + var i6 = _g15++; + controlPoints_post[i6] = controlPoints[i6].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 _g16 = b - 1; + var _g7 = n + 1; + while(_g16 < _g7) { + var i7 = _g16++; + controlPoints_post[i7 + r + 1] = controlPoints[i7].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; @@ -6209,8 +6211,8 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { var xi = i - degree - 1; if(useV) { var _g17 = 0; - var _g9 = controlPoints.length; - while(_g17 < _g9) { + var _g8 = controlPoints_post.length; + while(_g17 < _g8) { var ci1 = _g17++; controlPoints_post[ci1][wi] = controlPoints[ci1][xi]; } @@ -6221,41 +6223,41 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { } if(useV) { var _g18 = 0; - var _g10 = controlPoints.length; - while(_g18 < _g10) { + var _g9 = controlPoints_post.length; + while(_g18 < _g9) { var ci2 = _g18++; controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree]; } } else controlPoints_post[k - degree - 1] = controlPoints_post[k - degree].slice(0); var _g19 = 1; - var _g20 = degree + 1; - while(_g19 < _g20) { + var _g10 = degree + 1; + while(_g19 < _g10) { 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.length; - while(_g32 < _g23) { - var ci3 = _g32++; + var _g33 = 0; + var _g23 = controlPoints_post.length; + while(_g33 < _g23) { + var ci3 = _g33++; controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; } } else controlPoints_post[ind - 1] = controlPoints_post[ind]; } else { alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); if(useV) { - var _g33 = 0; - var _g24 = controlPoints.length; - while(_g33 < _g24) { - var wi1 = _g33++; + var _g34 = 0; + var _g24 = controlPoints_post.length; + while(_g34 < _g24) { + var wi1 = _g34++; controlPoints_post[wi1][ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[wi1][ind - 1],controlPoints_post[wi1][ind]); } } else { - var _g34 = 0; + var _g35 = 0; var _g25 = controlPoints_post[ind - 1].length; - while(_g34 < _g25) { - var wi2 = _g34++; + while(_g35 < _g25) { + var wi2 = _g35++; controlPoints_post[ind - 1][wi2] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1][wi2],controlPoints_post[ind][wi2]); } } diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 09200f26..bf1dd9c7 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -3724,8 +3724,9 @@ verb_eval_Analyze.rationalCurveClosestParam = function(curve,p) { 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,p0,p1,u0,u11); + 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; @@ -6074,62 +6075,63 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); var controlPoints_post = []; var knots_post = []; + var _g1 = 0; + var _g = a + 1; + while(_g1 < _g) { + var i1 = _g1++; + knots_post[i1] = knots[i1]; + } + var _g11 = b + degree; + var _g2 = m + 1; + while(_g11 < _g2) { + var i2 = _g11++; + knots_post[i2 + r + 1] = knots[i2]; + } if(useV) { - var _g1 = 0; - var _g = n + r; - while(_g1 < _g) { - var i1 = _g1++; + var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); + var _g12 = 0; + var _g3 = n + km.length - 1; + while(_g12 < _g3) { + var i3 = _g12++; controlPoints_post.push([]); } - var _g11 = 0; - var _g2 = a - degree + 1; - while(_g11 < _g2) { - var i2 = _g11++; - var _g3 = 0; + var _g13 = 0; + var _g4 = a - degree + 1; + while(_g13 < _g4) { + var i4 = _g13++; + var _g31 = 0; var _g21 = controlPoints.length; - while(_g3 < _g21) { - var j1 = _g3++; - controlPoints_post[j1][i2] = controlPoints[j1][i2]; + while(_g31 < _g21) { + var j1 = _g31++; + controlPoints_post[j1][i4] = controlPoints[j1][i4]; } } - var _g12 = b - 1; - var _g4 = n + 1; - while(_g12 < _g4) { - var i3 = _g12++; - var l = i3 + r + 1; - var _g31 = 0; + var _g14 = b - 1; + var _g5 = n + 1; + while(_g14 < _g5) { + var i5 = _g14++; + var l = i5 + r + 1; + var _g32 = 0; var _g22 = controlPoints.length; - while(_g31 < _g22) { - var j2 = _g31++; - controlPoints_post[j2][l] = controlPoints[j2][i3]; + while(_g32 < _g22) { + var j2 = _g32++; + controlPoints_post[j2][l] = controlPoints[j2][i5]; } } } else { - var _g13 = 0; - var _g5 = a - degree + 1; - while(_g13 < _g5) { - var i4 = _g13++; - controlPoints_post[i4] = controlPoints[i4].slice(0); + var _g15 = 0; + var _g6 = a - degree + 1; + while(_g15 < _g6) { + var i6 = _g15++; + controlPoints_post[i6] = controlPoints[i6].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 _g16 = b - 1; + var _g7 = n + 1; + while(_g16 < _g7) { + var i7 = _g16++; + controlPoints_post[i7 + r + 1] = controlPoints[i7].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; @@ -6140,8 +6142,8 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { var xi = i - degree - 1; if(useV) { var _g17 = 0; - var _g9 = controlPoints.length; - while(_g17 < _g9) { + var _g8 = controlPoints_post.length; + while(_g17 < _g8) { var ci1 = _g17++; controlPoints_post[ci1][wi] = controlPoints[ci1][xi]; } @@ -6152,41 +6154,41 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { } if(useV) { var _g18 = 0; - var _g10 = controlPoints.length; - while(_g18 < _g10) { + var _g9 = controlPoints_post.length; + while(_g18 < _g9) { var ci2 = _g18++; controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree]; } } else controlPoints_post[k - degree - 1] = controlPoints_post[k - degree].slice(0); var _g19 = 1; - var _g20 = degree + 1; - while(_g19 < _g20) { + var _g10 = degree + 1; + while(_g19 < _g10) { 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.length; - while(_g32 < _g23) { - var ci3 = _g32++; + var _g33 = 0; + var _g23 = controlPoints_post.length; + while(_g33 < _g23) { + var ci3 = _g33++; controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; } } else controlPoints_post[ind - 1] = controlPoints_post[ind]; } else { alfa = alfa / (knots_post[k + l1] - knots[i - degree + l1]); if(useV) { - var _g33 = 0; - var _g24 = controlPoints.length; - while(_g33 < _g24) { - var wi1 = _g33++; + var _g34 = 0; + var _g24 = controlPoints_post.length; + while(_g34 < _g24) { + var wi1 = _g34++; controlPoints_post[wi1][ind - 1] = verb_core_Vec.lerp(alfa,controlPoints_post[wi1][ind - 1],controlPoints_post[wi1][ind]); } } else { - var _g34 = 0; + var _g35 = 0; var _g25 = controlPoints_post[ind - 1].length; - while(_g34 < _g25) { - var wi2 = _g34++; + while(_g35 < _g25) { + var wi2 = _g35++; controlPoints_post[ind - 1][wi2] = verb_core_Vec.lerp(alfa,controlPoints_post[ind - 1][wi2],controlPoints_post[ind][wi2]); } } diff --git a/src/verb/eval/Analyze.hx b/src/verb/eval/Analyze.hx index 60f6cec5..62ef00fb 100644 --- a/src/verb/eval/Analyze.hx +++ b/src/verb/eval/Analyze.hx @@ -362,6 +362,7 @@ class Analyze { var u0 = pts[i].pop(); var u1 = pts[i + 1].pop(); + var p0 = pts[i]; var p0 = pts[i]; var p1 = pts[i + 1]; diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index fae5e53a..c7cbbc54 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -429,7 +429,7 @@ class Modify { public static function surfaceKnotRefine2( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { -// if ( knotsToInsert.length == 0 ) return Make.clonedCurve( curve ); +// if ( knotsToInsert.length == 0 ) return Make.clonedSurface( surface ); var degree, controlPoints = surface.controlPoints, knots; @@ -449,10 +449,25 @@ class Modify { , controlPoints_post = new Array>() , knots_post = new KnotArray(); + //new knot vector + + 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]; + } + //new control pts if (useV){ - for (i in 0...n+r){ + + // count unique elements in knot collection + + var km = Analyze.knotMultiplicities( knotsToInsert ); + + for (i in 0...n + km.length - 1 ){ controlPoints_post.push([]); } @@ -478,16 +493,6 @@ class Modify { } } - //new knot vector - - 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]; - } - var i = b + degree - 1; var k = b + degree + r; var j = r; @@ -499,7 +504,7 @@ class Modify { var xi = i - degree - 1; if (useV){ - for (ci in 0...controlPoints.length){ + for (ci in 0...controlPoints_post.length){ controlPoints_post[ci][wi] = controlPoints[ci][xi]; } } else { @@ -512,7 +517,7 @@ class Modify { } if (useV){ - for (ci in 0...controlPoints.length){ + for (ci in 0...controlPoints_post.length){ controlPoints_post[ci][k - degree - 1] = controlPoints_post[ci][k - degree]; } } else { @@ -526,7 +531,7 @@ class Modify { if ( Math.abs( alfa ) < Constants.EPSILON ) { if (useV){ - for (ci in 0...controlPoints.length){ + for (ci in 0...controlPoints_post.length){ controlPoints_post[ci][ind - 1] = controlPoints_post[ci][ind]; } } else { @@ -536,7 +541,7 @@ class Modify { alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); if (useV){ - for (wi in 0...controlPoints.length){ + for (wi in 0...controlPoints_post.length){ controlPoints_post[wi][ind - 1] = Vec.lerp( alfa, controlPoints_post[wi][ind - 1], controlPoints_post[wi][ind] ); } diff --git a/test/testEval.js b/test/testEval.js index f3cce547..4f94e2e6 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -4007,8 +4007,6 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { var res = verb.eval.Modify.surfaceKnotRefine( surface, new_knots, false ); - console.log( res.controlPoints[0].length, res.controlPoints.length ); - res.controlPoints.forEach(function(cp){ should.exist(cp); }); res.knotsU.forEach(function(cp){ should.exist(cp); }); res.knotsV.forEach(function(cp){ should.exist(cp); }); @@ -4079,7 +4077,6 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { } var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, false ); - console.log( res.controlPoints[0].length, res.controlPoints.length ); res.controlPoints.forEach(function(cp){ should.exist(cp); }); res.knotsU.forEach(function(cp){ should.exist(cp); }); @@ -4099,7 +4096,7 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { it('can add multiple knots into a surface in the u direction', () => { - var r = 2; + var r = 3; var u = 0.2; var new_knots = []; @@ -4108,7 +4105,6 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { } var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, false ); - console.log( res.controlPoints[0].length, res.controlPoints.length ); res.controlPoints.forEach(function(cp){ should.exist(cp); }); res.knotsU.forEach(function(cp){ should.exist(cp); }); @@ -4157,7 +4153,7 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { it('can add multiple duplicate knots into a surface in the v direction', () => { - var r = 2; + var r = 4; var u = 0.2; var new_knots = []; From 72f06e564024f33cec3c1e1b9285bc8ec7b272e8 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Mon, 16 Nov 2015 23:16:22 -0500 Subject: [PATCH 17/25] Fix issues with improved surface knot refinement methods --- build/js/verb.js | 50 ++++++++++------------ build/js/verbHaxe.js | 50 ++++++++++------------ src/verb/eval/Make.hx | 17 ++++++++ src/verb/eval/Modify.hx | 80 ++++++++++++++++++------------------ test/testEval.js | 91 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 182 insertions(+), 106 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index 4ccd9327..c0433cac 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -5419,6 +5419,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 = []; @@ -6098,34 +6117,7 @@ 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; - var degree; - var ctrlPts; - if(useV) { - ctrlPts = surface.controlPoints; - knots = surface.knotsV; - degree = surface.degreeV; - } else { - ctrlPts = verb_core_Mat.transpose(surface.controlPoints); - knots = surface.knotsU; - degree = surface.degreeU; - } - var c = null; - var _g = 0; - while(_g < ctrlPts.length) { - var cptrow = ctrlPts[_g]; - ++_g; - c = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,cptrow),knotsToInsert); - newPts.push(c.controlPoints); - } - var newknots = c.knots; - if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),newknots,newPts); else { - newPts = verb_core_Mat.transpose(newPts); - return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,newknots,surface.knotsV.slice(),newPts); - } -}; -verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { + if(knotsToInsert.length == 0) return verb_eval_Make.clonedSurface(surface); var degree; var controlPoints = surface.controlPoints; var knots; @@ -6159,7 +6151,7 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { if(useV) { var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); var _g12 = 0; - var _g3 = n + km.length - 1; + var _g3 = controlPoints.length + km.length - 1; while(_g12 < _g3) { var i3 = _g12++; controlPoints_post.push([]); diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index bf1dd9c7..49eb5e36 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -5350,6 +5350,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 = []; @@ -6029,34 +6048,7 @@ 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; - var degree; - var ctrlPts; - if(useV) { - ctrlPts = surface.controlPoints; - knots = surface.knotsV; - degree = surface.degreeV; - } else { - ctrlPts = verb_core_Mat.transpose(surface.controlPoints); - knots = surface.knotsU; - degree = surface.degreeU; - } - var c = null; - var _g = 0; - while(_g < ctrlPts.length) { - var cptrow = ctrlPts[_g]; - ++_g; - c = verb_eval_Modify.curveKnotRefine(new verb_core_NurbsCurveData(degree,knots,cptrow),knotsToInsert); - newPts.push(c.controlPoints); - } - var newknots = c.knots; - if(useV) return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,surface.knotsU.slice(),newknots,newPts); else { - newPts = verb_core_Mat.transpose(newPts); - return new verb_core_NurbsSurfaceData(surface.degreeU,surface.degreeV,newknots,surface.knotsV.slice(),newPts); - } -}; -verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { + if(knotsToInsert.length == 0) return verb_eval_Make.clonedSurface(surface); var degree; var controlPoints = surface.controlPoints; var knots; @@ -6090,7 +6082,7 @@ verb_eval_Modify.surfaceKnotRefine2 = function(surface,knotsToInsert,useV) { if(useV) { var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); var _g12 = 0; - var _g3 = n + km.length - 1; + var _g3 = controlPoints.length + km.length - 1; while(_g12 < _g3) { var i3 = _g12++; controlPoints_post.push([]); diff --git a/src/verb/eval/Make.hx b/src/verb/eval/Make.hx index c0ec6bc7..646c72c3 100644 --- a/src/verb/eval/Make.hx +++ b/src/verb/eval/Make.hx @@ -156,6 +156,23 @@ class Make { 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** diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index c7cbbc54..2ac25f05 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -389,47 +389,47 @@ class Modify { // //* A new NURBS surface with the knots inserted - 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 - - var newPts = [] - , knots - , degree - , ctrlPts; - - //u dir - if ( useV ) { - ctrlPts = surface.controlPoints; - knots = surface.knotsV; - degree = surface.degreeV; - } else { - ctrlPts = Mat.transpose( surface.controlPoints ); - knots = surface.knotsU; - degree = surface.degreeU; - } - - //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 ); - } - - var newknots = c.knots; - - if ( useV ) { - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), newknots, newPts ); - } else { - newPts = Mat.transpose( newPts ); - return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy( ), newPts ); - } - } +// 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 +// +// var newPts = [] +// , knots +// , degree +// , ctrlPts; +// +// //u dir +// if ( useV ) { +// ctrlPts = surface.controlPoints; +// knots = surface.knotsV; +// degree = surface.degreeV; +// } else { +// ctrlPts = Mat.transpose( surface.controlPoints ); +// knots = surface.knotsU; +// degree = surface.degreeU; +// } +// +// //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 ); +// } +// +// var newknots = c.knots; +// +// if ( useV ) { +// return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), newknots, newPts ); +// } else { +// newPts = Mat.transpose( newPts ); +// return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy( ), newPts ); +// } +// } - public static function surfaceKnotRefine2( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { + public static function surfaceKnotRefine( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { -// if ( knotsToInsert.length == 0 ) return Make.clonedSurface( surface ); + if ( knotsToInsert.length == 0 ) return Make.clonedSurface( surface ); var degree, controlPoints = surface.controlPoints, knots; @@ -467,7 +467,7 @@ class Modify { var km = Analyze.knotMultiplicities( knotsToInsert ); - for (i in 0...n + km.length - 1 ){ + for (i in 0...controlPoints.length + km.length - 1 ){ controlPoints_post.push([]); } diff --git a/test/testEval.js b/test/testEval.js index 4f94e2e6..fc7aec10 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,8 +20,6 @@ function last(a){ return a[a.length-1]; } -/* - describe("verb.eval.Eval.knotSpanGivenN",function(){ it('returns correct result', () => { @@ -3888,7 +3886,7 @@ describe("verb.eval.Tess.rationalBezierCurveStepLength",() => { }); }); -*/ + describe("verb.eval.Tess.rationalBezierSurfaceStepLength",() => { @@ -4053,7 +4051,7 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { }); -describe("verb.eval.Modify.surfaceKnotRefine2",() => { +describe("verb.eval.Modify.surfaceKnotRefine",() => { var degree = 3 , knotsV = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1] @@ -4076,7 +4074,7 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { new_knots.push(u); } - var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, false ); + 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); }); @@ -4104,7 +4102,7 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { new_knots.push(u); } - var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, false ); + 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); }); @@ -4132,7 +4130,7 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { new_knots.push(u); } - var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, true ); + 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); }); @@ -4161,7 +4159,7 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { new_knots.push(u); } - var res = verb.eval.Modify.surfaceKnotRefine2( surface, new_knots, true ); + 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); }); @@ -4178,4 +4176,81 @@ describe("verb.eval.Modify.surfaceKnotRefine2",() => { 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 ); + + 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 ); + + 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); + + }); + }); \ No newline at end of file From e8e19f934223e13a6b097469fe9fc0a051a1dcc5 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Mon, 16 Nov 2015 23:17:20 -0500 Subject: [PATCH 18/25] Delete old surface refinement code --- src/verb/eval/Modify.hx | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index 2ac25f05..cdcbc3bf 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -389,44 +389,6 @@ class Modify { // //* A new NURBS surface with the knots inserted -// 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 -// -// var newPts = [] -// , knots -// , degree -// , ctrlPts; -// -// //u dir -// if ( useV ) { -// ctrlPts = surface.controlPoints; -// knots = surface.knotsV; -// degree = surface.degreeV; -// } else { -// ctrlPts = Mat.transpose( surface.controlPoints ); -// knots = surface.knotsU; -// degree = surface.degreeU; -// } -// -// //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 ); -// } -// -// var newknots = c.knots; -// -// if ( useV ) { -// return new NurbsSurfaceData( surface.degreeU, surface.degreeV, surface.knotsU.copy( ), newknots, newPts ); -// } else { -// newPts = Mat.transpose( newPts ); -// return new NurbsSurfaceData( surface.degreeU, surface.degreeV, newknots, surface.knotsV.copy( ), newPts ); -// } -// } - public static function surfaceKnotRefine( surface : NurbsSurfaceData, knotsToInsert : Array, useV : Bool ) : NurbsSurfaceData { if ( knotsToInsert.length == 0 ) return Make.clonedSurface( surface ); From c8eeb39006d99cba5b32f1f904a668fb05598175 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Sun, 22 Nov 2015 22:28:52 -0500 Subject: [PATCH 19/25] Complete algorithm for fast tessellation by forward differencing --- benchmark/surfaceKnotRefinement.js | 33 -- build/js/verb.js | 506 +++++++++++++++++---- build/js/verbHaxe.js | 506 +++++++++++++++++---- examples/surfaceAdaptiveTessellation2.html | 167 +++++++ examples/surfaceBezierSubdivision.html | 134 ++++++ src/verb/eval/Make.hx | 2 +- src/verb/eval/Modify.hx | 112 ++++- src/verb/eval/Tess.hx | 456 ++++++++++++++++--- test/testEval.js | 128 +++++- 9 files changed, 1782 insertions(+), 262 deletions(-) delete mode 100644 benchmark/surfaceKnotRefinement.js create mode 100644 examples/surfaceAdaptiveTessellation2.html create mode 100644 examples/surfaceBezierSubdivision.html diff --git a/benchmark/surfaceKnotRefinement.js b/benchmark/surfaceKnotRefinement.js deleted file mode 100644 index 45185c35..00000000 --- a/benchmark/surfaceKnotRefinement.js +++ /dev/null @@ -1,33 +0,0 @@ - -var Benchmark = require('benchmark') - , verb = require('../build/js/verb.js'); - -function getComplexSurface(){ - - 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 ); - - - return surface; -} - -module.exports = { - name: 'Surface knot refinement', - tests: { - 'surfaceKnotRefine2': function() { - verb.eval.Modify.surfaceKnotRefine2( getComplexSurface(), [0.2], false ); - }, - 'surfaceKnotRefine': function() { - verb.eval.Modify.surfaceKnotRefine( getComplexSurface(), [0.2], false ); - } - } -}; - diff --git a/build/js/verb.js b/build/js/verb.js index c0433cac..105b65da 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -324,6 +324,12 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; +var haxe_Log = function() { }; +$hxClasses["haxe.Log"] = haxe_Log; +haxe_Log.__name__ = ["haxe","Log"]; +haxe_Log.trace = function(v,infos) { + js_Boot.__trace(v,infos); +}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -1058,6 +1064,25 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; +js_Boot.__unhtml = function(s) { + return s.split("&").join("&").split("<").join("<").split(">").join(">"); +}; +js_Boot.__trace = function(v,i) { + var msg; + if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; + msg += js_Boot.__string_rec(v,""); + if(i != null && i.customParams != null) { + var _g = 0; + var _g1 = i.customParams; + while(_g < _g1.length) { + var v1 = _g1[_g]; + ++_g; + msg += "," + js_Boot.__string_rec(v1,""); + } + } + var d; + if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); +}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1933,7 +1958,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"); + haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -6136,63 +6161,63 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); var controlPoints_post = []; var knots_post = []; - var _g1 = 0; - var _g = a + 1; - while(_g1 < _g) { - var i1 = _g1++; - knots_post[i1] = knots[i1]; - } - var _g11 = b + degree; - var _g2 = m + 1; - while(_g11 < _g2) { - var i2 = _g11++; - knots_post[i2 + r + 1] = knots[i2]; - } if(useV) { var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); - var _g12 = 0; - var _g3 = controlPoints.length + km.length - 1; - while(_g12 < _g3) { - var i3 = _g12++; + var _g1 = 0; + var _g = controlPoints.length + km.length - 1; + while(_g1 < _g) { + var i1 = _g1++; controlPoints_post.push([]); } - var _g13 = 0; - var _g4 = a - degree + 1; - while(_g13 < _g4) { - var i4 = _g13++; - var _g31 = 0; + var _g11 = 0; + var _g2 = a - degree + 1; + while(_g11 < _g2) { + var i2 = _g11++; + var _g3 = 0; var _g21 = controlPoints.length; - while(_g31 < _g21) { - var j1 = _g31++; - controlPoints_post[j1][i4] = controlPoints[j1][i4]; + while(_g3 < _g21) { + var j1 = _g3++; + controlPoints_post[j1][i2] = controlPoints[j1][i2]; } } - var _g14 = b - 1; - var _g5 = n + 1; - while(_g14 < _g5) { - var i5 = _g14++; - var l = i5 + r + 1; - var _g32 = 0; + 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(_g32 < _g22) { - var j2 = _g32++; - controlPoints_post[j2][l] = controlPoints[j2][i5]; + while(_g31 < _g22) { + var j2 = _g31++; + controlPoints_post[j2][l] = controlPoints[j2][i3]; } } } else { - var _g15 = 0; - var _g6 = a - degree + 1; - while(_g15 < _g6) { - var i6 = _g15++; - controlPoints_post[i6] = controlPoints[i6].slice(0); + var _g13 = 0; + var _g5 = a - degree + 1; + while(_g13 < _g5) { + var i4 = _g13++; + controlPoints_post[i4] = controlPoints[i4].slice(0); } - var _g16 = b - 1; - var _g7 = n + 1; - while(_g16 < _g7) { - var i7 = _g16++; - controlPoints_post[i7 + r + 1] = controlPoints[i7].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; @@ -6203,53 +6228,53 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { var xi = i - degree - 1; if(useV) { var _g17 = 0; - var _g8 = controlPoints_post.length; - while(_g17 < _g8) { + var _g9 = controlPoints_post.length; + while(_g17 < _g9) { var ci1 = _g17++; - controlPoints_post[ci1][wi] = controlPoints[ci1][xi]; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi].slice(0); } } else controlPoints_post[wi] = controlPoints[xi].slice(0); knots_post[k] = knots[i]; - k--; - i--; + k = k - 1; + i = i - 1; } if(useV) { var _g18 = 0; - var _g9 = controlPoints_post.length; - while(_g18 < _g9) { + var _g10 = controlPoints_post.length; + while(_g18 < _g10) { var ci2 = _g18++; - controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree]; + 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 _g10 = degree + 1; - while(_g19 < _g10) { + 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 _g33 = 0; + var _g32 = 0; var _g23 = controlPoints_post.length; - while(_g33 < _g23) { - var ci3 = _g33++; + while(_g32 < _g23) { + var ci3 = _g32++; controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; } - } else controlPoints_post[ind - 1] = controlPoints_post[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 _g34 = 0; + var _g33 = 0; var _g24 = controlPoints_post.length; - while(_g34 < _g24) { - var wi1 = _g34++; + 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 _g35 = 0; - var _g25 = controlPoints_post[ind - 1].length; - while(_g35 < _g25) { - var wi2 = _g35++; + 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]); } } @@ -6262,7 +6287,60 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { 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) { - return null; + 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; @@ -6276,6 +6354,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; @@ -6429,11 +6508,260 @@ 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.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) { - return null; + var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); + haxe_Log.trace(beziers.length,{ fileName : "Tess.hx", lineNumber : 91, className : "verb.eval.Tess", methodName : "rationalSurfaceAdaptiveSample", customParams : [beziers[0].length]}); + 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; + stepLengthRow.push(verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol)); + } + } + var pts = []; + 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; + 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; + 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; + 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; + 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); + 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,null); +}; +verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tessStep,edgeSide) { + var edgeIndices; + var knots; + var reverseFace = false; + var tessIStep = 1; + switch(edgeSide[1]) { + case 0: + edgeIndices = bei.n; + knots = bezier.knotsV; + break; + case 1: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV + 1); + reverseFace = true; + break; + case 2: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV + 1; + p0 += divsV; + break; + case 3: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV + 1; + reverseFace = true; + 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; + haxe_Log.trace("edgeCount",{ fileName : "Tess.hx", lineNumber : 318, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeCount]}); + haxe_Log.trace("divsU",{ fileName : "Tess.hx", lineNumber : 319, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsU]}); + haxe_Log.trace("divsV",{ fileName : "Tess.hx", lineNumber : 320, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsV]}); + haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 322, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); + haxe_Log.trace("edgeStep",{ fileName : "Tess.hx", lineNumber : 323, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeStep]}); + haxe_Log.trace("tessStep",{ fileName : "Tess.hx", lineNumber : 324, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessStep]}); + haxe_Log.trace("tessU",{ fileName : "Tess.hx", lineNumber : 326, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessU]}); + haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 327, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); + haxe_Log.trace("tessI",{ fileName : "Tess.hx", lineNumber : 329, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessI]}); + haxe_Log.trace("tessIStep",{ fileName : "Tess.hx", lineNumber : 330, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessIStep]}); + while(edgeI < edgeCount) { + while(edgeU < tessU - verb_core_Constants.EPSILON && edgeI < edgeCount) { + 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]); + } + 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); @@ -6551,8 +6879,27 @@ verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { }; 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 = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + 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; @@ -6561,18 +6908,18 @@ verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { var brange1; var bsteps; var nextU; - var _g1 = 0; - var _g = beziers.length; - while(_g1 < _g) { - var i = _g1++; - brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; + 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[i].knots) + verb_core_Constants.TOLERANCE) { + if(nextU > verb_core_ArrayExtensions.last(beziers[i2].knots) + verb_core_Constants.TOLERANCE) { nextU -= step; bsteps--; } - verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i],pts,currentU,step,bsteps + 1,includeU); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,currentU,step,bsteps + 1,includeU); currentU = nextU + step; } return pts; @@ -6597,7 +6944,8 @@ verb_eval_Tess.rationalCurveAdaptiveSample = function(crv,tol,includeU) { } return pts1; } - var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + 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; @@ -6789,8 +7137,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]; @@ -7276,7 +7624,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - console.log(error); + haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 81, className : "verb.exe.WorkerPool", methodName : "processQueue"}); } _g.processQueue(); }; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 49eb5e36..2e7d33d3 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -255,6 +255,12 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; +var haxe_Log = function() { }; +$hxClasses["haxe.Log"] = haxe_Log; +haxe_Log.__name__ = ["haxe","Log"]; +haxe_Log.trace = function(v,infos) { + js_Boot.__trace(v,infos); +}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -989,6 +995,25 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; +js_Boot.__unhtml = function(s) { + return s.split("&").join("&").split("<").join("<").split(">").join(">"); +}; +js_Boot.__trace = function(v,i) { + var msg; + if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; + msg += js_Boot.__string_rec(v,""); + if(i != null && i.customParams != null) { + var _g = 0; + var _g1 = i.customParams; + while(_g < _g1.length) { + var v1 = _g1[_g]; + ++_g; + msg += "," + js_Boot.__string_rec(v1,""); + } + } + var d; + if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); +}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1864,7 +1889,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"); + haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -6067,63 +6092,63 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { var b = verb_eval_Eval.knotSpan(degree,knotsToInsert[r],knots); var controlPoints_post = []; var knots_post = []; - var _g1 = 0; - var _g = a + 1; - while(_g1 < _g) { - var i1 = _g1++; - knots_post[i1] = knots[i1]; - } - var _g11 = b + degree; - var _g2 = m + 1; - while(_g11 < _g2) { - var i2 = _g11++; - knots_post[i2 + r + 1] = knots[i2]; - } if(useV) { var km = verb_eval_Analyze.knotMultiplicities(knotsToInsert); - var _g12 = 0; - var _g3 = controlPoints.length + km.length - 1; - while(_g12 < _g3) { - var i3 = _g12++; + var _g1 = 0; + var _g = controlPoints.length + km.length - 1; + while(_g1 < _g) { + var i1 = _g1++; controlPoints_post.push([]); } - var _g13 = 0; - var _g4 = a - degree + 1; - while(_g13 < _g4) { - var i4 = _g13++; - var _g31 = 0; + var _g11 = 0; + var _g2 = a - degree + 1; + while(_g11 < _g2) { + var i2 = _g11++; + var _g3 = 0; var _g21 = controlPoints.length; - while(_g31 < _g21) { - var j1 = _g31++; - controlPoints_post[j1][i4] = controlPoints[j1][i4]; + while(_g3 < _g21) { + var j1 = _g3++; + controlPoints_post[j1][i2] = controlPoints[j1][i2]; } } - var _g14 = b - 1; - var _g5 = n + 1; - while(_g14 < _g5) { - var i5 = _g14++; - var l = i5 + r + 1; - var _g32 = 0; + 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(_g32 < _g22) { - var j2 = _g32++; - controlPoints_post[j2][l] = controlPoints[j2][i5]; + while(_g31 < _g22) { + var j2 = _g31++; + controlPoints_post[j2][l] = controlPoints[j2][i3]; } } } else { - var _g15 = 0; - var _g6 = a - degree + 1; - while(_g15 < _g6) { - var i6 = _g15++; - controlPoints_post[i6] = controlPoints[i6].slice(0); + var _g13 = 0; + var _g5 = a - degree + 1; + while(_g13 < _g5) { + var i4 = _g13++; + controlPoints_post[i4] = controlPoints[i4].slice(0); } - var _g16 = b - 1; - var _g7 = n + 1; - while(_g16 < _g7) { - var i7 = _g16++; - controlPoints_post[i7 + r + 1] = controlPoints[i7].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; @@ -6134,53 +6159,53 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { var xi = i - degree - 1; if(useV) { var _g17 = 0; - var _g8 = controlPoints_post.length; - while(_g17 < _g8) { + var _g9 = controlPoints_post.length; + while(_g17 < _g9) { var ci1 = _g17++; - controlPoints_post[ci1][wi] = controlPoints[ci1][xi]; + controlPoints_post[ci1][wi] = controlPoints[ci1][xi].slice(0); } } else controlPoints_post[wi] = controlPoints[xi].slice(0); knots_post[k] = knots[i]; - k--; - i--; + k = k - 1; + i = i - 1; } if(useV) { var _g18 = 0; - var _g9 = controlPoints_post.length; - while(_g18 < _g9) { + var _g10 = controlPoints_post.length; + while(_g18 < _g10) { var ci2 = _g18++; - controlPoints_post[ci2][k - degree - 1] = controlPoints_post[ci2][k - degree]; + 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 _g10 = degree + 1; - while(_g19 < _g10) { + 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 _g33 = 0; + var _g32 = 0; var _g23 = controlPoints_post.length; - while(_g33 < _g23) { - var ci3 = _g33++; + while(_g32 < _g23) { + var ci3 = _g32++; controlPoints_post[ci3][ind - 1] = controlPoints_post[ci3][ind]; } - } else controlPoints_post[ind - 1] = controlPoints_post[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 _g34 = 0; + var _g33 = 0; var _g24 = controlPoints_post.length; - while(_g34 < _g24) { - var wi1 = _g34++; + 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 _g35 = 0; - var _g25 = controlPoints_post[ind - 1].length; - while(_g35 < _g25) { - var wi2 = _g35++; + 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]); } } @@ -6193,7 +6218,60 @@ verb_eval_Modify.surfaceKnotRefine = function(surface,knotsToInsert,useV) { 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) { - return null; + 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; @@ -6207,6 +6285,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; @@ -6360,11 +6439,260 @@ 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.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) { - return null; + var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); + haxe_Log.trace(beziers.length,{ fileName : "Tess.hx", lineNumber : 91, className : "verb.eval.Tess", methodName : "rationalSurfaceAdaptiveSample", customParams : [beziers[0].length]}); + 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; + stepLengthRow.push(verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol)); + } + } + var pts = []; + 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; + 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; + 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; + 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; + 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); + 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,null); +}; +verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tessStep,edgeSide) { + var edgeIndices; + var knots; + var reverseFace = false; + var tessIStep = 1; + switch(edgeSide[1]) { + case 0: + edgeIndices = bei.n; + knots = bezier.knotsV; + break; + case 1: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV + 1); + reverseFace = true; + break; + case 2: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV + 1; + p0 += divsV; + break; + case 3: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV + 1; + reverseFace = true; + 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; + haxe_Log.trace("edgeCount",{ fileName : "Tess.hx", lineNumber : 318, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeCount]}); + haxe_Log.trace("divsU",{ fileName : "Tess.hx", lineNumber : 319, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsU]}); + haxe_Log.trace("divsV",{ fileName : "Tess.hx", lineNumber : 320, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsV]}); + haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 322, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); + haxe_Log.trace("edgeStep",{ fileName : "Tess.hx", lineNumber : 323, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeStep]}); + haxe_Log.trace("tessStep",{ fileName : "Tess.hx", lineNumber : 324, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessStep]}); + haxe_Log.trace("tessU",{ fileName : "Tess.hx", lineNumber : 326, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessU]}); + haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 327, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); + haxe_Log.trace("tessI",{ fileName : "Tess.hx", lineNumber : 329, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessI]}); + haxe_Log.trace("tessIStep",{ fileName : "Tess.hx", lineNumber : 330, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessIStep]}); + while(edgeI < edgeCount) { + while(edgeU < tessU - verb_core_Constants.EPSILON && edgeI < edgeCount) { + 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]); + } + 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); @@ -6482,8 +6810,27 @@ verb_eval_Tess.rationalBezierSurfaceStepLength = function(surface,tol) { }; 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 = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + 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; @@ -6492,18 +6839,18 @@ verb_eval_Tess.rationalCurveRegularSample = function(crv,divs,includeU) { var brange1; var bsteps; var nextU; - var _g1 = 0; - var _g = beziers.length; - while(_g1 < _g) { - var i = _g1++; - brange1 = verb_core_ArrayExtensions.last(beziers[i].knots) - currentU; + 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[i].knots) + verb_core_Constants.TOLERANCE) { + if(nextU > verb_core_ArrayExtensions.last(beziers[i2].knots) + verb_core_Constants.TOLERANCE) { nextU -= step; bsteps--; } - verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i],pts,currentU,step,bsteps + 1,includeU); + verb_eval_Tess.rationalBezierCurveRegularSamplePointsMutate(beziers[i2],pts,currentU,step,bsteps + 1,includeU); currentU = nextU + step; } return pts; @@ -6528,7 +6875,8 @@ verb_eval_Tess.rationalCurveAdaptiveSample = function(crv,tol,includeU) { } return pts1; } - var beziers = verb_eval_Modify.decomposeCurveIntoBeziers(crv); + 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; @@ -6720,8 +7068,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]; @@ -7207,7 +7555,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - console.log(error); + haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 81, className : "verb.exe.WorkerPool", methodName : "processQueue"}); } _g.processQueue(); }; diff --git a/examples/surfaceAdaptiveTessellation2.html b/examples/surfaceAdaptiveTessellation2.html new file mode 100644 index 00000000..f17820a7 --- /dev/null +++ b/examples/surfaceAdaptiveTessellation2.html @@ -0,0 +1,167 @@ + + + + Surface Bezier Subdivision + + + + + + + + + + + + + + + + + +
Show/Hide Code
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/examples/surfaceBezierSubdivision.html b/examples/surfaceBezierSubdivision.html new file mode 100644 index 00000000..95396054 --- /dev/null +++ b/examples/surfaceBezierSubdivision.html @@ -0,0 +1,134 @@ + + + + Surface Bezier Subdivision + + + + + + + + + + + + + + + + + +
Show/Hide Code
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/src/verb/eval/Make.hx b/src/verb/eval/Make.hx index 646c72c3..66e94624 100644 --- a/src/verb/eval/Make.hx +++ b/src/verb/eval/Make.hx @@ -143,7 +143,7 @@ class Make { 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 diff --git a/src/verb/eval/Modify.hx b/src/verb/eval/Modify.hx index cdcbc3bf..774e78cd 100644 --- a/src/verb/eval/Modify.hx +++ b/src/verb/eval/Modify.hx @@ -411,16 +411,6 @@ class Modify { , controlPoints_post = new Array>() , knots_post = new KnotArray(); - //new knot vector - - 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]; - } - //new control pts if (useV){ @@ -455,32 +445,43 @@ class Modify { } } + //new knot vector + + 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]; + } + 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]; + controlPoints_post[ci][wi] = controlPoints[ci][xi].slice(0); } } else { controlPoints_post[wi] = controlPoints[xi].slice(0); } knots_post[k] = knots[i]; - k--; - 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]; + 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); @@ -492,12 +493,13 @@ class Modify { var alfa = knots_post[k + l] - knotsToInsert[j]; if ( Math.abs( alfa ) < Constants.EPSILON ) { + 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]; + controlPoints_post[ind - 1] = controlPoints_post[ind].slice(0); } } else { alfa = alfa / (knots_post[k + l] - knots[i - degree + l]); @@ -508,7 +510,7 @@ class Modify { Vec.lerp( alfa, controlPoints_post[wi][ind - 1], controlPoints_post[wi][ind] ); } } else { - for (wi in 0...controlPoints_post[ind - 1].length){ + 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] ); } } @@ -529,9 +531,83 @@ class Modify { } public static function decomposeSurfaceIntoBeziers( surface : NurbsSurfaceData ) : Array> { - return null; + + //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 @@ -561,6 +637,8 @@ class Modify { 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; diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index fe84f41e..eee2625e 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -22,21 +22,362 @@ 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 { - public static function rationalSurfaceAdaptiveSample(surface:NurbsSurfaceData, tol : Float ) : MeshData { + public static function rationalBezierSurfaceRegularSample( 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 ); + var v = (iso.knots.last( ) - iso.knots[0]) / divsV; + rationalBezierCurveRegularSamplePointsMutate( iso, pts, iso.knots[0], t, divsV, false ); + u += t; + } + + return pts; + } + + private static function northIndex( i, j, divs : Array> ) { + if ( i <= 0 ) return null; + return divs[ i - 1 ][ j ]; + } + + 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]; + } + + private static function westIndex( i, j, divs : Array> ) { + if ( j <= 0 ) return null; + return divs[ i ][j - 1]; + } + + public static function rationalSurfaceAdaptiveSample( surface : NurbsSurfaceData, tol : Float ) : MeshData { // split into bezier patches + var beziers = Modify.decomposeSurfaceIntoBeziers( surface ); + + trace(beziers.length, beziers[0].length); + // get step lengths for patches + var stepLengths : Array>> = [] + , stepLengthRow; + + for ( bezierrow in beziers ) { + stepLengthRow = []; + stepLengths.push( stepLengthRow ); + + for ( bezier in bezierrow ) { + stepLengthRow.push( rationalBezierSurfaceStepLength( bezier, tol ) ); + } + } + + var pts = [], + 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; + + // should be ( beziers.length + 1, beziers[0].length + 1 ) + + 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 ); + + e0 = pts.length; + + rationalBezierCurveRegularSamplePointsMutate2( ne, pts, stepLengths[i][j].item1 ); + + e1 = pts.length; + + 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; + + 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; + + 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; + + bei.e = new Pair(e0, e1); + } + } + +// pts = []; + // tessellate patches, merging into a single mesh - return null; + 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; + + for ( k in 0...divsU-1 ) { + + var iso = Make.surfaceIsocurve( bezier, u, false ); + rationalBezierCurveRegularSamplePointsMutate( iso, pts, iso.knots[0] + tessStepV, tessStepV, divsV - 1, false ); + + 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 + + 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 + + // complete north edge + 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, null ); } + 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; + + + switch (edgeSide) { + case EdgeSide.North: + edgeIndices = bei.n; + knots = bezier.knotsV; + case EdgeSide.South: + edgeIndices = bei.s; + knots = bezier.knotsV; + p0 += divsU * (divsV+1); + reverseFace = true; + case EdgeSide.East: + edgeIndices = bei.e; + knots = bezier.knotsU; + tessIStep = divsV+1; + p0 += divsV; + case EdgeSide.West: + edgeIndices = bei.w; + knots = bezier.knotsU; + tessIStep = divsV+1; + reverseFace = true; + } + + // 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; + + trace("edgeCount", edgeCount); + trace("divsU", divsU); + trace("divsV", divsV); + + trace("edgeU", edgeU); + trace("edgeStep", edgeStep); + trace("tessStep", tessStep); + + trace("tessU", tessU); + trace("edgeU", edgeU); + + trace("tessI", tessI); + trace("tessIStep", tessIStep); + + // triangulate the northwest corner + + while ( edgeI < edgeCount ){ + + while ( edgeU < tessU - Constants.EPSILON && edgeI < edgeCount ){ + + 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 ] ); + } + } + + 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 @@ -44,7 +385,7 @@ class Tess { var dehomo = Eval.dehomogenize2d( surface.controlPoints ); var bb = new BoundingBox(); - for (row in dehomo){ + for ( row in dehomo ) { bb.addRange( row ); } var avgPt = Vec.mul( 0.5, Vec.add( bb.min, bb.max ) ); @@ -73,14 +414,14 @@ class Tess { var duu = Math.NEGATIVE_INFINITY, iduu; - for (i in 0...surface.controlPoints.length-2){ - for (j in 0...surface.controlPoints[i].length){ + 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()); + 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; + if ( iduu > duu ) duu = iduu; } } @@ -89,14 +430,14 @@ class Tess { var dvv = Math.NEGATIVE_INFINITY, idvv; - for (i in 0...surface.controlPoints.length){ - for (j in 0...surface.controlPoints[i].length-2){ + 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()); + 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; + if ( idvv > dvv ) dvv = idvv; } } @@ -104,16 +445,16 @@ class Tess { var duv = Math.NEGATIVE_INFINITY, iduv; - for (i in 0...surface.controlPoints.length-1){ - for (j in 0...surface.controlPoints[i].length-1){ + 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()); + 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; + if ( iduv > duv ) duv = iduv; } } @@ -124,33 +465,33 @@ class Tess { 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(); + 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 ){ + if ( Math.abs( duu ) < Constants.TOLERANCE ) { stepu = 1.0; - if ( Math.abs(dvv) < Constants.TOLERANCE ) { + if ( Math.abs( dvv ) < Constants.TOLERANCE ) { stepv = 1.0; - return new Pair( stepu, stepv ); + return new Pair( stepu, stepv ); } stepv = ( Math.sqrt( duv * duv + 8 * dvv * tol * minw ) - duv ) / dvv; } - if ( Math.abs(dvv) < Constants.TOLERANCE ){ + 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 ); + return new Pair( stepu, stepv ); } var unum, vnum, denom; @@ -162,7 +503,7 @@ class Tess { vnum = 4 * duu * tol * minw; stepv = Math.sqrt( vnum / denom ); - return new Pair( stepu, stepv ); + return new Pair( stepu, stepv ); } // Compute a regularly spaced sequence of points on a non-uniform, rational spline curve. Generally, this algorithm @@ -179,10 +520,24 @@ class Tess { // //* an array of (divs+1) points - public static function rationalCurveRegularSample(crv:NurbsCurveData, divs:Int, includeU : Bool = false ):Array { + public static function rationalCurveRegularSample( crv : NurbsCurveData, divs : Int, includeU : Bool = false ) : Array { - var range = crv.knots.last() - crv.knots[0]; - var beziers = Modify.decomposeCurveIntoBeziers(crv); + //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; @@ -190,18 +545,18 @@ class Tess { var step = range / divs; var brange, bsteps, nextU; - for (i in 0...beziers.length) { + for ( i in 0...beziers.length ) { - brange = beziers[i].knots.last() - currentU; - bsteps = Math.ceil(brange / step); + brange = beziers[i].knots.last( ) - currentU; + bsteps = Math.ceil( brange / step ); nextU = currentU + bsteps * step; - if (nextU > beziers[i].knots.last() + Constants.TOLERANCE) { + if ( nextU > beziers[i].knots.last( ) + Constants.TOLERANCE ) { nextU -= step; bsteps--; } - rationalBezierCurveRegularSamplePointsMutate(beziers[i], pts, currentU, step, bsteps + 1, includeU); + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, currentU, step, bsteps + 1, includeU ); currentU = nextU + step; } @@ -214,19 +569,18 @@ class Tess { //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] )); + for ( i in 0...crv.controlPoints.length ) { + pts.push( Eval.dehomogenize( crv.controlPoints[i] ) ); } if ( includeU ) { - for (i in 0...crv.controlPoints.length){ + for ( i in 0...crv.controlPoints.length ) { pts[i].push( crv.knots[i + 1] ); } } return pts; } - var beziers = Modify.decomposeCurveIntoBeziers( crv ); - + var beziers = crv.knots.length == (crv.degree + 1) * 2 ? [ crv ] : Modify.decomposeCurveIntoBeziers( crv ); var pts = [], steps, domain, len; for ( i in 0...beziers.length ) { @@ -236,7 +590,7 @@ class Tess { steps = Math.ceil( domain / len ); len = domain / steps; - rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, beziers[i].knots[0], len, steps+1, includeU ); + rationalBezierCurveRegularSamplePointsMutate( beziers[i], pts, beziers[i].knots[0], len, steps + 1, includeU ); if ( i == beziers.length - 1 ) break; pts.pop( ); @@ -250,7 +604,7 @@ class Tess { startU : Float, step : Float, numSteps : Int, - includeU : Bool = false) : Void { + includeU : Bool = false ) : Void { var its = [], ts = [ its ], u = startU, degree1 = crv.degree + 1; @@ -312,9 +666,9 @@ class Tess { // add the parameters if required u = startU; - if (includeU){ - for (pt in pts){ - pt.push(u); + if ( includeU ) { + for ( pt in pts ) { + pt.push( u ); u += step; } } @@ -446,8 +800,8 @@ class Tess { 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] ); @@ -688,8 +1042,6 @@ class Tess { return pts; } - - } @:expose("core.AdaptiveRefinementOptions") diff --git a/test/testEval.js b/test/testEval.js index fc7aec10..f62b4614 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -20,6 +20,8 @@ function last(a){ return a[a.length-1]; } +/* + describe("verb.eval.Eval.knotSpanGivenN",function(){ it('returns correct result', () => { @@ -4051,6 +4053,8 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { }); +*/ + describe("verb.eval.Modify.surfaceKnotRefine",() => { var degree = 3 @@ -4199,6 +4203,34 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { 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); }); @@ -4237,6 +4269,33 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { 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); }); @@ -4253,4 +4312,71 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { }); -}); \ No newline at end of file +}); + + +describe("verb.eval.Modify.decomposeSurfaceIntoBeziers",() => { + + 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] ] ] + , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); + + it('can add knots into a surface in the u direction', () => { + + var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface ); + + var d = 10; + + res.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; + } + }); + }); + +// 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); + + }); +}); From bc6ff9065b9bdbd78fdbf83c32199fbe48d26e16 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Sun, 7 Feb 2016 17:49:04 -0500 Subject: [PATCH 20/25] More speeed --- benchmark/regularCurveSampling.js | 44 ++++---- benchmark/regularSurfaceDerivatives.js | 112 +++++++++---------- benchmark/regularSurfaceSampling.js | 118 ++++++++++----------- benchmark/surfaceTessellation.js | 24 ++--- build/js/verb.js | 40 +------ build/js/verb.min.js | 12 +-- build/js/verbHaxe.js | 40 +------ examples/surfaceAdaptiveTessellation2.html | 8 +- src/verb/eval/Tess.hx | 23 +--- test/testEval.js | 80 +++++++++----- todo | 10 +- 11 files changed, 222 insertions(+), 289 deletions(-) diff --git a/benchmark/regularCurveSampling.js b/benchmark/regularCurveSampling.js index fc4904d6..866e0b5b 100644 --- a/benchmark/regularCurveSampling.js +++ b/benchmark/regularCurveSampling.js @@ -1,22 +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 ) ) - } - } - } -}; - +//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 index 726c3443..6e5cbba9 100644 --- a/benchmark/regularSurfaceDerivatives.js +++ b/benchmark/regularSurfaceDerivatives.js @@ -1,56 +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 ) ) - } - } - } - } -}; - +//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 index 04e425e7..966b9d35 100644 --- a/benchmark/regularSurfaceSampling.js +++ b/benchmark/regularSurfaceSampling.js @@ -1,59 +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 ) ) - } - } - } - } -}; - +//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 index 04e425e7..e1b69fae 100644 --- a/benchmark/surfaceTessellation.js +++ b/benchmark/surfaceTessellation.js @@ -31,28 +31,16 @@ function getComplexSurface(){ return srfObj; } -var complexSurface = getComplexSurface(); +var surface = getComplexSurface(); module.exports = { - name: 'Regular surface sampling', + name: 'rationalSurfaceAdaptiveSample', tests: { - 'surfaceRegularSample2 (80 x 80)': function() { - verb.eval.Tess.surfaceRegularSample2( complexSurface, 80, 80 ); + 'rationalSurfaceAdaptiveSample (tol 0.2)': function() { + var mesh = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface, 0.1 ); }, - '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 ) ) - } - } + 'rationalSurfaceAdaptive (default)': function() { + var mesh = verb.eval.Tess.rationalSurfaceAdaptive( surface ); } } }; diff --git a/build/js/verb.js b/build/js/verb.js index 105b65da..c1bb1020 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -324,12 +324,6 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; -var haxe_Log = function() { }; -$hxClasses["haxe.Log"] = haxe_Log; -haxe_Log.__name__ = ["haxe","Log"]; -haxe_Log.trace = function(v,infos) { - js_Boot.__trace(v,infos); -}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -1064,25 +1058,6 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; -js_Boot.__unhtml = function(s) { - return s.split("&").join("&").split("<").join("<").split(">").join(">"); -}; -js_Boot.__trace = function(v,i) { - var msg; - if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; - msg += js_Boot.__string_rec(v,""); - if(i != null && i.customParams != null) { - var _g = 0; - var _g1 = i.customParams; - while(_g < _g1.length) { - var v1 = _g1[_g]; - ++_g; - msg += "," + js_Boot.__string_rec(v1,""); - } - } - var d; - if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); -}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1958,7 +1933,7 @@ var verb_Verb = function() { }; $hxClasses["verb.Verb"] = verb_Verb; verb_Verb.__name__ = ["verb","Verb"]; verb_Verb.main = function() { - haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); + console.log("verb 2.0.0"); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -6569,7 +6544,6 @@ verb_eval_Tess.westIndex = function(i,j,divs) { }; verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); - haxe_Log.trace(beziers.length,{ fileName : "Tess.hx", lineNumber : 91, className : "verb.eval.Tess", methodName : "rationalSurfaceAdaptiveSample", customParams : [beziers[0].length]}); var stepLengths = []; var stepLengthRow; var _g = 0; @@ -6730,16 +6704,6 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess var tessU = verb_core_ArrayExtensions.first(knots) + 1.5 * tessStep; var edgeI = 0; var tessI = 0; - haxe_Log.trace("edgeCount",{ fileName : "Tess.hx", lineNumber : 318, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeCount]}); - haxe_Log.trace("divsU",{ fileName : "Tess.hx", lineNumber : 319, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsU]}); - haxe_Log.trace("divsV",{ fileName : "Tess.hx", lineNumber : 320, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsV]}); - haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 322, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); - haxe_Log.trace("edgeStep",{ fileName : "Tess.hx", lineNumber : 323, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeStep]}); - haxe_Log.trace("tessStep",{ fileName : "Tess.hx", lineNumber : 324, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessStep]}); - haxe_Log.trace("tessU",{ fileName : "Tess.hx", lineNumber : 326, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessU]}); - haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 327, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); - haxe_Log.trace("tessI",{ fileName : "Tess.hx", lineNumber : 329, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessI]}); - haxe_Log.trace("tessIStep",{ fileName : "Tess.hx", lineNumber : 330, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessIStep]}); while(edgeI < edgeCount) { while(edgeU < tessU - verb_core_Constants.EPSILON && edgeI < edgeCount) { var ei = edgeIndices.item0 + edgeI; @@ -7624,7 +7588,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 81, className : "verb.exe.WorkerPool", methodName : "processQueue"}); + console.log(error); } _g.processQueue(); }; diff --git a/build/js/verb.min.js b/build/js/verb.min.js index 37029498..d25e0b23 100644 --- a/build/js/verb.min.js +++ b/build/js/verb.min.js @@ -1,6 +1,6 @@ -/*! verb 2015-10-25 */ -!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__=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);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!=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;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,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;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!=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=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 jb:return(0|a)===a;case lb:return"number"==typeof a;case mb:return"boolean"==typeof a;case String:return"string"==typeof a;case Array:return a instanceof Array&&null==a.__enum__;case kb: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==nb&&null!=a.__name__?!0:b==ob&&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 rb(this,a,null==b?null:b-a),d=new qb(c.byteLength),e=new rb(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.0.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.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=Ma.rationalCurveRegularSample(a,a.controlPoints.length*a.degree,!0),f=0,g=e.length-1;g>f;){var h=f++,i=e[h][0],j=e[h+1][0],k=e[h].slice(1),l=e[h+1].slice(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++;p=Ca.sub(p,Ca.mul(Q.get(o,s)*g[0][s],h[l][o-s]))}for(var t=1,u=l+1;u>t;){var v=t++;p=Ca.sub(p,Ca.mul(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++;w=Ca.add(w,Ca.mul(Q.get(o,z)*g[v][z],h[l-v][o-z]))}p=Ca.sub(p,Ca.mul(Q.get(l,v),w))}h[l].push(Ca.mul(1/g[0][0],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++;k=Ca.sub(k,Ca.mul(Q.get(j,n)*f[n],g[j-n]))}g.push(Ca.mul(1/f[0],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++;t[A]=Ca.add(t[A],Ca.mul(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++;o[x][I]=Ca.add(o[x][I],Ca.mul(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++;s=Ca.add(s,Ca.mul(n[y],h[p+y][q]))}r=Ca.add(r,Ca.mul(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++;y=Ca.sub(y,Ca.mul(Q.get(x,B)*q[0][B],r[u][x-B]))}for(var C=1,D=u+1;D>C;){var E=C++;y=Ca.sub(y,Ca.mul(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++;F=Ca.add(F,Ca.mul(Q.get(x,I)*q[E][I],r[u-E][x-I]))}y=Ca.sub(y,Ca.mul(Q.get(u,E),F))}r[u].push(Ca.mul(1/q[0][0],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.rationalSurfaceRegularSample=function(a,b,c){return Ia.dehomogenize2d(Ia.surfaceRegularSample(a,b,c))},Ia.surfaceRegularSample=function(a,b,c){for(var d=a.degreeU,e=a.degreeV,f=a.controlPoints,g=a.knotsU,h=a.knotsV,i=f[0][0].length,j=((P.last(g)-g[0])/b,(P.last(h)-h[0])/c,Ia.regularlySpacedBasisFunctions(d,g,b)),k=j.item0,l=j.item1,m=Ia.regularlySpacedBasisFunctions(e,h,c),n=m.item0,o=m.item1,p=[],q=b+1,r=c+1,s=0;q>s;){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},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.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++;i=Ca.add(i,Ca.mul(f[r],c[k+r][l]))}l++,j=Ca.add(j,Ca.mul(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++;n[u]=Ca.add(n[u],Ca.mul(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++;m[r][B]=Ca.add(m[r][B],Ca.mul(g[B][E],n[E]))}}}return m},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.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++;j[o]=Ca.add(j[o],Ca.mul(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++;i=Ca.add(i,Ca.mul(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++;x=Ca.add(x,Ca.mul(s[K],h[v+K][H][D]))}y=Ca.add(y,Ca.mul(t[G],x))}w=Ca.add(w,Ca.mul(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=Ma.rationalSurfaceAdaptive(a),e=Ma.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.rationalBezierCurve=function(a,b){for(var c=a.length-1,d=[],e=0,f=c+1;f>e;){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){var d,e,f,g=[];c?(f=a.controlPoints,d=a.knotsV,e=a.degreeV):(f=ta.transpose(a.controlPoints),d=a.knotsU,e=a.degreeU);for(var h=null,i=0;im;){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(E,j[K+1]),Ca.mul(1-E,j[K]))}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=b.eval.Tess=function(){};g["verb.eval.Tess"]=Ma,Ma.__name__=["verb","eval","Tess"],Ma.rationalCurveRegularSample=function(a,b,c){return Ma.rationalCurveRegularSampleRange(a,a.knots[0],P.last(a.knots),b,c)},Ma.rationalCurveRegularSampleRange=function(a,b,c,d,e){1>d&&(d=2);for(var f=[],g=(c-b)/(d-1),h=0,i=0;d>i;){var j=i++;h=b+g*j,e?f.push([h].concat(Ia.rationalCurvePoint(a,h))):f.push(Ia.rationalCurvePoint(a,h))}return f},Ma.rationalCurveAdaptiveSample=function(a,b,c){if(null==c&&(c=!1),null==b&&(b=1e-6),1==a.degree){if(c){for(var d=[],e=0,f=a.controlPoints.length;f>e;){var g=e++;d.push([a.knots[g+1]].concat(Ia.dehomogenize(a.controlPoints[g])))}return d}return a.controlPoints.map(Ia.dehomogenize)}return Ma.rationalCurveAdaptiveSampleRange(a,a.knots[0],P.last(a.knots),b,c)},Ma.rationalCurveAdaptiveSampleRange=function(a,b,c,d,e){var f=Ia.rationalCurvePoint(a,b),g=Ia.rationalCurvePoint(a,c),h=.5+.2*Math.random(),i=b+(c-b)*h,j=Ia.rationalCurvePoint(a,i),k=Ca.sub(f,g),l=Ca.sub(f,j);if(Ca.dot(k,k)d||!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){1>b&&(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=o*h,t=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)},Ma.divideRationalSurfaceAdaptive=function(a,b){null==b&&(b=new Na),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 Oa(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=Ma.north(I,F,H,c,f,m),K=Ma.east(I,F,H,c,f,m),L=Ma.south(I,F,H,c,f,m),M=Ma.west(I,F,H,c,f,m);m[I].neighbors=[L,K,J,M],m[I].divide(b)}return m},Ma.north=function(a,b,c,d,e,f){return 0==b?null:f[a-d]},Ma.south=function(a,b,c,d,e,f){return b==e-1?null:f[a+d]},Ma.east=function(a,b,c,d,e,f){return c==d-1?null:f[a+1]},Ma.west=function(a,b,c,d,e,f){return 0==c?null:f[a-1]},Ma.triangulateAdaptiveRefinementNodeTree=function(a){for(var b=Y.empty(),c=0;ca;){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 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;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(Qa.basePath+b)}catch(e){e instanceof C&&(e=e.val),d=new Worker(Qa.basePath+b.substring(0,-3)+".min.js")}this._pool.push(d)}};g["verb.exe.WorkerPool"]=Qa,Qa.__name__=["verb","exe","WorkerPool"],Qa.prototype={addWork:function(a,b,c,d){var e=new Ra(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__: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;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 pb={},qb=c.ArrayBuffer||E;null==qb.prototype.slice&&(qb.prototype.slice=E.sliceImpl);var rb=(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]],Pa.THREADS=1,Pa._init=!1,Qa.basePath="",Ra.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}); \ No newline at end of file +/*! verb 2015-11-23 */ +!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__=mb++);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 E.__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 D("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 z:this.buf.b+="b";for(var t=a,v=t.keys();v.hasNext();){var y=v.next();this.serializeString(y),this.serialize(null!=tb[y]?t.getReserved(y):t.h[y])}this.buf.b+="h";break;case w:this.buf.b+="q";for(var B=a,C=B.keys();C.hasNext();){var F=C.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 x: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 A:for(var K=a,L=0,M=K.length-2,N=new n,O=u.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(E.__instanceof(a,rb)){var W=q.getClassName(a);this.buf.b+="A",this.serializeString(W)}else if(E.__instanceof(a,sb))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 D("Cannot serialize function");default:throw new D("Cannot serialize "+m.string(a))}},__class__:u};var v=function(a){this.buf=a,this.length=a.length,this.pos=0,this.scache=[],this.cache=[];var b=v.DEFAULT_RESOLVER;null==b&&(b=q,v.DEFAULT_RESOLVER=b),this.setResolver(b)};g["haxe.Unserializer"]=v,v.__name__=["haxe","Unserializer"],v.initCodes=function(){for(var a=[],b=0,c=v.BASE64.length;c>b;){var d=b++;a[v.BASE64.charCodeAt(d)]=d}return a},v.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 D("Invalid object");if(103==this.buf.charCodeAt(this.pos))break;var b=this.unserialize();if("string"!=typeof b)throw new D("Invalid object key");var c=this.unserialize();a[b]=c}this.pos++},unserializeEnum:function(a,b){if(58!=this.get(this.pos++))throw new D("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 D("Invalid reference");return this.cache[h];case 82:var j=this.readDigits();if(0>j||j>=this.scache.length)throw new D("Invalid string reference");return this.scache[j];case 120:throw new D(this.unserialize());case 99:var l=this.unserialize(),m=this.resolver.resolveClass(l);if(null==m)throw new D("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 D("Enum not found "+p);var s=this.unserializeEnum(r,this.unserialize());return this.cache.push(s),s;case 106:var t=this.unserialize(),u=this.resolver.resolveEnum(t);if(null==u)throw new D("Enum not found "+t);this.pos++;var y=this.readDigits(),B=q.getEnumConstructs(u)[y];if(null==B)throw new D("Unknown enum index "+t+"@"+y);var C=this.unserializeEnum(u,B);return this.cache.push(C),C;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 z;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 w;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 D("Invalid IntMap format");return H;case 77:var K=new x;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=A.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 D("Class not found "+ea);var ga=q.createEmptyInstance(fa);if(this.cache.push(ga),ga.hxUnserialize(this),103!=this.get(this.pos++))throw new D("Invalid custom data");return ga;case 65:var ha=this.unserialize(),ia=this.resolver.resolveClass(ha);if(null==ia)throw new D("Class not found "+ha);return ia;case 66:var ja=this.unserialize(),ka=this.resolver.resolveEnum(ja);if(null==ka)throw new D("Enum not found "+ja);return ka}throw this.pos--,new D("Invalid char "+this.buf.charAt(this.pos)+" at position "+this.pos)},__class__:v};var w=function(){this.h={}};g["haxe.ds.IntMap"]=w,w.__name__=["haxe","ds","IntMap"],w.__interfaces__=[r],w.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__:w};var x=function(){this.h={},this.h.__keys__={}};g["haxe.ds.ObjectMap"]=x,x.__name__=["haxe","ds","ObjectMap"],x.__interfaces__=[r],x.prototype={set:function(a,b){var c=a.__id__||(a.__id__=++x.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__:x};var y=g["haxe.ds.Option"]={__ename__:["haxe","ds","Option"],__constructs__:["Some","None"]};y.Some=function(a){var b=["Some",0,a];return b.__enum__=y,b.toString=h,b},y.None=["None",1],y.None.toString=h,y.None.__enum__=y;var z=function(){this.h={}};g["haxe.ds.StringMap"]=z,z.__name__=["haxe","ds","StringMap"],z.__interfaces__=[r],z.prototype={set:function(a,b){null!=tb[a]?this.setReserved(a,b):this.h[a]=b},get:function(a){return null!=tb[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__:z};var A=function(a){this.length=a.byteLength,this.b=new vb(a),this.b.bufferValue=a,a.hxBytes=this,a.bytes=this.b};g["haxe.io.Bytes"]=A,A.__name__=["haxe","io","Bytes"],A.alloc=function(a){return new A(new ub(a))},A.prototype={get:function(a){return this.b[a]},set:function(a,b){this.b[a]=255&b},__class__:A};var B=g["haxe.io.Error"]={__ename__:["haxe","io","Error"],__constructs__:["Blocked","Overflow","OutsideBounds","Custom"]};B.Blocked=["Blocked",0],B.Blocked.toString=h,B.Blocked.__enum__=B,B.Overflow=["Overflow",1],B.Overflow.toString=h,B.Overflow.__enum__=B,B.OutsideBounds=["OutsideBounds",2],B.OutsideBounds.toString=h,B.OutsideBounds.__enum__=B,B.Custom=function(a){var b=["Custom",3,a];return b.__enum__=B,b.toString=h,b};var C=function(){};g["haxe.io.FPHelper"]=C,C.__name__=["haxe","io","FPHelper"],C.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)},C.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},C.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)},C.doubleToI64=function(a){var b=C.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 D=function(a){Error.call(this),this.val=a,this.message=String(a),Error.captureStackTrace&&Error.captureStackTrace(this,D)};g["js._Boot.HaxeError"]=D,D.__name__=["js","_Boot","HaxeError"],D.__super__=Error,D.prototype=d(Error.prototype,{__class__:D});var E=function(){};g["js.Boot"]=E,E.__name__=["js","Boot"],E.__unhtml=function(a){return a.split("&").join("&").split("<").join("<").split(">").join(">")},E.__trace=function(b,c){var d;if(d=null!=c?c.fileName+":"+c.lineNumber+": ":"",d+=E.__string_rec(b,""),null!=c&&null!=c.customParams)for(var e=0,f=c.customParams;e":"undefined"!=typeof a&&null!=a.log&&a.log(d)},E.getClass=function(a){if(a instanceof Array&&null==a.__enum__)return Array;var b=a.__class__;if(null!=b)return b;var c=E.__nativeClassName(a);return null!=c?E.__resolveNativeClass(c):null},E.__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?","+E.__string_rec(a[g],b):E.__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?",":"")+E.__string_rec(a[k],b)}return i+="]"}var l;try{l=a.toString}catch(m){return m instanceof D&&(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+" : "+E.__string_rec(a[o],b));return b=b.substring(1),p+="\n"+b+"}";case"function":return"";case"string":return a;default:return String(a)}},E.__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||E.__interfLoop(g,b))return!0}return E.__interfLoop(a.__super__,b)},E.__instanceof=function(a,b){if(null==b)return!1;switch(b){case nb:return(0|a)===a;case pb:return"number"==typeof a;case qb:return"boolean"==typeof a;case String:return"string"==typeof a;case Array:return a instanceof Array&&null==a.__enum__;case ob:return!0;default:if(null==a)return!1;if("function"==typeof b){if(a instanceof b)return!0;if(E.__interfLoop(E.getClass(a),b))return!0}else if("object"==typeof b&&E.__isNativeObj(b)&&a instanceof b)return!0;return b==rb&&null!=a.__name__?!0:b==sb&&null!=a.__ename__?!0:a.__enum__==b}},E.__nativeClassName=function(a){var b=E.__toStr.call(a).slice(8,-1);return"Object"==b||"Function"==b||"Math"==b||"JSON"==b?null:b},E.__isNativeObj=function(a){return null!=E.__nativeClassName(a)},E.__resolveNativeClass=function(a){return c[a]};var F=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"]=F,F.__name__=["js","html","compat","ArrayBuffer"],F.sliceImpl=function(a,b){var c=new vb(this,a,null==b?null:b-a),d=new ub(c.byteLength),e=new vb(d);return e.set(c),d},F.prototype={slice:function(a,b){return new F(this.a.slice(a,b))},__class__:F};var G=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 D(B.OutsideBounds)};g["js.html.compat.DataView"]=G,G.__name__=["js","html","compat","DataView"],G.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 C.i32ToFloat(this.getInt32(a,b))},getFloat64:function(a,b){var c=this.getInt32(a,b),d=this.getInt32(a+4,b);return C.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,C.floatToI32(b),c)},setFloat64:function(a,b,c){var d=C.doubleToI64(b);c?(this.setUint32(a,d.low),this.setUint32(a,d.high)):(this.setUint32(a,d.high),this.setUint32(a,d.low))},__class__:G};var H=function(){};g["js.html.compat.Uint8Array"]=H,H.__name__=["js","html","compat","Uint8Array"],H._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 F(d)}else if(E.__instanceof(a,F)){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 D("TODO "+m.string(a));d=a.slice(),d.byteLength=d.length,d.byteOffset=0,d.buffer=new F(d)}return d.subarray=H._subarray,d.set=H._set,d},H._set=function(a,b){var c=this;if(E.__instanceof(a.buffer,F)){var d=a;if(a.byteLength+b>c.byteLength)throw new D("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 D("TODO");var h=a;if(h.length+b>c.byteLength)throw new D("set() outside of range");for(var i=0,j=h.length;j>i;){var k=i++;c[k+b]=h[k]}}},H._subarray=function(a,b){var c=this,d=H._new(c.slice(a,b));return d.byteOffset=a,d};var I=function(a){this._resolved=!1,this._pending=!1,this._errorPending=!1,this._fulfilled=!1,this._update=[],this._error=[],this._errored=!1,null!=a&&I.link(a,this,function(a){return a})};g["promhx.base.AsyncBase"]=I,I.__name__=["promhx","base","AsyncBase"],I.link=function(a,b,c){a._update.push({async:b,linkf:function(a){b.handleResolve(c(a))}}),I.immediateLinkUpdate(a,b,c)},I.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 D&&(d=d.val),b.handleError(d)}},I.linkAll=function(a,b){for(var c=function(c,d,f){if(0==c.length||I.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)})}I.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))},I.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)}),I.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 D&&(g=g.val),b.handleError(g)}},I.allResolved=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._resolved)return!1}return!0},I.allFulfilled=function(a){for(var b=e(a)();b.hasNext();){var c=b.next();if(!c._fulfilled)return!1}return!0},I.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?N.enqueue(function(a,b){return function(){a(b)}}(f(this,this._resolve),a)):(this._resolved=!0,this._pending=!0,N.queue.add(function(){b._val=a;for(var c=0,d=b._update;c0)for(var c=0,d=b._error;c0))throw new D(a);for(var f=0,g=b._update;f0&&null!=(b=N.queue.pop());)b();return N.queue.isEmpty()},N.clear=function(){N.queue=new k},N.f=function(){var a=N.queue.pop();null!=a&&a(),N.queue.isEmpty()||N.continueOnNextLoop()},N.continueOnNextLoop=function(){null!=N.nextLoop?N.nextLoop(N.f):setImmediate(N.f)};var O=g["promhx.error.PromiseError"]={__ename__:["promhx","error","PromiseError"],__constructs__:["AlreadyResolved","DownstreamNotFullfilled"]};O.AlreadyResolved=function(a){var b=["AlreadyResolved",0,a];return b.__enum__=O,b.toString=h,b},O.DownstreamNotFullfilled=function(a){var b=["DownstreamNotFullfilled",1,a];return b.__enum__=O,b.toString=h,b};var P=function(){};g["verb.Verb"]=P,P.__name__=["verb","Verb"],P.main=function(){t.trace("verb 2.0.0",{fileName:"Verb.hx",lineNumber:45,className:"verb.Verb",methodName:"main"})};var Q=function(){};g["verb.core.ArrayExtensions"]=Q,Q.__name__=["verb","core","ArrayExtensions"],Q.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),R.memo_exists(a,b))return R.get_memo(a,b);for(var c=1,d=a,e=1,f=b+1;f>e;){var g=e++;R.memo_exists(d,g)?(a--,c=R.get_memo(d,g)):(c*=a--,c/=g,R.memoize(d,g,c))}return c},R.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},R.memo_exists=function(a,b){return R.memo.h.hasOwnProperty(a)&&R.memo.h[a].h.hasOwnProperty(b)},R.get_memo=function(a,b){return R.memo.h[a].h[b]},R.memoize=function(a,b,c){R.memo.h.hasOwnProperty(a)||R.memo.set(a,new w),R.memo.h[a].h[b]=c};var S=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"]=S,S.__name__=["verb","core","BoundingBox"],S.intervalsOverlap=function(a,b,c,d,e){null==e&&(e=-1);var f;f=-.5>e?T.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},S.prototype={fromPoint:function(a){return new S([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 S([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(!S.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 S([h,g])},__class__:S};var T=b.core.Constants=function(){};g["verb.core.Constants"]=T,T.__name__=["verb","core","Constants"];var U=b.core.SerializableBase=function(){};g["verb.core.SerializableBase"]=U,U.__name__=["verb","core","SerializableBase"],U.prototype={serialize:function(){var a=new u;return a.serialize(this),a.toString()},__class__:U};var V=b.core.Plane=function(a,b){this.origin=a,this.normal=b};g["verb.core.Plane"]=V,V.__name__=["verb","core","Plane"],V.__super__=U,V.prototype=d(U.prototype,{__class__:V});var W=b.core.Ray=function(a,b){this.origin=a,this.dir=b};g["verb.core.Ray"]=W,W.__name__=["verb","core","Ray"],W.__super__=U,W.prototype=d(U.prototype,{__class__:W});var X=b.core.NurbsCurveData=function(a,b,c){this.degree=a,this.controlPoints=c,this.knots=b};g["verb.core.NurbsCurveData"]=X,X.__name__=["verb","core","NurbsCurveData"],X.__super__=U,X.prototype=d(U.prototype,{__class__:X});var Y=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"]=Y,Y.__name__=["verb","core","NurbsSurfaceData"],Y.__super__=U,Y.prototype=d(U.prototype,{__class__:Y});var Z=b.core.MeshData=function(a,b,c,d){this.faces=a,this.points=b,this.normals=c,this.uvs=d};g["verb.core.MeshData"]=Z,Z.__name__=["verb","core","MeshData"],Z.empty=function(){return new Z([],[],[],[])},Z.__super__=U,Z.prototype=d(U.prototype,{__class__:Z});var $=b.core.PolylineData=function(a,b){this.points=a,this.params=b};g["verb.core.PolylineData"]=$,$.__name__=["verb","core","PolylineData"],$.__super__=U,$.prototype=d(U.prototype,{__class__:$});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__=U,_.prototype=d(U.prototype,{__class__:_});var aa=b.core.Pair=function(a,b){this.item0=a,this.item1=b};g["verb.core.Pair"]=aa,aa.__name__=["verb","core","Pair"],aa.prototype={__class__:aa};var ba=b.core.Interval=function(a,b){this.min=a,this.max=b};g["verb.core.Interval"]=ba,ba.__name__=["verb","core","Interval"],ba.prototype={__class__:ba};var ca=b.core.CurveCurveIntersection=function(a,b,c,d){this.point0=a,this.point1=b,this.u0=c,this.u1=d};g["verb.core.CurveCurveIntersection"]=ca,ca.__name__=["verb","core","CurveCurveIntersection"],ca.prototype={__class__:ca};var da=b.core.CurveSurfaceIntersection=function(a,b,c,d){this.u=a,this.uv=b,this.curvePoint=c,this.surfacePoint=d};g["verb.core.CurveSurfaceIntersection"]=da,da.__name__=["verb","core","CurveSurfaceIntersection"],da.prototype={__class__:da};var ea=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"]=ea,ea.__name__=["verb","core","MeshIntersectionPoint"],ea.prototype={__class__:ea};var fa=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"]=fa,fa.__name__=["verb","core","PolylineMeshIntersection"],fa.prototype={__class__:fa};var ga=b.core.SurfaceSurfaceIntersectionPoint=function(a,b,c,d){this.uv0=a,this.uv1=b,this.point=c,this.dist=d};g["verb.core.SurfaceSurfaceIntersectionPoint"]=ga,ga.__name__=["verb","core","SurfaceSurfaceIntersectionPoint"],ga.prototype={__class__:ga};var ha=b.core.TriSegmentIntersection=function(a,b,c,d){this.point=a,this.s=b,this.t=c,this.p=d};g["verb.core.TriSegmentIntersection"]=ha,ha.__name__=["verb","core","TriSegmentIntersection"],ha.prototype={__class__:ha};var ia=b.core.CurveTriPoint=function(a,b,c){this.u=a,this.point=b,this.uv=c};g["verb.core.CurveTriPoint"]=ia,ia.__name__=["verb","core","CurveTriPoint"],ia.prototype={__class__:ia};var ja=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"]=ja,ja.__name__=["verb","core","SurfacePoint"],ja.fromUv=function(a,b){return new ja(null,null,[a,b])},ja.prototype={__class__:ja};var ka=b.core.CurvePoint=function(a,b){this.u=a,this.pt=b};g["verb.core.CurvePoint"]=ka,ka.__name__=["verb","core","CurvePoint"],ka.prototype={__class__:ka};var la=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"]=la,la.__name__=["verb","core","KdTree"],la.prototype={buildTree:function(a,b,c){var d,e,f=b%this.dim;return 0==a.length?null:1==a.length?new oa(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 oa(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 ma(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 aa(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 aa(null,c))}d(this.root);for(var i=[],j=0;b>j;){var k=j++;null!=f.content[k].item0&&i.push(new aa(f.content[k].item0.kdPoint,f.content[k].item1))}return i},__class__:la};var ma=function(a){this.content=[],this.scoreFunction=a};g["verb.core.BinaryHeap"]=ma,ma.__name__=["verb","core","BinaryHeap"],ma.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__:ma};var na=b.core.KdPoint=function(a,b){this.point=a,this.obj=b};g["verb.core.KdPoint"]=na,na.__name__=["verb","core","KdPoint"],na.prototype={__class__:na};var oa=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"]=oa,oa.__name__=["verb","core","KdNode"],oa.prototype={__class__:oa};var pa=function(){};g["verb.eval.IBoundingBoxTree"]=pa,pa.__name__=["verb","eval","IBoundingBoxTree"],pa.prototype={__class__:pa};var qa=function(a,b){this._boundingBox=null,this._curve=a,null==b&&(b=Da.domain(this._curve.knots)/64),this._knotTol=b};g["verb.core.LazyCurveBoundingBoxTree"]=qa,qa.__name__=["verb","core","LazyCurveBoundingBoxTree"],qa.__interfaces__=[pa],qa.prototype={split:function(){var a=Q.first(this._curve.knots),b=Q.last(this._curve.knots),c=b-a,d=Ha.curveSplit(this._curve,(b+a)/2+.1*c*Math.random());return new aa(new qa(d[0],this._knotTol),new qa(d[1],this._knotTol))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=new S(Ja.dehomogenize1d(this._curve.controlPoints))),this._boundingBox},"yield":function(){return this._curve},indivisible:function(a){return Da.domain(this._curve.knots)d;){var f=d++;c.push(f)}b=c}this._faceIndices=b};g["verb.core.LazyMeshBoundingBoxTree"]=ra,ra.__name__=["verb","core","LazyMeshBoundingBoxTree"],ra.__interfaces__=[pa],ra.prototype={split:function(){var a=wa.sortTrianglesOnLongestAxis(this.boundingBox(),this._mesh,this._faceIndices),b=Q.left(a),c=Q.right(a);return new aa(new ra(this._mesh,b),new ra(this._mesh,c))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=wa.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__:ra};var sa=function(a,b){this._boundingBox=null,this._polyline=a,null==b&&(b=new ba(0,0!=a.points.length?a.points.length-1:0)),this._interval=b};g["verb.core.LazyPolylineBoundingBoxTree"]=sa,sa.__name__=["verb","core","LazyPolylineBoundingBoxTree"],sa.__interfaces__=[pa],sa.prototype={split:function(){var a=this._interval.min,b=this._interval.max,c=a+Math.ceil((b-a)/2),d=new ba(a,c),e=new ba(c,b);return new aa(new sa(this._polyline,d),new sa(this._polyline,e))},boundingBox:function(){return null==this._boundingBox&&(this._boundingBox=new S(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__:sa};var ta=function(a,b,c,d){null==b&&(b=!1),this._boundingBox=null,this._surface=a,this._splitV=b,null==c&&(c=Da.domain(a.knotsU)/16),null==d&&(d=Da.domain(a.knotsV)/16),this._knotTolU=c,this._knotTolV=d};g["verb.core.LazySurfaceBoundingBoxTree"]=ta,ta.__name__=["verb","core","LazySurfaceBoundingBoxTree"],ta.__interfaces__=[pa],ta.prototype={split:function(){var a,b;this._splitV?(a=Q.first(this._surface.knotsV),b=Q.last(this._surface.knotsV)):(a=Q.first(this._surface.knotsU),b=Q.last(this._surface.knotsU));var c=(a+b)/2,d=Ha.surfaceSplit(this._surface,c,this._splitV);return new aa(new ta(d[0],!this._splitV,this._knotTolU,this._knotTolV),new ta(d[1],!this._splitV,this._knotTolU,this._knotTolV))},boundingBox:function(){if(null==this._boundingBox){this._boundingBox=new S;for(var a=0,b=this._surface.controlPoints;ad;){var f=d++;c.push(Da.mul(a,b[f]))}return c},ua.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},ua.add=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Da.add(a[f],b[f]))}return c},ua.div=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Da.div(a[f],b))}return c},ua.sub=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Da.sub(a[f],b[f]))}return c},ua.dot=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(Da.dot(a[f],b))}return c},ua.identity=function(a){for(var b=Da.zeros2d(a,a),c=0;a>c;){var d=c++;b[d][d]=1}return b},ua.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},ua.solve=function(a,b){return ua.LUsolve(ua.LU(a),b)},ua.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},ua.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 va(a,q)};var va=function(a,b){this.LU=a,this.P=b};g["verb.core._Mat.LUDecomp"]=va,va.__name__=["verb","core","_Mat","LUDecomp"],va.prototype={__class__:va};var wa=b.core.Mesh=function(){};g["verb.core.Mesh"]=wa,wa.__name__=["verb","core","Mesh"],wa.getTriangleNorm=function(a,b){var c=a[b[0]],d=a[b[1]],e=a[b[2]],f=Da.sub(d,c),g=Da.sub(e,c),h=Da.cross(f,g);return Da.mul(1/Da.norm(h),h)},wa.makeMeshAabb=function(a,b){for(var c=new S,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},wa.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},wa.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},wa.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=Da.sub(e,c),l=Da.sub(f,c),m=Da.sub(g,c),n=Da.norm(Da.cross(Da.sub(e,f),Da.sub(e,g))),o=Da.norm(Da.cross(l,m))/n,p=Da.norm(Da.cross(m,k))/n,q=Da.norm(Da.cross(k,l))/n;return Da.add(Da.mul(o,h),Da.add(Da.mul(p,i),Da.mul(q,j)))};var xa=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=wa.makeMeshAabb(a,b),b.length<1)return void(this._empty=!0);if(b.length<2)return void(this._face=b[0]);var g=wa.sortTrianglesOnLongestAxis(this._boundingBox,a,b),h=Q.left(g),i=Q.right(g);this._children=new aa(new xa(a,h),new xa(a,i))};g["verb.core.MeshBoundingBoxTree"]=xa,xa.__name__=["verb","core","MeshBoundingBoxTree"],xa.__interfaces__=[pa],xa.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__:xa};var ya=b.core.Minimizer=function(){};g["verb.core.Minimizer"]=ya,ya.__name__=["verb","core","Minimizer"],ya.uncmin=function(a,b,c,d,e){null==c&&(c=1e-8),null==d&&(d=function(b){return ya.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 D("uncmin: f(x0) is a NaN!");c=Math.max(c,T.EPSILON);var j,k,l,m,n,o,p,q,r,s=ua.identity(g),t=0,u=[],v="";for(k=d(b);e>t;){if(!Da.all(Da.finite(k))){v="Gradient has Infinity or NaN";break}if(j=Da.neg(ua.dot(s,k)),!Da.all(Da.finite(j))){v="Search direction has Infinity or NaN";break}if(r=Da.norm(j),c>r){v="Newton step smaller than tol";break}for(q=1,f=Da.dot(k,j),m=b;e>t&&!(c>q*r)&&(u=Da.mul(q,j),m=Da.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=Da.sub(l,k),p=Da.dot(n,u),o=ua.dot(s,n),s=ua.sub(ua.add(s,ua.mul((p+Da.dot(n,o))/(p*p),ya.tensor(u,u))),ua.div(ua.add(ya.tensor(o,u),ya.tensor(u,o)),p)),b=m,h=i,k=l,++t}return new za(b,h,k,s,t,v)},ya.numericalGradient=function(a,b){var c=b.length,d=a(b);if(NaN==d)throw new D("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 D("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=Da.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(Da.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},ya.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 za=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"]=za,za.__name__=["verb","core","MinimizationResult"],za.prototype={__class__:za};var Aa=function(){};g["verb.core.ISerializable"]=Aa,Aa.__name__=["verb","core","ISerializable"],Aa.prototype={__class__:Aa};var Ba=b.core.Deserializer=function(){};g["verb.core.Deserializer"]=Ba,Ba.__name__=["verb","core","Deserializer"],Ba.deserialize=function(a){var b=new v(a),c=b.unserialize();return c};var Ca=b.core.Trig=function(){};g["verb.core.Trig"]=Ca,Ca.__name__=["verb","core","Trig"],Ca.isPointInPlane=function(a,b,c){return Math.abs(Da.dot(Da.sub(a,b.origin),b.normal))h},Ca.segmentClosestPoint=function(a,b,c,d,e){var f=Da.sub(c,b),g=Da.norm(f);if(gk?{u:d,pt:b}:k>g?{u:e,pt:c}:{u:d+(e-d)*k/g,pt:Da.add(h,Da.mul(k,i))}};var Da=b.core.Vec=function(){};g["verb.core.Vec"]=Da,Da.__name__=["verb","core","Vec"],Da.angleBetween=function(a,b){return Math.acos(Da.dot(a,b)/(Da.norm(a)*Da.norm(b)))},Da.positiveAngleBetween=function(a,b,c){var d=Da.cross(a,b),e=Da.norm(a),f=Da.norm(b),g=e*f,h=Da.dot(a,b),i=Da.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=Da.dot(c,d);return Math.abs(l)0?k:-k},Da.signedAngleBetween=function(a,b,c){var d=Da.cross(a,b),e=Da.norm(a),f=Da.norm(b),g=e*f,h=Da.dot(a,b),i=Da.norm(d)/g,j=h/g,k=Math.atan2(i,j),l=Da.dot(c,d);return l>0?k:2*Math.PI-k},Da.angleBetweenNormalized2d=function(a,b){var c=a[0]*b[1]-a[1]*b[0];return Math.atan2(c,Da.dot(a,b))},Da.domain=function(a){return Q.last(a)-Q.first(a)},Da.range=function(a){for(var b=[],c=0,d=0;a>d;){d++;b.push(c),c+=1}return b},Da.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},Da.neg=function(a){return a.map(function(a){return-a})},Da.min=function(a){return j.fold(a,function(a,b){return Math.min(a,b)},1/0)},Da.max=function(a){return j.fold(a,function(a,b){return Math.max(a,b)},-(1/0))},Da.all=function(a){return j.fold(a,function(a,b){return b&&a},!0)},Da.finite=function(a){return a.map(function(a){return isFinite(a)})},Da.onRay=function(a,b,c){return Da.add(a,Da.mul(c,b))},Da.lerp=function(a,b,c){return Da.add(Da.mul(a,b),Da.mul(1-a,c))},Da.normalized=function(a){return Da.div(a,Da.norm(a))},Da.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]]},Da.dist=function(a,b){return Da.norm(Da.sub(a,b))},Da.distSquared=function(a,b){return Da.normSquared(Da.sub(a,b))},Da.sum=function(a){return j.fold(a,function(a,b){return b+a},0)},Da.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 Da.add(b,a)},Da.rep(c,0))},Da.addAllMutate=function(a){for(var b=a[0],c=1,d=a.length;d>c;){var e=c++;Da.addMutate(b,a[e])}},Da.addMulMutate=function(a,b,c){for(var d=0,e=a.length;e>d;){var f=d++;a[f]=a[f]+b*c[f]}},Da.subMulMutate=function(a,b,c){for(var d=0,e=a.length;e>d;){var f=d++;a[f]=a[f]-b*c[f]}},Da.addMutate=function(a,b){for(var c=0,d=a.length;d>c;){var e=c++;a[e]=a[e]+b[e]}},Da.subMutate=function(a,b){for(var c=0,d=a.length;d>c;){var e=c++;a[e]=a[e]-b[e]}},Da.mulMutate=function(a,b){for(var c=0,d=b.length;d>c;){var e=c++;b[e]=b[e]*a}},Da.norm=function(a){var b=Da.normSquared(a);return 0!=b?Math.sqrt(b):b},Da.normSquared=function(a){return j.fold(a,function(a,b){return b+a*a},0)},Da.rep=function(a,b){for(var c=[],d=0;a>d;){d++;c.push(b)}return c},Da.zeros1d=function(a){for(var b=[],c=0;a>c;){c++;b.push(0)}return b},Da.zeros2d=function(a,b){for(var c=[],d=0;a>d;){d++;c.push(Da.zeros1d(b))}return c},Da.zeros3d=function(a,b,c){for(var d=[],e=0;a>e;){e++;d.push(Da.zeros2d(b,c))}return d},Da.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},Da.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},Da.mul=function(a,b){for(var c=[],d=0,e=b.length;e>d;){var f=d++;c.push(a*b[f])}return c},Da.div=function(a,b){for(var c=[],d=0,e=a.length;e>d;){var f=d++;c.push(a[f]/b)}return c},Da.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},Da.isZero=function(a){for(var b=0,c=a.length;c>b;){var d=b++;if(Math.abs(a[d])>T.TOLERANCE)return!1}return!0},Da.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},Da.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])T.EPSILON&&(c=new Fa(e,0),b.push(c)),c.inc()}return b},Ea.isRationalSurfaceClosed=function(a,b){null==b&&(b=!0);var c;c=b?a.controlPoints:ua.transpose(a.controlPoints);for(var d=0,e=c[0].length;e>d;){var f=d++,g=Da.dist(Q.first(c)[f],Q.last(c)[f])r;){var t=r++,u=p.points[t],v=Da.normSquared(Da.sub(b,u));q>v&&(q=v,e=p.uvs[t])}for(var w=function(b){return Ja.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=Da.dot(d,c),k=Da.dot(e,c),l=[-j,-k],m=Da.dot(d,d)+Da.dot(f,c),n=Da.dot(d,e)+Da.dot(h,c),o=Da.dot(d,e)+Da.dot(i,c),p=Da.dot(e,e)+Da.dot(g,c),q=[[m,n],[o,p]],r=ua.solve(q,l);return Da.add(r,a)};f>g;){c=w(e),d=Da.sub(c[0][0],b);var y=Da.norm(d),z=Da.dot(c[1][0],d),A=Da.norm(c[1][0])*y,B=Da.dot(c[0][1],d),C=Da.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-T.EPSILON,I[1]]),I[1]m&&(I=o?[I[0],l+(I[0]-m)]:[I[0],m-T.EPSILON]);var J=Da.norm(Da.mul(I[0]-e[0],c[1][0])),K=Da.norm(Da.mul(I[1]-e[1],c[0][1]));if(h>J+K)return e;e=I,g++}return e},Ea.rationalCurveClosestPoint=function(a,b){return Ja.rationalCurvePoint(a,Ea.rationalCurveClosestParam(a,b))},Ea.rationalCurveClosestParam=function(a,b){for(var c=1/0,d=0,e=Qa.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=Ca.segmentClosestPoint(b,k,l,i,j),n=Da.norm(Da.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=Q.last(a.knots),w=Da.normSquared(Da.sub(a.controlPoints[0],Q.last(a.controlPoints)))r;){o=y(x),p=Da.sub(o[0],b);var A=Da.norm(p),B=Da.dot(o[1],p),C=Da.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=Da.norm(Da.mul(G-x,o[1]));if(s>H)return x;x=G,r++}return x},Ea.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:Ea.rationalBezierCurveArcLength(a),b>e)return Q.last(a.knots);var f,g=a.knots[0],h=0,i=Q.last(a.knots),j=e,k=0,l=0;for(f=null!=c?c:2*T.TOLERANCE;j-h>f;)k=(g+i)/2,l=Ea.rationalBezierCurveArcLength(a,k),l>b?(i=k,j=l):(g=k,h=l);return(g+i)/2},Ea.rationalCurveArcLength=function(a,b,c){null==c&&(c=16),b=null==b?Q.last(a.knots):b;for(var d=Ma.decomposeCurveIntoBeziers(a),e=0,f=d[0],g=0;ej;){var k=j++;e=g*Ea.Tvalues[i][k]+g+a.knots[0], +f=Ja.rationalCurveDerivatives(a,e,1),h+=Ea.Cvalues[i][k]*Da.norm(f[1])}return g*h};var Fa=b.eval.KnotMultiplicity=function(a,b){this.knot=a,this.mult=b};g["verb.eval.KnotMultiplicity"]=Fa,Fa.__name__=["verb","eval","KnotMultiplicity"],Fa.prototype={inc:function(){this.mult++},__class__:Fa};var Ga=b.eval.Check=function(){};g["verb.eval.Check"]=Ga,Ga.__name__=["verb","eval","Check"],Ga.isValidKnotVector=function(a,b){if(0==a.length)return!1;if(a.length<2*(b+1))return!1;for(var c=Q.first(a),d=0,e=b+1;e>d;){var f=d++;if(Math.abs(a[f]-c)>T.EPSILON)return!1}c=Q.last(a);for(var g=a.length-b-1,h=a.length;h>g;){var i=g++;if(Math.abs(a[i]-c)>T.EPSILON)return!1}return Ga.isNonDecreasing(a)},Ga.isNonDecreasing=function(a){for(var b=Q.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=Ja.knotSpan(e,b,d),n=null,o=0;og;){g++;f.push(b)}c=f;var i=Ma.curveKnotRefine(a,c),j=Ja.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 X(d,k,m),new X(d,l,n)]},Ha.rationalCurveByEqualArcLength=function(a,b){var c=Ea.rationalCurveArcLength(a),d=c/b;return Ha.rationalCurveByArcLength(a,d)},Ha.rationalCurveByArcLength=function(a,b){var c=Ma.decomposeCurveIntoBeziers(a),d=c.map(function(a){return Ea.rationalBezierCurveArcLength(a)}),e=Da.sum(d),f=[new Ia(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++;Da.subMulMutate(p,R.get(o,s)*g[0][s],h[l][o-s])}for(var t=1,u=l+1;u>t;){var v=t++;Da.subMulMutate(p,R.get(l,v)*g[v][0],h[l-v][o]);for(var w=Da.zeros1d(i),x=1,y=o+1;y>x;){var z=x++;Da.addMulMutate(w,R.get(o,z)*g[v][z],h[l-v][o-z])}Da.subMulMutate(p,R.get(l,v),w)}Da.mulMutate(1/g[0][0],p),h[l].push(p)}}return h},Ja.rationalSurfacePoint=function(a,b,c){return Ja.dehomogenize(Ja.surfacePoint(a,b,c))},Ja.rationalCurveDerivatives=function(a,b,c){null==c&&(c=1);for(var d=Ja.curveDerivatives(a,b,c),e=Ja.rational1d(d),f=Ja.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++;Da.subMulMutate(k,R.get(j,n)*f[n],g[j-n])}Da.mulMutate(1/f[0],k),g.push(k)}return g},Ja.rationalCurvePoint=function(a,b){return Ja.dehomogenize(Ja.curvePoint(a,b))},Ja.surfaceDerivatives=function(a,b,c,d){var e=a.knotsU.length-a.degreeU-2,f=a.knotsV.length-a.degreeV-2;return Ja.surfaceDerivativesGivenNM(e,f,a,b,c,d)},Ja.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(!Ja.areValidRelations(g,i.length,j.length)||!Ja.areValidRelations(h,i[0].length,k.length))throw new D("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=Da.zeros3d(l+1,n+1,m),p=Ja.knotSpanGivenN(a,g,d,j),q=Ja.knotSpanGivenN(b,h,e,k),r=Ja.derivativeBasisFunctionsGivenNI(p,d,g,a,j),s=Ja.derivativeBasisFunctionsGivenNI(q,e,h,b,k),t=Da.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]=Da.zeros1d(m);for(var B=0,C=g+1;C>B;){var E=B++;Da.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]=Da.zeros1d(m);for(var J=0,K=h+1;K>J;){var L=J++;Da.addMulMutate(o[x][I],s[I][L],t[L])}}}return o},Ja.surfacePoint=function(a,b,c){var d=a.knotsU.length-a.degreeU-2,e=a.knotsV.length-a.degreeV-2;return Ja.surfacePointGivenNM(d,e,a,b,c)},Ja.surfacePointGivenNM=function(a,b,c,d,e){var f=c.degreeU,g=c.degreeV,h=c.controlPoints,i=c.knotsU,j=c.knotsV;if(!Ja.areValidRelations(f,h.length,i.length)||!Ja.areValidRelations(g,h[0].length,j.length))throw new D("Invalid relations between control points, knot vector, and n");for(var k=h[0][0].length,l=Ja.knotSpanGivenN(a,f,d,i),m=Ja.knotSpanGivenN(b,g,e,j),n=Ja.basisFunctionsGivenKnotSpanIndex(l,d,f,i),o=Ja.basisFunctionsGivenKnotSpanIndex(m,e,g,j),p=l-f,q=m,r=Da.zeros1d(k),s=Da.zeros1d(k),t=0,u=g+1;u>t;){var v=t++;s=Da.zeros1d(k),q=m-g+v;for(var w=0,x=f+1;x>w;){var y=w++;Da.addMulMutate(s,n[y],h[p+y][q])}Da.addMulMutate(r,o[v],s)}return r},Ja.rationalSurfaceRegularSampleDerivatives=function(a,b,c,d){for(var e=Ja.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=Ja.rational2d(o),q=Ja.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++;Da.subMulMutate(y,R.get(x,B)*q[0][B],r[u][x-B])}for(var C=1,D=u+1;D>C;){var E=C++;Da.subMulMutate(y,R.get(u,E)*q[E][0],r[u-E][x]);for(var F=Da.zeros1d(s),G=1,H=x+1;H>G;){var I=G++;Da.addMulMutate(F,R.get(x,I)*q[E][I],r[u-E][x-I])}Da.subMulMutate(y,R.get(u,E),F)}Da.mulMutate(1/q[0][0],y),r[u].push(y)}}l.push(r)}}return f},Ja.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=((Q.last(h)-h[0])/b,(Q.last(i)-i[0])/c,Ja.regularlySpacedDerivativeBasisFunctions(e,h,b)),l=k.item0,m=k.item1,n=Ja.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(Ja.surfaceDerivativesGivenBasesKnotSpans(e,f,g,l[u],o[x],m[u],p[x],j,d))}}return q},Ja.regularlySpacedBasisFunctions=function(a,b,c){for(var d=b.length-a-2,e=(Q.last(b)-b[0])/c,f=[],g=[],h=b[0],i=Ja.knotSpanGivenN(d,a,h,b),j=c+1,k=0;j>k;){for(k++;h>=b[i+1];)i++;g.push(i),f.push(Ja.basisFunctionsGivenKnotSpanIndex(i,h,a,b)),h+=e}return new aa(g,f)},Ja.regularlySpacedDerivativeBasisFunctions=function(a,b,c){for(var d=b.length-a-2,e=(Q.last(b)-b[0])/c,f=[],g=[],h=b[0],i=Ja.knotSpanGivenN(d,a,h,b),j=c+1,k=0;j>k;){for(k++;h>=b[i+1];)i++;g.push(i),f.push(Ja.derivativeBasisFunctionsGivenNI(i,h,a,d,b)),h+=e}return new aa(g,f)},Ja.surfacePointGivenBasesKnotSpans=function(a,b,c,d,e,f,g,h){for(var i,j=Da.zeros1d(h),k=d-a,l=e-b,m=0,n=b+1;n>m;){var o=m++;i=Da.zeros1d(h);for(var p=0,q=a+1;q>p;){var r=p++;Da.addMulMutate(i,f[r],c[k+r][l])}l++,Da.addMulMutate(j,g[o],i)}return j},Ja.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=Da.zeros3d(j+1,l+1,k),n=Da.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]=Da.zeros1d(k);for(var v=0,w=a+1;w>v;){var x=v++;Da.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]=Da.zeros1d(k);for(var C=0,D=b+1;D>C;){var E=C++;Da.addMulMutate(m[r][B],g[B][E],n[E])}}}return m},Ja.curveDerivatives=function(a,b,c){var d=a.knots.length-a.degree-2;return Ja.curveDerivativesGivenN(d,a,b,c)},Ja.curveDerivativesGivenN=function(a,b,c,d){var e=b.degree,f=b.controlPoints,g=b.knots;if(!Ja.areValidRelations(e,f.length,g.length))throw new D("Invalid relations between control points, knot vector, and n");var h,i=f[0].length;h=e>d?d:e;for(var j=Da.zeros2d(h+1,i),k=Ja.knotSpanGivenN(a,e,c,g),l=Ja.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++;Da.addMulMutate(j[o],l[o][r],f[k-e+r])}return j},Ja.curvePoint=function(a,b){var c=a.knots.length-a.degree-2;return Ja.curvePointGivenN(c,a,b)},Ja.areValidRelations=function(a,b,c){return b+a+1-c==0},Ja.curvePointGivenN=function(a,b,c){var d=b.degree,e=b.controlPoints,f=b.knots;if(!Ja.areValidRelations(d,e.length,f.length))throw new D("Invalid relations between control points, knot Array, and n");for(var g=Ja.knotSpanGivenN(a,d,c,f),h=Ja.basisFunctionsGivenKnotSpanIndex(g,c,d,f),i=Da.zeros1d(e[0].length),j=0,k=d+1;k>j;){var l=j++;Da.addMulMutate(i,h[l],e[g-d+l])}return i},Ja.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 Ja.volumePointGivenNML(a,e,f,g,b,c,d)},Ja.volumePointGivenNML=function(a,b,c,d,e,f,g){if(!Ja.areValidRelations(a.degreeU,a.controlPoints.length,a.knotsU.length)||!Ja.areValidRelations(a.degreeV,a.controlPoints[0].length,a.knotsV.length)||!Ja.areValidRelations(a.degreeW,a.controlPoints[0][0].length,a.knotsW.length))throw new D("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=Ja.knotSpanGivenN(b,i,e,l),q=Ja.knotSpanGivenN(c,j,f,m),r=Ja.knotSpanGivenN(d,k,g,n),s=Ja.basisFunctionsGivenKnotSpanIndex(p,e,i,l),t=Ja.basisFunctionsGivenKnotSpanIndex(q,f,j,m),u=Ja.basisFunctionsGivenKnotSpanIndex(r,g,k,n),v=p-i,w=Da.zeros1d(o),x=Da.zeros1d(o),y=Da.zeros1d(o),z=0,A=k+1;A>z;){var B=z++;y=Da.zeros1d(o);for(var C=r-k+B,E=0,F=j+1;F>E;){var G=E++;x=Da.zeros1d(o);for(var H=q-j+G,I=0,J=i+1;J>I;){var K=I++;Da.addMulMutate(x,s[K],h[v+K][H][C])}Da.addMulMutate(y,t[G],x)}Da.addMulMutate(w,u[B],y)}return w},Ja.derivativeBasisFunctions=function(a,b,c){var d=Ja.knotSpan(b,a,c),e=c.length-1,f=e-b-1;return Ja.derivativeBasisFunctionsGivenNI(d,a,b,f,c)},Ja.derivativeBasisFunctionsGivenNI=function(a,b,c,d,e){var f=Da.zeros2d(c+1,c+1),g=Da.zeros1d(c+1),h=Da.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=Da.zeros2d(d+1,c+1),q=Da.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},Ja.basisFunctions=function(a,b,c){var d=Ja.knotSpan(b,a,c);return Ja.basisFunctionsGivenKnotSpanIndex(d,a,b,c)},Ja.basisFunctionsGivenKnotSpanIndex=function(a,b,c,d){var e=Da.zeros1d(c+1),f=Da.zeros1d(c+1),g=Da.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},Ja.knotSpan=function(a,b,c){return Ja.knotSpanGivenN(c.length-a-2,a,b,c)},Ja.knotSpanGivenN=function(a,b,c,d){if(c>d[a+1]-T.EPSILON)return a;if(c=d[g+1];)cf;){var g=f++;c.push(a[g]/d)}return c},Ja.rational1d=function(a){var b=a[0].length-1;return a.map(function(a){return a.slice(0,b)})},Ja.rational2d=function(a){return a.map(Ja.rational1d)},Ja.weight1d=function(a){var b=a[0].length-1;return a.map(function(a){return a[b]})},Ja.weight2d=function(a){return a.map(Ja.weight1d)},Ja.dehomogenize1d=function(a){return a.map(Ja.dehomogenize)},Ja.dehomogenize2d=function(a){return a.map(Ja.dehomogenize1d)},Ja.homogenize1d=function(a,b){var c,d=a.length,e=a[0].length,f=[],g=0,h=[];c=null!=b?b:Da.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},Ja.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(Da.rep(a[0].length,1))}c=f}for(var h=0;d>h;){var i=h++;e.push(Ja.homogenize1d(a[i],c[i]))}return e};var Ka=b.eval.Intersect=function(){};g["verb.eval.Intersect"]=Ka,Ka.__name__=["verb","eval","Intersect"],Ka.surfaces=function(a,b,c){var d=Qa.rationalSurfaceAdaptive(a),e=Qa.rationalSurfaceAdaptive(b),f=Ka.meshes(d,e),g=f.map(function(d){return d.map(function(d){return Ka.surfacesAtPointWithEstimate(a,b,d.uv0,d.uv1,c)})});return g.map(function(a){return La.rationalInterpCurve(a.map(function(a){return a.point}),3)})},Ka.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=Ja.rationalSurfaceDerivatives(a,c[0],c[1],1),g=f[0][0],i=f[1][0],j=f[0][1],h=Da.normalized(Da.cross(i,j)),k=Da.dot(h,g),l=Ja.rationalSurfaceDerivatives(b,d[0],d[1],1),m=l[0][0],o=l[1][0],p=l[0][1],n=Da.normalized(Da.cross(o,p)),q=Da.dot(n,m),r=Da.distSquared(g,m),e*e>r)break;var u=Da.normalized(Da.cross(h,n)),v=Da.dot(u,g),w=Ka.threePlanes(h,k,n,q,u,v);if(null==w)throw new D("panic!");var x=Da.sub(w,g),y=Da.sub(w,m),z=Da.cross(i,h),A=Da.cross(j,h),B=Da.cross(o,n),C=Da.cross(p,n),E=Da.dot(A,x)/Da.dot(A,i),F=Da.dot(z,x)/Da.dot(z,j),G=Da.dot(C,y)/Da.dot(C,o),H=Da.dot(B,y)/Da.dot(B,p);c=Da.add([E,F],c),d=Da.add([G,H],d),t++}while(s>t);return new ga(c,d,g,r)},Ka.meshes=function(a,b,c,d){null==c&&(c=new ra(a)),null==d&&(d=new ra(b));var e=Ka.boundingBoxTrees(c,d,0),f=Q.unique(e.map(function(c){return Ka.triangles(a,c.item0,b,c.item1)}).filter(function(a){return null!=a}).filter(function(a){return Da.distSquared(a.min.point,a.max.point)>T.EPSILON}),function(a,b){var c=Da.sub(a.min.uv0,b.min.uv0),d=Da.dot(c,c),e=Da.sub(a.max.uv0,b.max.uv0),f=Da.dot(e,e),g=Da.sub(a.min.uv0,b.max.uv0),h=Da.dot(g,g),i=Da.sub(a.max.uv0,b.min.uv0),j=Da.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 aa(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},Ka.curves=function(a,b,c){var d=Ka.boundingBoxTrees(new qa(a),new qa(b),0);return Q.unique(d.map(function(d){return Ka.curvesWithEstimate(a,b,Q.first(d.item0.knots),Q.first(d.item1.knots),c)}).filter(function(a){return Da.distSquared(a.point0,a.point1)m;){var n=m++,o=e[n],p=i[n],q=Ka.rays(o,p,a.origin,a.dir);if(null!=q){var r=q.u0,s=q.u1;r<-T.EPSILON||r>j[n]+T.EPSILON||((null==k||sl.u)&&(l=new ia(s,Da.onRay(a.origin,a.dir,s),Da.onRay(f[n],g[n],r/j[n]))))}}return null==l||null==k?null:new ba(k,l)},Ka.mergeTriangleClipIntervals=function(a,b,c,d,e,f){if(b.min.u>a.max.u+T.EPSILON||a.min.u>b.max.u+T.EPSILON)return null;var g;g=a.min.u>b.min.u?new aa(a.min,0):new aa(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=-Da.dot(a,b),p=-Da.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 W(n,Da.normalized(e))},Ka.threePlanes=function(a,b,c,d,e,f){var g=Da.cross(c,e),h=Da.dot(a,g);if(Math.abs(h)q)return new ca(o,p,m,n)}return null},Ka.rays=function(a,b,c,d){var e=Da.dot(b,d),f=Da.dot(b,c),g=Da.dot(b,a),h=Da.dot(d,c),i=Da.dot(d,a),j=Da.dot(b,b),k=Da.dot(d,d),l=j*k-e*e;if(Math.abs(l)o||o>1)return null;var p=Da.add(a,Da.mul(o,k)),q=Da.dot(h,i),r=Da.dot(h,h),s=Da.dot(i,i),t=Da.sub(p,e),u=Da.dot(t,h),v=Da.dot(t,i),w=q*q-r*s;if(Math.abs(w)1+T.EPSILON||y>1+T.EPSILON||y<-T.EPSILON||x<-T.EPSILON||x+y>1+T.EPSILON?null:new ha(p,x,y,o)},Ka.segmentAndPlane=function(a,b,c,d){var e=Da.dot(d,Da.sub(b,a));if(Math.abs(e)1+T.EPSILON||g<-T.EPSILON?null:{p:g}};var La=b.eval.Make=function(){};g["verb.eval.Make"]=La,La.__name__=["verb","eval","Make"],La.rationalTranslationalSurface=function(a,b){for(var c=Ja.rationalCurvePoint(b,Q.first(b.knots)),d=Q.first(b.knots),e=Q.last(b.knots),f=2*b.controlPoints.length,g=(e-d)/(f-1),h=[],i=0;f>i;){var j=i++,k=Da.sub(Ja.rationalCurvePoint(b,d+j*g),c),l=Ma.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 La.loftedSurface(h)},La.surfaceBoundaryCurves=function(a){var b=La.surfaceIsocurve(a,Q.first(a.knotsU),!1),c=La.surfaceIsocurve(a,Q.last(a.knotsU),!1),d=La.surfaceIsocurve(a,Q.first(a.knotsV),!0),e=La.surfaceIsocurve(a,Q.last(a.knotsV),!0);return[b,c,d,e]},La.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=Ea.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?Ma.surfaceKnotRefine(a,Da.rep(k,b),c):a;var m=Ja.knotSpan(e,b,d);return Math.abs(b-Q.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=La.rationalInterpCurve(j,b,!0);f.push(k.controlPoints),e=k.knots}return new Y(c,b,d,e,f)},La.clonedCurve=function(a){return new X(a.degree,a.knots.slice(),a.controlPoints.map(function(a){return a.slice()}))},La.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=Da.rep(a.length,1)),new X(c,d,Ja.homogenize1d(a,b))},La.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=Da.lerp(o,a,b),q=Da.lerp(o,d,c),r=Da.lerp(1-n/f,p,q);r.push(1),k.push(r)}g.push(k)}var s=Da.rep(e+1,0),t=Da.rep(e+1,1);return new Y(e,e,s.concat(t),s.concat(t),g)},La.ellipseArc=function(a,b,c,d,e){var f=Da.norm(b),g=Da.norm(c);b=Da.normalized(b),c=Da.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=Da.add(a,Da.add(Da.mul(f*Math.cos(d),b),Da.mul(g*Math.sin(d),c))),m=Da.sub(Da.mul(Math.cos(d),c),Da.mul(Math.sin(d),b)),n=[],o=Da.zeros1d(2*i+3),p=0,q=d,r=Da.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=Da.add(a,Da.add(Da.mul(f*Math.cos(q),b),Da.mul(g*Math.sin(q),c)));r[p+2]=1,n[p+2]=v;var w=Da.sub(Da.mul(Math.cos(q),c),Da.mul(Math.sin(q),b)),x=Ka.rays(l,Da.mul(1/Da.norm(m),m),v,Da.mul(1/Da.norm(w),w)),y=Da.add(l,Da.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 X(2,o,Ja.homogenize1d(n,r))},La.arc=function(a,b,c,d,e,f){return La.ellipseArc(a,Da.mul(d,Da.normalized(b)),Da.mul(d,Da.normalized(c)),e,f)},La.polyline=function(a){for(var b=[0,0],c=0,d=0,e=a.length-1;e>d;){var f=d++;c+=Da.dist(a[f],a[f+1]),b.push(c)}b.push(c),b=Da.mul(1/c,b);for(var g,h=[],i=0,j=a.length;j>i;){i++;h.push(1)}return g=h,new X(1,b,Ja.homogenize1d(a.slice(0),g))},La.extrudedSurface=function(a,b,c){for(var d=[[],[],[]],e=[[],[],[]],f=Ja.dehomogenize1d(c.controlPoints),g=Ja.weight1d(c.controlPoints),h=Da.mul(b,a),i=Da.mul(.5*b,a),j=0,k=f.length;k>j;){var l=j++;d[2][l]=f[l],d[1][l]=Da.add(i,f[l]),d[0][l]=Da.add(h,f[l]),e[0][l]=g[l],e[1][l]=g[l],e[2][l]=g[l]}return new Y(2,c.degree,[0,0,0,1,1,1],c.knots,Ja.homogenize2d(d,e))},La.cylindricalSurface=function(a,b,c,d,e){var f=Da.cross(a,b),g=(2*Math.PI,La.arc(c,b,f,e,0,2*Math.PI));return La.extrudedSurface(a,d,g)},La.revolvedSurface=function(a,b,c,d){var e,f,g=Ja.dehomogenize1d(a.controlPoints),h=Ja.weight1d(a.controlPoints);d<=Math.PI/2?(e=1,f=Da.zeros1d(6+2*(e-1))):d<=Math.PI?(e=2,f=Da.zeros1d(6+2*(e-1)),f[3]=f[4]=.5):d<=3*Math.PI/2?(e=3,f=Da.zeros1d(6+2*(e-1)),f[3]=f[4]=.3333333333333333,f[5]=f[6]=.6666666666666666):(e=4,f=Da.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=Da.zeros1d(e+1),p=Da.zeros1d(e+1),q=Da.zeros3d(2*e+1,g.length,3),r=Da.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=Ca.rayClosestPoint(g[x],b,c),z=Da.sub(g[x],y),A=Da.norm(z),B=Da.cross(c,z);A>T.EPSILON&&(z=Da.mul(1/A,z),B=Da.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:Da.add(y,Da.add(Da.mul(A*p[I],z),Da.mul(A*o[I],B))),q[E+2][x]=H,r[E+2][x]=h[x];var J=Da.sub(Da.mul(p[I],B),Da.mul(o[I],z));if(0==A)q[E+1][x]=y;else{var K=Ka.rays(C,Da.mul(1/Da.norm(D),D),H,Da.mul(1/Da.norm(J),J)),L=Da.add(C,Da.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 Y(2,a.degree,f,a.knots,Ja.homogenize2d(q,r))},La.sphericalSurface=function(a,b,c,d){var e=La.arc(a,Da.mul(-1,b),c,d,0,Math.PI);return La.revolvedSurface(e,a,b,2*Math.PI)},La.conicalSurface=function(a,b,c,d,e){var f=2*Math.PI,g=1,h=[Da.add(c,Da.mul(d,a)),Da.add(c,Da.mul(e,b))],i=[0,0,1,1],j=[1,1],k=new X(g,i,Ja.homogenize1d(h,j));return La.revolvedSurface(k,c,a,f)},La.rationalInterpCurve=function(a,b,c,d,e){if(null==c&&(c=!1),null==b&&(b=3),a.lengthg;){var i=g++,j=Da.norm(Da.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=Da.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(Da.rep(b+1,1)),A=[];y=r?a.length+1:a.length-1;var B;B=r?1:0;var C;C=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 W=1,Y=a.length-1;Y>W;){var Z=W++;U.push(a[Z][V[0]])}U.push(R*e[V[0]]),U.push(Q.last(a)[V[0]]); +}else U=a.map(function(a){return function(b){return b[a[0]]}}(V));var $=ua.solve(A,U);P.push($)}var _=ua.transpose(P);if(!c){var aa=Da.rep(_.length,1);_=Ja.homogenize1d(_,aa)}return new X(b,z,_)};var Ma=b.eval.Modify=function(){};g["verb.eval.Modify"]=Ma,Ma.__name__=["verb","eval","Modify"],Ma.curveReverse=function(a){return new X(a.degree,Ma.knotsReverse(a.knots),Q.reversed(a.controlPoints))},Ma.surfaceReverse=function(a,b){return null==b&&(b=!1),b?new Y(a.degreeU,a.degreeV,a.knotsU,Ma.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},Ma.unifyCurveKnotVectors=function(a){a=a.map(La.clonedCurve);for(var b=j.fold(a,function(a,b){return Ma.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 Da.sortedSetUnion(a.knots,b)},[]),v=0,w=a.length;w>v;){var x=v++,y=Da.sortedSetSub(u,a[x].knots);0==y.length&&(a[x]=a[x]),a[x]=Ma.curveKnotRefine(a[x],y)}return a},Ma.imin=function(a,b){return b>a?a:b},Ma.imax=function(a,b){return a>b?a:b},Ma.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=Da.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/R.get(o,u),w=Ma.imin(e,u),x=Ma.imax(0,u-h),y=w+1;y>x;){var z=x++;j[u][z]=v*R.get(e,z)*R.get(h,u-z)}for(var A=p+1;o>A;)for(var B=A++,C=Ma.imin(e,B),D=Ma.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 Q=0,S=e+1;S>Q;){var T=Q++;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,W=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 _=W-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]=Da.add(Da.mul(aa[ha-ga],k[ha]),Da.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]=Da.zeros1d(i);for(var la=Ma.imin(e,ka),ma=Ma.imax(0,ka-h),na=la+1;na>ma;){var oa=ma++;l[ka]=Da.add(l[ka],Da.mul(j[ka][oa],k[oa]))}}if(Y>1)for(var pa=H-2,qa=H,ra=W-M,sa=(W-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=(W-r[va])/(M-r[va]);q[va]=Da.lerp(ya,q[va],q[va-1])}if(wa>=Z){if(H-o+Y>=wa-ua){var za=(W-r[wa-ua])/ra;l[xa]=Da.lerp(za,l[xa],l[xa+1])}}else l[xa]=Da.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 Ca=Z,Ea=$+1;Ea>Ca;){var Fa=Ca++;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=W}else for(var La=0,Na=o+1;Na>La;){var Oa=La++;r[H+Oa]=W}}return c=G-o-1,new X(b,r,q)},Ma.rationalSurfaceTransform=function(a,b){for(var c=Ja.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]=ua.dot(b,j).slice(0,j.length-1)}return new Y(a.degreeU,a.degreeV,a.knotsU.slice(),a.knotsV.slice(),Ja.homogenize2d(c,Ja.weight2d(a.controlPoints)))},Ma.rationalCurveTransform=function(a,b){for(var c=Ja.dehomogenize1d(a.controlPoints),d=0,e=c.length;e>d;){var f=d++,g=c[f];g.push(1),c[f]=ua.dot(b,g).slice(0,g.length-1)}return new X(a.degree,a.knots.slice(),Ja.homogenize1d(c,Ja.weight1d(a.controlPoints)))},Ma.surfaceKnotRefine=function(a,b,c){if(0==b.length)return La.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=Ja.knotSpan(d,b[0],e),k=Ja.knotSpan(d,b[i],e),l=[],m=[];if(c){for(var n=Ea.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 S=Q-d-1,U=P-d-1;if(c)for(var V=0,W=l.length;W>V;){var X=V++;l[X][S]=f[X][U].slice(0)}else l[S]=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]=Da.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]=Da.lerp(ea,l[da-1][na],l[da][na])}}m[Q]=b[R],Q-=1,R--}return c?new Y(a.degreeU,a.degreeV,a.knotsU.slice(),m,l):new Y(a.degreeU,a.degreeV,m,a.knotsV.slice(),l)},Ma.decomposeSurfaceIntoBeziers=function(a){for(var b=Ea.knotMultiplicities(a.knotsU),c=a.degreeU+1,d=0;dg;){var i=g++;f.push(a[i].slice(c,c+e))}return f},Ma.decomposeCurveIntoBeziers=function(a){for(var b=a.degree,c=a.controlPoints,d=a.knots,e=Ea.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]=Da.add(Da.mul(1-E,j[K]),Da.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 X(d,k,l)};var Na=function(){};g["verb.eval.NewMeshData"]=Na,Na.__name__=["verb","eval","NewMeshData"],Na.prototype={__class__:Na};var Oa=function(){};g["verb.eval.BezierEdgeIndices"]=Oa,Oa.__name__=["verb","eval","BezierEdgeIndices"],Oa.prototype={__class__:Oa};var Pa=g["verb.eval.EdgeSide"]={__ename__:["verb","eval","EdgeSide"],__constructs__:["North","South","East","West"]};Pa.North=["North",0],Pa.North.toString=h,Pa.North.__enum__=Pa,Pa.South=["South",1],Pa.South.toString=h,Pa.South.__enum__=Pa,Pa.East=["East",2],Pa.East.toString=h,Pa.East.__enum__=Pa,Pa.West=["West",3],Pa.West.toString=h,Pa.West.__enum__=Pa;var Qa=b.eval.Tess=function(){};g["verb.eval.Tess"]=Qa,Qa.__name__=["verb","eval","Tess"],Qa.rationalBezierSurfaceRegularSample=function(a,b,c){for(var d=[],e=a.knotsU[0],f=(Q.last(a.knotsU)-a.knotsU[0])/b,g=0;b>g;){var h=(g++,La.surfaceIsocurve(a,e,!0));(Q.last(h.knots)-h.knots[0])/c;Qa.rationalBezierCurveRegularSamplePointsMutate(h,d,h.knots[0],f,c,!1),e+=f}return d},Qa.northIndex=function(a,b,c){return 0>=a?null:c[a-1][b]},Qa.southIndex=function(a,b,c){return a>=c.length-1?null:c[a+1][b]},Qa.eastIndex=function(a,b,c){return b>=c[a].length-1?null:c[a][b+1]},Qa.westIndex=function(a,b,c){return 0>=b?null:c[a][b-1]},Qa.rationalSurfaceAdaptiveSample=function(a,b){var c=Ma.decomposeSurfaceIntoBeziers(a);t.trace(c.length,{fileName:"Tess.hx",lineNumber:91,className:"verb.eval.Tess",methodName:"rationalSurfaceAdaptiveSample",customParams:[c[0].length]});for(var d,e=[],f=0;fu;){var w=u++;l=[],s.push(l);for(var x=0,y=c[w].length;y>x;){var z=x++;if(p=c[w][z],m=new Oa,l.push(m),j=Qa.southIndex(w,z,e),null==j&&(j=r),k=Qa.eastIndex(w,z,e),null==k&&(k=r),0==w){var A=La.surfaceIsocurve(p,Q.first(p.knotsU),!1);n=q.length,Qa.rationalBezierCurveRegularSamplePointsMutate2(A,q,e[w][z].item1),o=q.length,m.n=new aa(n,o)}else m.n=s[w-1][z].s;if(0==z){n=q.length;var B=La.surfaceIsocurve(p,Q.first(p.knotsV),!0);Qa.rationalBezierCurveRegularSamplePointsMutate2(B,q,e[w][z].item0),o=q.length,m.w=new aa(n,o)}else m.w=s[w][z-1].e;n=q.length;var C=La.surfaceIsocurve(p,Q.last(p.knotsU),!1);Qa.rationalBezierCurveRegularSamplePointsMutate2(C,q,Math.min(j.item1,e[w][z].item1)),o=q.length,m.s=new aa(n,o),n=q.length;var D=La.surfaceIsocurve(p,Q.last(p.knotsV),!0);Qa.rationalBezierCurveRegularSamplePointsMutate2(D,q,Math.min(k.item0,e[w][z].item0)),o=q.length,m.e=new aa(n,o)}}for(var E,F=[],G=0,H=c.length;H>G;)for(var I=G++,J=0,K=c[I].length;K>J;){var L=J++;E=q.length;for(var M=c[I][L],N=Math.ceil(1/e[I][L].item0),O=Q.last(M.knotsV)-M.knotsV[0],P=Q.last(M.knotsU)-M.knotsU[0],R=Math.ceil(1/e[I][L].item1),S=O/R,T=P/N,U=M.knotsU[0]+T,V=0,W=N-1;W>V;){var X=(V++,La.surfaceIsocurve(M,U,!1));Qa.rationalBezierCurveRegularSamplePointsMutate(X,q,X.knots[0]+S,S,R-1,!1),U+=T}N-=2,R-=2;for(var Y=0;N>Y;)for(var $=Y++,_=0;R>_;){var ba=_++,ca=E+$*(R+1)+ba,da=E+($+1)*(R+1)+ba,ea=da+1,fa=ca+1,ga=[ca,da,ea],ha=[ca,ea,fa];F.push(ga),F.push(ha)}m=s[I][L],Qa.stitchMesh(M,F,m,N,R,O,E,S,Pa.North),Qa.stitchMesh(M,F,m,N,R,O,E,S,Pa.South),Qa.stitchMesh(M,F,m,N,R,P,E,T,Pa.East),Qa.stitchMesh(M,F,m,N,R,P,E,T,Pa.West)}return new Z(F,q,null,null)},Qa.stitchMesh=function(a,b,c,d,e,f,g,h,i){var j,k,l=!1,m=1;switch(i[1]){case 0:j=c.n,k=a.knotsV;break;case 1:j=c.s,k=a.knotsV,g+=d*(e+1),l=!0;break;case 2:j=c.e,k=a.knotsU,m=e+1,g+=e;break;case 3:j=c.w,k=a.knotsU,m=e+1,l=!0}for(var n=j.item1-j.item0-1,o=f/n,p=Q.first(k),q=Q.first(k)+1.5*h,r=0,s=0;n>r;){for(;pr;){var t=j.item0+r,u=t+1;l?b.push([t,u,g+s]):b.push([t,g+s,u]),r++,p+=o}if(n>r){var v=j.item0+r;l?b.push([g+s,v,g+s+m]):b.push([g+s,g+s+m,v])}s+=m,q+=h}},Qa.rationalBezierCurveRegularSamplePointsMutate2=function(a,b,c,d){null==d&&(d=!1);var e=Q.last(a.knots)-a.knots[0],f=Math.ceil(1/c),g=e/f;Qa.rationalBezierCurveRegularSamplePointsMutate(a,b,a.knots[0],g,f+1,!1)},Qa.rationalBezierSurfaceStepLength=function(a,b){for(var c=Ja.dehomogenize2d(a.controlPoints),d=new S,e=0;el;)for(var n=l++,o=0,p=c[n].length;p>o;){var q=o++;j=Da.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=Da.norm(Da.add(c[v+2][y],Da.add(Da.mul(-2,c[v+1][y]),c[v][y])))-(k-b)*(Q.last(i.controlPoints[v+2][y])-2*Q.last(i.controlPoints[v+1][y])+Q.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=Da.norm(Da.add(c[D][G+2],Da.add(Da.mul(-2,c[D][G+1]),c[D][G])))-(k-b)*(Q.last(i.controlPoints[D][G+2])-2*Q.last(i.controlPoints[D][G+1])+Q.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=Da.norm(Da.addAll([c[L+1][O+1],Da.mul(-1,c[L][O+1]),Da.mul(-1,c[L+1][O]),c[L][O]]))-(k-b)*(Q.last(i.controlPoints[L+1][O+1])-Q.last(i.controlPoints[L][O+1])-Q.last(i.controlPoints[L+1][O])+Q.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 P,R=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++;P=Q.last(a.controlPoints[W][Z]),R>P&&(R=P)}var $,_;if(Math.abs(s)e;){var g=e++;d.push(Ja.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=Q.last(a.knots)-a.knots[0];k=a.knots.length==2*(a.degree+1)?[a]:Ma.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=Q.last(k[u].knots)-q,n=Math.ceil(m/r),o=q+n*r,o>Q.last(k[u].knots)+T.TOLERANCE&&(o-=r,n--),Qa.rationalBezierCurveRegularSamplePointsMutate(k[u],p,q,r,n+1,c),q=o+r}return p},Qa.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(Ja.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]:Ma.decomposeCurveIntoBeziers(a);for(var l,m,n,o=[],p=0,q=k.length;q>p;){var r=p++;if(m=Q.last(k[r].knots)-k[r].knots[0],n=Qa.rationalBezierCurveStepLength(k[r],b),l=Math.ceil(m/n),n=m/l,Qa.rationalBezierCurveRegularSamplePointsMutate(k[r],o,k[r].knots[0],n,l+1,c),r==k.length-1)break;o.pop()}return o},Qa.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(Ja.rationalCurvePoint(a,i)),i+=d}else{for(var l=0;j>l;){l++;g.push(Ja.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(Da.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,Da.addMutate(v[z],v[z+1])}b.push(Ja.dehomogenize(v[0]))}if(i=c,f)for(var G=0;Gj;){var l=j++;h=Da.norm(c[l]),h>i&&(i=h)}var m=Ja.weight1d(a.controlPoints),n=Da.min(m),o=Q.last(a.knots)-a.knots[0];if(i>b){for(var p,q=8*n*b,r=Qa.secondForwardDiff(m),s=Qa.secondForwardDiff2(c),t=[],u=0,v=s.length;v>u;){var w=u++;t.push(Da.norm(s[w])+(i-b)*r[w])}p=t;var x=Da.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=Qa.secondForwardDiff2(c),C=[],D=0,E=B.length;E>D;){var F=D++;C.push(Da.norm(B[F]))}z=C;var G=Da.max(z),H=a.degree*(a.degree-1)*G;return o*Math.sqrt(A/H)}return o},Qa.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=Q.last(d)-d[0],g=Q.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=Ja.rationalSurfaceDerivatives(a,s,t,1),v=u[0][0];j.push(v);var w=Da.normalized(Da.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 Z(x,j,l,k)},Qa.divideRationalSurfaceAdaptive=function(a,b){null==b&&(b=new Ra),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=Q.last(a.knotsU),h=a.knotsU[0],i=Q.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=Ja.rationalSurfaceDerivatives(a,v,w,1),y=Da.normalized(Da.cross(x[0][1],x[1][0]));r.push(new ja(x[0][0],y,[v,w],-1,Da.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 Sa(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=Qa.north(I,F,H,c,f,m),K=Qa.east(I,F,H,c,f,m),L=Qa.south(I,F,H,c,f,m),M=Qa.west(I,F,H,c,f,m);m[I].neighbors=[L,K,J,M],m[I].divide(b)}return m},Qa.north=function(a,b,c,d,e,f){return 0==b?null:f[a-d]},Qa.south=function(a,b,c,d,e,f){return b==e-1?null:f[a+d]},Qa.east=function(a,b,c,d,e,f){return c==d-1?null:f[a+1]},Qa.west=function(a,b,c,d,e,f){return 0==c?null:f[a-1]},Qa.triangulateAdaptiveRefinementNodeTree=function(a){for(var b=Z.empty(),c=0;cs;){var t=s++,u=[];p.push(u);for(var v=0;r>v;){var w=v++;u.push(Ja.surfacePointGivenBasesKnotSpans(d,e,f,k[t],n[w],l[t],o[w],i))}}return p},Qa.surfaceRegularSample2=function(a,b,c){for(var d=[],e=a.knotsU[0],f=(Q.last(a.knotsU)-a.knotsU[0])/b,g=0;b>g;){var h=(g++,La.surfaceIsocurve(a,e,!0));d.push(Qa.rationalCurveRegularSample(h,c)),e+=f}return d};var Ra=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"]=Ra,Ra.__name__=["verb","eval","AdaptiveRefinementOptions"],Ra.prototype={__class__:Ra};var Sa=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=Q.last(a.knotsU),f=a.knotsV[0],g=Q.last(a.knotsV);this.corners=[ja.fromUv(d,f),ja.fromUv(e,f),ja.fromUv(e,g),ja.fromUv(d,g)]}};g["verb.eval.AdaptiveRefinementNode"]=Sa,Sa.__name__=["verb","eval","AdaptiveRefinementNode"],Sa.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=Ja.rationalSurfaceDerivatives(this.srf,a,b,1),e=d[0][0],f=Da.cross(d[0][1],d[1][0]),g=Da.isZero(f);return g||(f=Da.normalized(f)),null!=c?(c.degen=g,c.point=e,c.normal=f,c):new ja(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=T.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=Da.normSquared(Da.sub(this.corners[0].normal,this.corners[1].normal))>a.normTol||Da.normSquared(Da.sub(this.corners[2].normal,this.corners[3].normal))>a.normTol,this.splitHoriz=Da.normSquared(Da.sub(this.corners[1].normal,this.corners[2].normal))>a.normTol||Da.normSquared(Da.sub(this.corners[3].normal,this.corners[0].normal))>a.normTol,this.splitVert||this.splitHoriz)return!0;var c=this.center();return Da.normSquared(Da.sub(c.normal,this.corners[0].normal))>a.normTol||Da.normSquared(Da.sub(c.normal,this.corners[1].normal))>a.normTol||Da.normSquared(Da.sub(c.normal,this.corners[2].normal))>a.normTol||Da.normSquared(Da.sub(c.normal,this.corners[3].normal))>a.normTol},divide:function(a){null==a&&(a=new Ra),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 Sa(this.srf,d),new Sa(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 Sa(this.srf,f),new Sa(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(Ua.basePath+b)}catch(e){e instanceof D&&(e=e.val),d=new Worker(Ua.basePath+b.substring(0,-3)+".min.js")}this._pool.push(d)}};g["verb.exe.WorkerPool"]=Ua,Ua.__name__=["verb","exe","WorkerPool"],Ua.prototype={addWork:function(a,b,c,d){var e=new Va(a,b,c);this._callbacks.set(e.id,d),this._queue.push(e),this.processQueue()},processQueue:function(){for(var a=this;this._queue.length>0&&this._pool.length>0;){var b=this._queue.shift(),c=[b.id],d=[this._pool.shift()];this._working.h[c[0]]=d[0],d[0].onmessage=function(b,c){return function(d){a._working.remove(c[0]),a._pool.push(b[0]);try{a._callbacks.h.hasOwnProperty(c[0])&&(a._callbacks.h[c[0]](d.data.result),a._callbacks.remove(c[0]))}catch(e){e instanceof D&&(e=e.val),t.trace(e,{fileName:"WorkerPool.hx",lineNumber:81,className:"verb.exe.WorkerPool",methodName:"processQueue"})}a.processQueue()}}(d,c),d[0].postMessage(b)}},__class__:Ua};var Va=function(a,b,c){this.className=a,this.methodName=b,this.args=c,this.id=Va.uuid++};g["verb.exe._WorkerPool.Work"]=Va,Va.__name__=["verb","exe","_WorkerPool","Work"],Va.prototype={__class__:Va};var Wa=function(){};g["verb.geom.ICurve"]=Wa,Wa.__name__=["verb","geom","ICurve"],Wa.__interfaces__=[Aa],Wa.prototype={__class__:Wa};var Xa=b.geom.NurbsCurve=function(a){this._data=Ga.isValidNurbsCurveData(a)};g["verb.geom.NurbsCurve"]=Xa,Xa.__name__=["verb","geom","NurbsCurve"],Xa.__interfaces__=[Wa],Xa.byKnotsControlPointsWeights=function(a,b,c,d){return new Xa(new X(a,b.slice(),Ja.homogenize1d(c,d)))},Xa.byPoints=function(a,b){return null==b&&(b=3),new Xa(La.rationalInterpCurve(a,b))},Xa.__super__=U,Xa.prototype=d(U.prototype,{degree:function(){return this._data.degree},knots:function(){return this._data.knots.slice(0)},controlPoints:function(){return Ja.dehomogenize1d(this._data.controlPoints)},weights:function(){return Ja.weight1d(this._data.controlPoints)},asNurbs:function(){return new X(this.degree(),this.knots(),Ja.homogenize1d(this.controlPoints(),this.weights()))},clone:function(){return new Xa(this._data)},domain:function(){return new ba(Q.first(this._data.knots),Q.last(this._data.knots))},transform:function(a){return new Xa(Ma.rationalCurveTransform(this._data,a))},transformAsync:function(a){return Ta.dispatchMethod(Ma,"rationalCurveTransform",[this._data,a]).then(function(a){return new Xa(a)})},point:function(a){return Ja.rationalCurvePoint(this._data,a)},pointAsync:function(a){return Ta.dispatchMethod(Ja,"rationalCurvePoint",[this._data,a])},tangent:function(a){return Ja.rationalCurveTangent(this._data,a)},tangentAsync:function(a){return Ta.dispatchMethod(Ja,"rationalCurveTangent",[this._data,a])},derivatives:function(a,b){return null==b&&(b=1),Ja.rationalCurveDerivatives(this._data,a,b)},derivativesAsync:function(a,b){return null==b&&(b=1),Ta.dispatchMethod(Ja,"rationalCurveDerivatives",[this._data,a,b])},closestPoint:function(a){return Ea.rationalCurveClosestPoint(this._data,a)},closestPointAsync:function(a){return Ta.dispatchMethod(Ea,"rationalCurveClosestPoint",[this._data,a])},closestParam:function(a){return Ea.rationalCurveClosestParam(this._data,a)},closestParamAsync:function(a){return Ta.dispatchMethod(Ea,"rationalCurveClosestParam",[this._data,a])},length:function(){return Ea.rationalCurveArcLength(this._data)},lengthAsync:function(){return Ta.dispatchMethod(Ea,"rationalCurveArcLength",[this._data])},lengthAtParam:function(a){return Ea.rationalCurveArcLength(this._data,a)},lengthAtParamAsync:function(){return Ta.dispatchMethod(Ea,"rationalCurveArcLength",[this._data])},paramAtLength:function(a,b){return Ea.rationalCurveParamAtArcLength(this._data,a,b)},paramAtLengthAsync:function(a,b){return Ta.dispatchMethod(Ea,"rationalCurveParamAtArcLength",[this._data,a,b])},divideByEqualArcLength:function(a){return Ha.rationalCurveByEqualArcLength(this._data,a)},divideByEqualArcLengthAsync:function(a){return Ta.dispatchMethod(Ha,"rationalCurveByEqualArcLength",[this._data,a])},divideByArcLength:function(a){return Ha.rationalCurveByArcLength(this._data,a)},divideByArcLengthAsync:function(a){return Ta.dispatchMethod(Ha,"rationalCurveByArcLength",[this._data,a])},split:function(a){return Ha.curveSplit(this._data,a).map(function(a){return new Xa(a)})},splitAsync:function(a){return Ta.dispatchMethod(Ha,"curveSplit",[this._data,a]).then(function(a){return a.map(function(a){return new Xa(a)})})},reverse:function(){return new Xa(Ma.curveReverse(this._data))},reverseAsync:function(){return Ta.dispatchMethod(Ma,"curveReverse",[this._data]).then(function(a){return new Xa(a)})},tessellate:function(a){return null==a&&(a=.001),Qa.rationalCurveAdaptiveSample(this._data,a,!1)},tessellateAsync:function(a){return null==a&&(a=.001),Ta.dispatchMethod(Qa,"rationalCurveAdaptiveSample",[this._data,a,!1])},__class__:Xa});var Ya=b.geom.Arc=function(a,b,c,d,e,f){Xa.call(this,La.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"]=Ya,Ya.__name__=["verb","geom","Arc"],Ya.__super__=Xa,Ya.prototype=d(Xa.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__:Ya});var Za=b.geom.BezierCurve=function(a,b){Xa.call(this,La.rationalBezierCurve(a,b))};g["verb.geom.BezierCurve"]=Za,Za.__name__=["verb","geom","BezierCurve"],Za.__super__=Xa,Za.prototype=d(Xa.prototype,{__class__:Za});var $a=b.geom.Circle=function(a,b,c,d){Ya.call(this,a,b,c,d,0,2*Math.PI)};g["verb.geom.Circle"]=$a,$a.__name__=["verb","geom","Circle"],$a.__super__=Ya,$a.prototype=d(Ya.prototype,{__class__:$a});var _a=function(){};g["verb.geom.ISurface"]=_a,_a.__name__=["verb","geom","ISurface"],_a.__interfaces__=[Aa],_a.prototype={__class__:_a};var ab=b.geom.NurbsSurface=function(a){this._data=Ga.isValidNurbsSurfaceData(a)};g["verb.geom.NurbsSurface"]=ab,ab.__name__=["verb","geom","NurbsSurface"],ab.__interfaces__=[_a],ab.byKnotsControlPointsWeights=function(a,b,c,d,e,f){return new ab(new Y(a,b,c,d,Ja.homogenize2d(e,f)))},ab.byCorners=function(a,b,c,d){return new ab(La.fourPointSurface(a,b,c,d))},ab.byLoftingCurves=function(a,b){return new ab(La.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 tb={},ub=c.ArrayBuffer||F;null==ub.prototype.slice&&(ub.prototype.slice=F.sliceImpl);var vb=(c.DataView||G,c.Uint8Array||H._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")()),u.USE_CACHE=!1,u.USE_ENUM_INDEX=!1,u.BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:",v.DEFAULT_RESOLVER=q,v.BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:",x.count=0,C.i64tmp=function(a){var b,c=new s(0,0);return b=c}(this),E.__toStr={}.toString,H.BYTES_PER_ELEMENT=1,N.queue=new k,R.memo=new w,T.TOLERANCE=1e-6,T.EPSILON=1e-10,T.VERSION="2.0.0",Ea.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]],Ea.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]],Ta.THREADS=1,Ta._init=!1,Ua.basePath="",Va.uuid=0,P.main()}("undefined"!=typeof console?console:{log:function(){}},a,"undefined"!=typeof c?c:"undefined"!=typeof b?b:"undefined"!=typeof self?self:this),a}); \ No newline at end of file diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 2e7d33d3..315f67d6 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -255,12 +255,6 @@ haxe__$Int64__$_$_$Int64.__name__ = ["haxe","_Int64","___Int64"]; haxe__$Int64__$_$_$Int64.prototype = { __class__: haxe__$Int64__$_$_$Int64 }; -var haxe_Log = function() { }; -$hxClasses["haxe.Log"] = haxe_Log; -haxe_Log.__name__ = ["haxe","Log"]; -haxe_Log.trace = function(v,infos) { - js_Boot.__trace(v,infos); -}; var haxe_Serializer = function() { this.buf = new StringBuf(); this.cache = []; @@ -995,25 +989,6 @@ js__$Boot_HaxeError.prototype = $extend(Error.prototype,{ var js_Boot = function() { }; $hxClasses["js.Boot"] = js_Boot; js_Boot.__name__ = ["js","Boot"]; -js_Boot.__unhtml = function(s) { - return s.split("&").join("&").split("<").join("<").split(">").join(">"); -}; -js_Boot.__trace = function(v,i) { - var msg; - if(i != null) msg = i.fileName + ":" + i.lineNumber + ": "; else msg = ""; - msg += js_Boot.__string_rec(v,""); - if(i != null && i.customParams != null) { - var _g = 0; - var _g1 = i.customParams; - while(_g < _g1.length) { - var v1 = _g1[_g]; - ++_g; - msg += "," + js_Boot.__string_rec(v1,""); - } - } - var d; - if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js_Boot.__unhtml(msg) + "
"; else if(typeof console != "undefined" && console.log != null) console.log(msg); -}; js_Boot.getClass = function(o) { if((o instanceof Array) && o.__enum__ == null) return Array; else { var cl = o.__class__; @@ -1889,7 +1864,7 @@ var verb_Verb = function() { }; $hxClasses["verb.Verb"] = verb_Verb; verb_Verb.__name__ = ["verb","Verb"]; verb_Verb.main = function() { - haxe_Log.trace("verb 2.0.0",{ fileName : "Verb.hx", lineNumber : 45, className : "verb.Verb", methodName : "main"}); + console.log("verb 2.0.0"); }; var verb_core_ArrayExtensions = function() { }; $hxClasses["verb.core.ArrayExtensions"] = verb_core_ArrayExtensions; @@ -6500,7 +6475,6 @@ verb_eval_Tess.westIndex = function(i,j,divs) { }; verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { var beziers = verb_eval_Modify.decomposeSurfaceIntoBeziers(surface); - haxe_Log.trace(beziers.length,{ fileName : "Tess.hx", lineNumber : 91, className : "verb.eval.Tess", methodName : "rationalSurfaceAdaptiveSample", customParams : [beziers[0].length]}); var stepLengths = []; var stepLengthRow; var _g = 0; @@ -6661,16 +6635,6 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess var tessU = verb_core_ArrayExtensions.first(knots) + 1.5 * tessStep; var edgeI = 0; var tessI = 0; - haxe_Log.trace("edgeCount",{ fileName : "Tess.hx", lineNumber : 318, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeCount]}); - haxe_Log.trace("divsU",{ fileName : "Tess.hx", lineNumber : 319, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsU]}); - haxe_Log.trace("divsV",{ fileName : "Tess.hx", lineNumber : 320, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [divsV]}); - haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 322, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); - haxe_Log.trace("edgeStep",{ fileName : "Tess.hx", lineNumber : 323, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeStep]}); - haxe_Log.trace("tessStep",{ fileName : "Tess.hx", lineNumber : 324, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessStep]}); - haxe_Log.trace("tessU",{ fileName : "Tess.hx", lineNumber : 326, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessU]}); - haxe_Log.trace("edgeU",{ fileName : "Tess.hx", lineNumber : 327, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [edgeU]}); - haxe_Log.trace("tessI",{ fileName : "Tess.hx", lineNumber : 329, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessI]}); - haxe_Log.trace("tessIStep",{ fileName : "Tess.hx", lineNumber : 330, className : "verb.eval.Tess", methodName : "stitchMesh", customParams : [tessIStep]}); while(edgeI < edgeCount) { while(edgeU < tessU - verb_core_Constants.EPSILON && edgeI < edgeCount) { var ei = edgeIndices.item0 + edgeI; @@ -7555,7 +7519,7 @@ verb_exe_WorkerPool.prototype = { } } catch( error ) { if (error instanceof js__$Boot_HaxeError) error = error.val; - haxe_Log.trace(error,{ fileName : "WorkerPool.hx", lineNumber : 81, className : "verb.exe.WorkerPool", methodName : "processQueue"}); + console.log(error); } _g.processQueue(); }; diff --git a/examples/surfaceAdaptiveTessellation2.html b/examples/surfaceAdaptiveTessellation2.html index f17820a7..2269b96a 100644 --- a/examples/surfaceAdaptiveTessellation2.html +++ b/examples/surfaceAdaptiveTessellation2.html @@ -132,9 +132,10 @@ // surface = getBezier(); - var tol = 0.3; + var tol = 0.1; var mat2 = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, wireframe: true }); + var mat3 = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide, wireframe: true }); var l = verb.eval.Tess.rationalBezierSurfaceStepLength( surface, tol ); var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface ); @@ -153,9 +154,12 @@ // add the edge points to the scene var mesh = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface, tol ); + var mesh2 = verb.eval.Tess.rationalSurfaceAdaptive( surface ); addMeshToScene( getThreeMesh( mesh ) ); - addMeshToScene( getThreeMesh( mesh ), mat2 ); + //addMeshToScene( getThreeMesh( mesh2 ), mat3 ); + // addMeshToScene( getThreeMesh( mesh ), mat2 ); + // addPointsToScene( mesh.points ); renderScene(); diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index eee2625e..6ddf05a9 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -88,8 +88,6 @@ class Tess { var beziers = Modify.decomposeSurfaceIntoBeziers( surface ); - trace(beziers.length, beziers[0].length); - // get step lengths for patches var stepLengths : Array>> = [] @@ -168,6 +166,7 @@ class Tess { e1 = pts.length; bei.w = new Pair(e0, e1); + } else { bei.w = beis[i][j-1].e; } @@ -196,9 +195,7 @@ class Tess { } } -// pts = []; - - // tessellate patches, merging into a single mesh + // tessellate patches, merging into a single mesh by reusing the edge points var faces = [], p0; @@ -264,7 +261,6 @@ class Tess { 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 ); - } } @@ -279,7 +275,6 @@ class Tess { var reverseFace = false; var tessIStep = 1; - switch (edgeSide) { case EdgeSide.North: edgeIndices = bei.n; @@ -315,20 +310,6 @@ class Tess { var edgeI = 0; var tessI = 0; - trace("edgeCount", edgeCount); - trace("divsU", divsU); - trace("divsV", divsV); - - trace("edgeU", edgeU); - trace("edgeStep", edgeStep); - trace("tessStep", tessStep); - - trace("tessU", tessU); - trace("edgeU", edgeU); - - trace("tessI", tessI); - trace("tessIStep", tessIStep); - // triangulate the northwest corner while ( edgeI < edgeCount ){ diff --git a/test/testEval.js b/test/testEval.js index f62b4614..af1c785f 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -4317,24 +4317,48 @@ describe("verb.eval.Modify.surfaceKnotRefine",() => { describe("verb.eval.Modify.decomposeSurfaceIntoBeziers",() => { - 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] ] ] - , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); + var getSurface11 = () => { - it('can add knots into a surface 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 ); + + return bezier; + }; + + var getSurface23 = () => { - var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface ); + 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; - res.forEach((x,k) => { + decomp.forEach((x,k) => { x.forEach((y, l) => { var u0 = u = y.knotsU[0]; @@ -4364,19 +4388,23 @@ describe("verb.eval.Modify.decomposeSurfaceIntoBeziers",() => { }); }); -// 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 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 2 x 3 set of bezier patches with no distortion', () => { + + var surface11 = getSurface11(); + var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface11 ); + + checkSurfaceDecomposition( surface11, res, 1, 1 ); }); }); diff --git a/todo b/todo index c9f292ee..c702e1bc 100644 --- a/todo +++ b/todo @@ -1,11 +1,15 @@ -Documentation generation - docco no longer works, always sucked anyways -Update website +Complete forward differencing algorithm + + - degenerate cases (e.g. no interior points, cylinder) + - provide UVs + - approximate normals + - exact normals + - tests (spheres, circles) Split Holes are not recognized 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 From da77d3998d1f1444e545151134415066f26cf326 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Mon, 8 Feb 2016 13:48:52 -0500 Subject: [PATCH 21/25] Ensure handling of flat faces in forward differencing tessellation --- build/js/verb.js | 7 ++- build/js/verbHaxe.js | 7 ++- examples/surfaceAdaptiveTessellation2.html | 70 ++++++++++++---------- src/verb/Verb.hx | 2 +- src/verb/eval/Tess.hx | 18 ++++-- test/testEval.js | 70 +++++++++++++++++++++- todo | 8 ++- 7 files changed, 135 insertions(+), 47 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index c1bb1020..31b0f816 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -1933,7 +1933,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; @@ -6556,7 +6556,10 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { while(_g1 < bezierrow.length) { var bezier = bezierrow[_g1]; ++_g1; - stepLengthRow.push(verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol)); + 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 = []; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 315f67d6..833bb439 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -1864,7 +1864,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; @@ -6487,7 +6487,10 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { while(_g1 < bezierrow.length) { var bezier = bezierrow[_g1]; ++_g1; - stepLengthRow.push(verb_eval_Tess.rationalBezierSurfaceStepLength(bezier,tol)); + 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 = []; diff --git a/examples/surfaceAdaptiveTessellation2.html b/examples/surfaceAdaptiveTessellation2.html index 2269b96a..141c78fa 100644 --- a/examples/surfaceAdaptiveTessellation2.html +++ b/examples/surfaceAdaptiveTessellation2.html @@ -88,12 +88,13 @@ 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, 1], [20, -10, 1], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ], - [ [0, -20, 0], [10, -20, 20], [20, -20, 1], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ], - [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 30] , [40, -30, 0], [50, -30, 0] ], - [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, 0], [50, -40, 0] ] ] + [ [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] ] ] , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); @@ -101,36 +102,42 @@ var degree = 3 , knots = [0, 0, 0, 0, 1, 1, 1, 1] - , pts = [ [ [0, 0, 0], [10, 0, 10], [20, 0, 0], [30, 0, 0] ], + , 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, 10], [10, -30, 10], [20, -30, 10], [30, -30, 10] ] ] - , 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 - }; + [ [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 ] ]; + + return new verb.core.NurbsSurfaceData( degree, degree, knots, knots, verb.eval.Eval.homogenize2d(pts, wts) ); } - // homogenize the pts - controlPoints.forEach((x) => { - x.forEach((y) => { - y.push(1.0); - }); - }); + 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, 5], [20, -40, 0], [30, -40, 0], [40, -40, -10], [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; + }; + + + console.log(getBezier()) - // surface = getBezier(); + surface = getBezier(); var tol = 0.1; @@ -154,10 +161,9 @@ // add the edge points to the scene var mesh = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface, tol ); - var mesh2 = verb.eval.Tess.rationalSurfaceAdaptive( surface ); addMeshToScene( getThreeMesh( mesh ) ); - //addMeshToScene( getThreeMesh( mesh2 ), mat3 ); + addMeshToScene( getThreeMesh( mesh ), mat3 ); // addMeshToScene( getThreeMesh( mesh ), mat2 ); // addPointsToScene( mesh.points ); diff --git a/src/verb/Verb.hx b/src/verb/Verb.hx index 28bcd39d..1a286b19 100644 --- a/src/verb/Verb.hx +++ b/src/verb/Verb.hx @@ -42,6 +42,6 @@ import verb.eval.Check; class Verb { public static function main( ) : Void { - trace( "verb 2.0.0" ); + trace( "verb 2.1.0" ); } } \ No newline at end of file diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 6ddf05a9..95b45ede 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -98,7 +98,12 @@ class Tess { stepLengths.push( stepLengthRow ); for ( bezier in bezierrow ) { - stepLengthRow.push( rationalBezierSurfaceStepLength( bezier, tol ) ); + 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 ); } } @@ -112,7 +117,7 @@ class Tess { e1 : Int, srf; - // should be ( beziers.length + 1, beziers[0].length + 1 ) + // tessellate the edges of the bezier patches for (i in 0...beziers.length){ @@ -195,7 +200,7 @@ class Tess { } } - // tessellate patches, merging into a single mesh by reusing the edge points + // tessellate the patch interior and join to the polyline interiors together var faces = [], p0; @@ -204,7 +209,7 @@ class Tess { // tessellate just the interior of the surface - // keep track of the position in the pts array + // keep track of the position in the pts array p0 = pts.length; @@ -222,6 +227,8 @@ class Tess { var u = bezier.knotsU[0] + tessStepU; + // evaluate all points on the interior of the face + for ( k in 0...divsU-1 ) { var iso = Make.surfaceIsocurve( bezier, u, false ); @@ -235,7 +242,7 @@ class Tess { divsU = divsU - 2; divsV = divsV - 2; - // triangulate the interior of the face + // triangulate the interior of the face after having computed the points for ( k in 0...divsU ) { for ( l in 0...divsV ) { @@ -256,7 +263,6 @@ class Tess { bei = beis[i][j]; // we'll need the edge indices for completing this - // complete north edge 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 ); diff --git a/test/testEval.js b/test/testEval.js index af1c785f..215ada65 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -4399,7 +4399,7 @@ describe("verb.eval.Modify.decomposeSurfaceIntoBeziers",() => { }); - it('can decompose into 2 x 3 set of bezier patches with no distortion', () => { + it('can decompose into 1 x 1 set of bezier patches with no distortion', () => { var surface11 = getSurface11(); var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface11 ); @@ -4408,3 +4408,71 @@ describe("verb.eval.Modify.decomposeSurfaceIntoBeziers",() => { }); }); + + +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; + }; + + it('can tessellate rational flat patch 1x1', () => { + + var surface11 = getSurface11(); + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface11, 0.1 ); + + // should return 2 faces! + + should.equal( 2, res.faces.length ); + + console.log(res); + }); + + it('can tessellate 2 x 3 rational flat patch', () => { + + var surface23 = getSurface23(); + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface23, 0.1 ); + + // should return 12 faces + should.equal( 6, res.faces.length ); + + }); + +}); \ No newline at end of file diff --git a/todo b/todo index c702e1bc..ab1c8a9c 100644 --- a/todo +++ b/todo @@ -1,17 +1,19 @@ Complete forward differencing algorithm - degenerate cases (e.g. no interior points, cylinder) - - provide UVs + - make UVS - approximate normals - exact normals - tests (spheres, circles) -Split +BRep Split Holes are not recognized +BRep Bool + Not complete + SweptSurface 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 From d111c7675bb4704b6313950dc9508b814c094e5a Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Mon, 15 Feb 2016 14:45:20 -0500 Subject: [PATCH 22/25] Fix bug in stitching code --- build/js/verb.js | 9 +++++++- build/js/verbHaxe.js | 9 +++++++- examples/surfaceAdaptiveTessellation2.html | 3 +-- src/verb/eval/Tess.hx | 25 +++++++++++++--------- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/build/js/verb.js b/build/js/verb.js index 31b0f816..b1ae7675 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -6677,28 +6677,33 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess 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; @@ -6707,8 +6712,9 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess 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 - verb_core_Constants.EPSILON && 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]); @@ -6719,6 +6725,7 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess 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; } diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 833bb439..53ccab33 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -6608,28 +6608,33 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess 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; @@ -6638,8 +6643,9 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess 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 - verb_core_Constants.EPSILON && 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]); @@ -6650,6 +6656,7 @@ verb_eval_Tess.stitchMesh = function(bezier,faces,bei,divsU,divsV,domain,p0,tess 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; } diff --git a/examples/surfaceAdaptiveTessellation2.html b/examples/surfaceAdaptiveTessellation2.html index 141c78fa..cc9e1288 100644 --- a/examples/surfaceAdaptiveTessellation2.html +++ b/examples/surfaceAdaptiveTessellation2.html @@ -115,7 +115,6 @@ } 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] @@ -154,7 +153,7 @@ var srf = res[i][j]; var l = verb.eval.Tess.rationalBezierSurfaceStepLength( srf, tol ); - // addMeshToScene( tessellateSurface( srf, Math.ceil( 1 / l.item0 ), Math.ceil( 1 / l.item1) ), mat ); + //=addMeshToScene( tessellateSurface( srf, Math.ceil( 1 / l.item0 ), Math.ceil( 1 / l.item1) ), mat ); } } diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 95b45ede..ecb39f34 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -98,12 +98,12 @@ class Tess { stepLengths.push( stepLengthRow ); for ( bezier in bezierrow ) { - var ls = rationalBezierSurfaceStepLength( bezier, tol ); + 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); + 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 ); + stepLengthRow.push( ls ); } } @@ -209,7 +209,7 @@ class Tess { // tessellate just the interior of the surface - // keep track of the position in the pts array + // keep track of the position in the pts array p0 = pts.length; @@ -227,7 +227,7 @@ class Tess { var u = bezier.knotsU[0] + tessStepU; - // evaluate all points on the interior of the face + // evaluate all points on the interior of the face for ( k in 0...divsU-1 ) { @@ -280,26 +280,31 @@ class Tess { 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? @@ -316,12 +321,12 @@ class Tess { 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 - Constants.EPSILON && edgeI < edgeCount ){ - + while ( edgeU < tessU && edgeI < edgeCount || (edgeI < edgeCount && tessDivI > tessDivCount) ){ var ei = edgeIndices.item0 + edgeI, ei2 = ei + 1; @@ -345,12 +350,12 @@ class Tess { } } + tessDivI++; tessI += tessIStep; tessU += tessStep; } } - private static function rationalBezierCurveRegularSamplePointsMutate2( crv : NurbsCurveData, pts : Array, step : Float, From 278547d78c8923797218f820f48e9f63790989e2 Mon Sep 17 00:00:00 2001 From: Peter Boyer Date: Mon, 15 Feb 2016 20:33:30 -0500 Subject: [PATCH 23/25] Build UVs when tessellating --- benchmark/surfaceTessellation.js | 3 +- build/js/verb.js | 21 +- build/js/verbHaxe.js | 21 +- examples/build/.gitignore | 5 + examples/build/js/verb.js | 8470 ++++++++++++++++++++ examples/build/js/verb.min.js | 6 + examples/build/js/verbHaxe.js | 8396 +++++++++++++++++++ examples/images/stone-wall.jpg | Bin 0 -> 59087 bytes examples/js/verbToThreeConversion.js | 1 + examples/surfaceAdaptiveTessellation2.html | 24 +- src/verb/eval/Tess.hx | 40 +- test/testEval.js | 10 +- 12 files changed, 16982 insertions(+), 15 deletions(-) create mode 100644 examples/build/.gitignore create mode 100644 examples/build/js/verb.js create mode 100644 examples/build/js/verb.min.js create mode 100644 examples/build/js/verbHaxe.js create mode 100644 examples/images/stone-wall.jpg diff --git a/benchmark/surfaceTessellation.js b/benchmark/surfaceTessellation.js index e1b69fae..bb8dbbc6 100644 --- a/benchmark/surfaceTessellation.js +++ b/benchmark/surfaceTessellation.js @@ -1,5 +1,6 @@ var Benchmark = require('benchmark') - , verb = require('../build/js/verb.js'); + , verb = require('../build/js/verb.js') + , verbOld = require('../build/js/verbOld.js'); function getComplexSurface(){ diff --git a/build/js/verb.js b/build/js/verb.js index b1ae7675..e9a4be8d 100644 --- a/build/js/verb.js +++ b/build/js/verb.js @@ -6563,6 +6563,7 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { } } var pts = []; + var uvs = []; var edgeRow; var n; var s; @@ -6597,6 +6598,7 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { 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) { @@ -6604,17 +6606,20 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { 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); } } @@ -6643,6 +6648,7 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { 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; @@ -6670,7 +6676,20 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.West); } } - return new verb_core_MeshData(faces,pts,null,null); + 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; diff --git a/build/js/verbHaxe.js b/build/js/verbHaxe.js index 53ccab33..5968e03b 100644 --- a/build/js/verbHaxe.js +++ b/build/js/verbHaxe.js @@ -6494,6 +6494,7 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { } } var pts = []; + var uvs = []; var edgeRow; var n; var s; @@ -6528,6 +6529,7 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { 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) { @@ -6535,17 +6537,20 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { 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); } } @@ -6574,6 +6579,7 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { 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; @@ -6601,7 +6607,20 @@ verb_eval_Tess.rationalSurfaceAdaptiveSample = function(surface,tol) { verb_eval_Tess.stitchMesh(bezier1,faces,bei,divsU,divsV,domainU,p0,tessStepU,verb_eval_EdgeSide.West); } } - return new verb_core_MeshData(faces,pts,null,null); + 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; 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 - - - - - - - - - - - - - - - -
Show/Hide Code
-
-
-
-
- - - - - - - \ No newline at end of file diff --git a/examples/surfaceBezierSubdivision.html b/examples/surfaceBezierSubdivision.html index 95396054..2b6b9d4b 100644 --- a/examples/surfaceBezierSubdivision.html +++ b/examples/surfaceBezierSubdivision.html @@ -51,6 +51,7 @@ geometry.vertices.push.apply( geometry.vertices, threePts ); var threeFaces = tess.faces.map(function(faceIndices){ + var normals = faceIndices.map(function(x){ var vn = tess.normals[x]; return new THREE.Vector3( vn[0], vn[1], vn[2] ); @@ -63,70 +64,142 @@ return geometry; } - function getComplexSurface(){ + function getThreeMesh( tess ) { - var degree = 3 - , knots = [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, 10], [10, -30, 10], [20, -30, 10], [30, -30, 10] ] ] - , 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 - }; + var geometry = new THREE.Geometry(); + var threePts = asVector3( tess.points ); + + geometry.vertices.push.apply( geometry.vertices, threePts ); + + var threeFaces = tess.faces.map(function(faceIndices){ + return new THREE.Face3(faceIndices[0],faceIndices[1],faceIndices[2]); + }); + + geometry.faces.push.apply(geometry.faces, threeFaces); + + geometry.faceVertexUvs[0] = []; + + tess.faces.forEach(function(f){ + geometry.faceVertexUvs[0].push([ + new THREE.Vector2( tess.uvs[f[0]][0], tess.uvs[f[0]][1] ), + new THREE.Vector2( tess.uvs[f[1]][0], tess.uvs[f[1]][1] ), + new THREE.Vector2( tess.uvs[f[2]][0], tess.uvs[f[2]][1] ), + ]); + }); + + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + + return geometry; } 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, 1], [20, -10, 1], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ], - [ [0, -20, 0], [10, -20, 20], [20, -20, 1], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ], - [ [0, -30, 0], [10, -30, 0], [20, -30, 0], [30, -30, 30] , [40, -30, 0], [50, -30, 0] ], - [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, 0], [50, -40, 0] ] ] + [ [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] ] ] , surface = new verb.core.NurbsSurfaceData( degree, degree, knotsU, knotsV, controlPoints ); - controlPoints.forEach((x) => { - x.forEach((y) => { - y.push(1.0); - }); - }); - var tol = 0.5; + var getSurface11 = () => { - var mat2 = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide, wireframe: true }); - var l = verb.eval.Tess.rationalBezierSurfaceStepLength( surface, tol ); + 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, 5], [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; + }; + function getBezier(){ + + var degree = 3 + , knots = [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 ] ]; + + return new verb.core.NurbsSurfaceData( degree, degree, knots, knots, verb.eval.Eval.homogenize2d(pts, wts) ); + } + + var getSurface23 = () => { + var degree = 3 + , knotsV = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3] + , knotsU = [0, 0, 0, 0, 1, 2, 2, 2, 2] + , pts = [ [ [0, 0, 12], [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, -12] ] ] + , 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, 0], [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, 0], [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; + }; + + + surface = getSurface23Deg2Curved(); + + var tol = 1; + + var l = verb.eval.Tess.rationalBezierSurfaceStepLength( surface, tol ); var res = verb.eval.Modify.decomposeSurfaceIntoBeziers( surface ); for (var i = 0; i < res.length; i++){ for (var j = 0; j < res[i].length; j++){ - var color = '#'+Math.floor(Math.random()*16777215).toString(16); var mat = new THREE.MeshBasicMaterial( { color: color, side: THREE.DoubleSide, wireframe: true }); var srf = res[i][j]; - var l = verb.eval.Tess.rationalBezierSurfaceStepLength( srf, tol ); - addMeshToScene( tessellateSurface( srf, Math.ceil( 1 / l.item0 ), Math.ceil( 1 / l.item1) ), mat ); + var mesh = verb.eval.Tess.rationalSurfaceAdaptiveSample( srf, tol ); + addMeshToScene( getThreeMesh( mesh ), mat ); } } renderScene(); - diff --git a/src/verb/eval/Tess.hx b/src/verb/eval/Tess.hx index 27a0db13..00ca8279 100644 --- a/src/verb/eval/Tess.hx +++ b/src/verb/eval/Tess.hx @@ -84,12 +84,13 @@ class Tess { public static function rationalSurfaceAdaptiveSample( surface : NurbsSurfaceData, tol : Float ) : MeshData { - // split into bezier patches + // 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; @@ -107,9 +108,6 @@ class Tess { } } - trace("YO"); - trace(stepLengths); - var pts = [], uvs = [], edgeRow, n, s, e, w, @@ -122,7 +120,6 @@ class Tess { srf; // tessellate the edges of the bezier patches - for (i in 0...beziers.length){ beir = []; @@ -212,11 +209,7 @@ class Tess { } } - trace(beziers.length); - trace(beziers[0].length); - // tessellate the patch interior and join to the polyline interiors together - var faces = [], p0; for ( i in 0...beziers.length ) { @@ -258,8 +251,6 @@ class Tess { divsU = divsU - 2; divsV = divsV - 2; - trace(divsU, divsV); - // triangulate the interior of the face after having computed the points for ( k in 0...divsU ) { @@ -405,6 +396,7 @@ class Tess { } + public static function rationalBezierSurfaceStepLength( surface : NurbsSurfaceData, tol : Float ) : Pair { // center the control pts at the origin diff --git a/test/testEval.js b/test/testEval.js index 07eb642e..f1e76c52 100644 --- a/test/testEval.js +++ b/test/testEval.js @@ -4453,30 +4453,72 @@ describe("verb.eval.Tess.rationalSurfaceAdaptiveSample",() => { return surface23; }; - it('can tessellate rational flat patch 1x1', () => { - - var surface11 = getSurface11(); - var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface11, 0.1 ); - - // should return 2 faces! + 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; + }; -// should.equal( 2, res.faces.length ); + it('can tessellate rational flat patch 1x1', () => { + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( getSurface11(), 1 ); - console.log("faces", res.faces.length); - console.log(res.uvs.length); - console.log(res.points.length); + 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, 0.1 ); + var res = verb.eval.Tess.rationalSurfaceAdaptiveSample( surface23, 1 ); - console.log(res.uvs.length); - console.log(res.points.length); + should.equal( 320, res.faces.length ); + }); - // should return 12 faces -// should.equal( 6, 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/todo b/todo index ab1c8a9c..4f721307 100644 --- a/todo +++ b/todo @@ -5,6 +5,11 @@ Complete forward differencing algorithm - approximate normals - exact normals - tests (spheres, circles) + - rationalBezierSurfaceStepLength + * supports degree2? + * + + BRep Split Holes are not recognized