Skip to content
Browse files

Compute gaussian, mean, principal curvatures on >degree 2 surface inc…

…luding basic unit test
  • Loading branch information...
1 parent 7d99dca commit 02e43ac61e1fee29cb5a0175f2e26bc83abc2da6 @pboyer committed Feb 1, 2014
Showing with 1,806 additions and 579 deletions.
  1. +183 −71 build/verb.js
  2. +3 −3 build/verb.min.js
  3. +183 −71 build/verbEval.js
  4. +3 −2 build/verbEval.min.js
  5. +1,100 −319 docs/verb.html
  6. +90 −0 src/eval/eval.js
  7. +11 −11 src/eval/geom.js
  8. +81 −59 src/eval/tesselate.js
  9. +152 −43 test/test.js
View
254 build/verb.js
@@ -3351,7 +3351,7 @@ verb.eval.nurbs.divide_rational_surface_adaptive = function( degree_u, knots_u,
, v0 = min_v + v_interval * j
, v1 = min_v + v_interval * (j + 1);
- divs.push( new AdaptiveRefinementNode( srf, u0, u1, v0, v1, null, null ) );
+ divs.push( new verb.eval.nurbs.AdaptiveRefinementNode( srf, u0, u1, v0, v1, null, null ) );
}
}
@@ -3417,7 +3417,46 @@ verb.eval.nurbs.unique_mesh = function( mesh ) {
}
-function AdaptiveRefinementNode( srf, u0, u1, v0, v1, parentNode, neighbors ) {
+
+Array.prototype.where = function( predicate ){
+
+ if (this.length === 0) return this;
+
+ var res = [];
+
+ for (var i = 0; i < this.length; i++){
+ if ( predicate( this[i] ) ) res.push( this[i] );
+ }
+
+ return res;
+
+}
+
+verb.eval.nurbs.AdaptiveRefinementNode = function( srf, u0, u1, v0, v1, parentNode, neighbors ) {
+
+ //
+ // Structure of the child nodes
+ // in the adaptive refinement tree
+ //
+ // +--> u
+ // |
+ // v
+ // v
+ //
+ // neighbors[0]
+ //
+ // (u0,v0)---(u05,v0)---(u1,v0)
+ // | | |
+ // | 0 | 1 |
+ // | | |
+ // neighbors[3] (u0,v05)--(u05,v05)--(u1,v05) neighbors[1]
+ // | | |
+ // | 3 | 2 |
+ // | | |
+ // (u0,v1)---(u05,v1)---(u1,v1)
+ //
+ // neighbors[2]
+ //
this.srf = srf;
this.u0 = u0;
@@ -3431,11 +3470,12 @@ function AdaptiveRefinementNode( srf, u0, u1, v0, v1, parentNode, neighbors ) {
}
-AdaptiveRefinementNode.prototype.isLeaf = function(){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.isLeaf = function(){
return (this.children === undefined);
};
-AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
+
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
var derivs = verb.eval.nurbs.rational_surface_derivs( this.srf.degree_u,
this.srf.knots_u,
@@ -3455,54 +3495,43 @@ AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
};
-Array.prototype.where = function( predicate ){
-
- if (length === 0) return this;
- var res = [];
-
- for (var i = 0; i < this.length; i++){
- if ( predicate( this[i] ) ) res.push( res[i] );
- }
-
- return res;
-
-}
-
-AdaptiveRefinementNode.prototype.getEdgeUvs = function( edgeIndex ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.getEdgeUvs = function( edgeIndex ){
// if its a leaf, there are no children to obtain uvs from
- if ( this.isLeaf() ) return this.leafEdgeUvs[ edgeIndex ];
+ if ( this.isLeaf() ) return [ this.leafEdgeUvs[ edgeIndex ] ]
// get the uvs owned by the children along this edge
this.cachedEdgeUvs[edgeIndex] = this.cachedEdgeUvs[edgeIndex] || this.children[ edgeIndex ].getEdgeUvs( edgeIndex )
.concat( this.children[ (edgeIndex + 1) % 4 ].getEdgeUvs( edgeIndex ));
return this.cachedEdgeUvs[edgeIndex];
};
-AdaptiveRefinementNode.prototype.getAllEdgeUvs = function( edgeIndex ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.getAllEdgeUvs = function( edgeIndex ){
- var baseArr = [ leafEdgeUvs[edgeIndex] ];
+ var baseArr = [ this.leafEdgeUvs[edgeIndex] ];
- if (this.neighbors[edgeIndex] === null) return baseArr;
+ if ( this.neighbors[edgeIndex] === null ) return baseArr;
// get opposite edges uvs
var uvs = this.neighbors[edgeIndex].getEdgeUvs( ( edgeIndex + 2 ) % 4 );
var funcIndex = edgeIndex % 2;
+ var that = this;
+
// range clipping functions
var rangeFuncMap = [
- function(x){ return x[0] > u0 + verb.EPSILON && x[0] < u1 - verb.EPSILON; },
- function(x){ return x[1] > v0 + verb.EPSILON && x[1] < v1 - verb.EPSILON; }
+ function(x){ return x[0] > that.u0 + verb.EPSILON && x[0] < that.u1 - verb.EPSILON; },
+ function(x){ return x[1] > that.v0 + verb.EPSILON && x[1] < that.v1 - verb.EPSILON; }
];
// clip the range of uvs to match this one
- return baseArr.concat( uvs.slice(0).reverse().where( rangeFuncMap[ funcIndex ] ) ) ;
+ return baseArr.concat( uvs.where( rangeFuncMap[ funcIndex ] ).reverse() ) ;
};
-AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
var baseIndex = mesh.points.length - 1;
@@ -3539,7 +3568,7 @@ AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
// make point at center of face
mesh.uvs.push( [ this.u05, this.v05 ] );
- var center = this.evalSurface( this.u05, this.v05 );
+ var center = this.evalSurface( [ this.u05, this.v05 ] );
mesh.points.push( center.point );
mesh.normals.push( center.normal );
@@ -3557,7 +3586,7 @@ AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
};
-AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
if ( this.isLeaf() ) return this.triangulateLeaf( mesh );
@@ -3569,44 +3598,37 @@ AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
};
-AdaptiveRefinementNode.prototype.divide = function( options ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.shouldDivide = function( options, currentDepth ){
- //
- // Structure of the child nodes
- // in the adaptive refinement tree
- //
- // +--> u
- // |
- // v
- // v
- //
- // neighbors[0]
- //
- // (u0,v0)---(u05,v0)---(u1,v0)
- // | | |
- // | 0 | 1 |
- // | | |
- // neighbors[3] (u0,v05)--(u05,v05)--(u1,v05) neighbors[1]
- // | | |
- // | 3 | 2 |
- // | | |
- // (u0,v1)---(u05,v1)---(u1,v1)
- //
- // neighbors[2]
- //
+ if ( ( options.minDepth && currentDepth < options.minDepth ) ){
+ return true;
+ } else if ( this.srf && !verb.eval.nurbs.is_rational_surface_domain_flat( this.srf, this.u0, this.u1, this.v0, this.v1, options ) ){
+ return true;
+ }
- if ( verb.eval.nurbs.is_rational_surface_domain_flat( this.srf, this.u0, this.u1, this.v0, this.v1, options ) )
- return;
+ return false;
- // divide the domain
+}
+
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.divide = function( options, currentDepth ){
+
+ // initialize currentDepth if it's not present
+ if (currentDepth === undefined) currentDepth = 0;
+ if ( !this.shouldDivide( options, currentDepth ) ) return;
+
+ // increment the depth
+ currentDepth++;
+
+ // divide the domain
this.u05 = (this.u0 + this.u1) / 2;
this.v05 = (this.v0 + this.v1) / 2;
- this.children = [ new AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v0, this.v05, this ),
- new AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v0, this.v05, this ),
- new AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v05, this.v1, this ),
- new AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v05, this.v1, this ) ];
+ // create the children
+ this.children = [ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v0, this.v05, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v0, this.v05, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v05, this.v1, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v05, this.v1, this ) ];
// correctly assign neighbors
this.children[0].neighbors = [ this.neighbors[0], this.children[1], this.children[3], this.neighbors[3] ];
@@ -3615,7 +3637,7 @@ AdaptiveRefinementNode.prototype.divide = function( options ){
this.children[3].neighbors = [ this.children[0], this.children[2], this.neighbors[2], this.neighbors[3] ];
// divide all children recursively
- this.children.forEach(function(x){ x.divide( options ); });
+ this.children.forEach(function(x){ x.divide( options,currentDepth ); })
};
@@ -3937,28 +3959,28 @@ verb.eval.nurbs.get_cone_surface = function( axis, xaxis, base, height, radius )
verb.eval.nurbs.get_extruded_surface = function( axis, length, prof_knots, prof_degree, prof_control_points, prof_weights){
- var control_points = verb.eval.nurbs.zeros_2d( 2, prof_control_points.length )
- , weights = verb.eval.nurbs.zeros_2d( 2, prof_control_points.length );
+ var control_points = verb.eval.nurbs.zeros_2d( 3, prof_control_points.length )
+ , weights = verb.eval.nurbs.zeros_2d( 3, prof_control_points.length );
+
+ var translation = numeric.mul(axis, length);
+ var halfTranslation = numeric.mul(axis, 0.5 * length);
// original control points
for (var j = 0; j < prof_control_points.length; j++){
control_points[0][j] = prof_control_points[j];
- weights[0][j] = prof_weights[j];
- }
-
- // build translated control points
- var translation = numeric.mul(axis, length);
+ control_points[1][j] = numeric.add( halfTranslation, prof_control_points[j] );
+ control_points[2][j] = numeric.add( translation, prof_control_points[j] );
- for (var j = 0; j < prof_control_points.length; j++){
- control_points[1][j] = numeric.add( translation, prof_control_points[j] );
+ weights[0][j] = prof_weights[j];
weights[1][j] = prof_weights[j];
+ weights[2][j] = prof_weights[j];
}
// return all parameters
- return {"knots_u": [0,0,1,1],
+ return {"knots_u": [0,0,0,1,1,1],
"knots_v": prof_knots,
"control_points": control_points,
- "degree_u": 1,
+ "degree_u": 2,
"degree_v": prof_degree,
"weights": weights };
}
@@ -4142,6 +4164,96 @@ verb.eval.nurbs.get_arc = function( center, xaxis, yaxis, radius, start_angle, e
+//
+// ####surface_curvature( degree_u, knots_u, degree_v, knots_v, control_points, u, v, options )
+//
+// Compute the gaussian curvature on a non-uniform, non-rational B spline surface
+//
+// **params**
+// + *Number*, integer degree of surface in u direction
+// + *Array*, array of nondecreasing knot values in u direction
+// + *Number*, integer degree of surface in v direction
+// + *Array*, array of nondecreasing knot values in v direction
+// + *Array*, 3d array of control points, where rows are the u dir, and columns run alonsg the positive v direction,
+// and where each control point is an array of length (dim)
+// + *Number*, u parameter at which to evaluate the derivatives
+// + *Number*, v parameter at which to evaluate the derivatives
+//
+// **returns**
+// + *Array*, a point represented by an array of length (dim)
+//
+
+verb.eval.nurbs.rational_surface_curvature = function( degree_u, knots_u, degree_v, knots_v, homo_control_points, u, v ) {
+
+ // compute the first fundamental form
+
+ // symmetric matrix where
+ //
+ // I = [ E F; F G ]
+ //
+ // where:
+ //
+ // E = Xu * Xu
+ // F = Xu * Xv
+ // G = Xv * Xv
+
+ // second fundamental form (shape operator)
+
+ // symmetric matrix where
+ //
+ // II = [ L M; M N ]
+ //
+ // where:
+ //
+ // L = Xuu * n
+ // M = Xuv * n
+ // N = Xvv * n
+
+ // principal curvatures are the eigenvalues of the second fundamental form
+
+ var derivs = verb.eval.nurbs.rational_surface_derivs( degree_u,
+ knots_u,
+ degree_v,
+ knots_v,
+ homo_control_points,
+ 2, u, v );
+
+ // structure of the derivatives
+
+ // pos du vuu
+ // dv duv
+ // dvv
+
+
+ var du = derivs[0][1];
+ var dv = derivs[1][0];
+ var duu = derivs[0][2];
+ var dvv = derivs[2][0];
+ var duv = derivs[1][1];
+
+ var n = numeric.cross( du, dv );
+ var L = numeric.dot( duu, n );
+ var M = numeric.dot( duv, n );
+ var N = numeric.dot( dvv, n );
+
+ var shapeOperator = [ [ L, M ], [ M, N ] ];
+
+ var eigs = numeric.eig( shapeOperator );
+
+ // contains: lambda - x
+ // E - x
+
+ var k1 = eigs.lambda.x[0];
+ var k2 = eigs.lambda.x[1];
+ var mean = 0.5 * ( k1 + k2 );
+ var gaussian = k1 * k2;
+ var p1 = numeric.add( numeric.mul( eigs.E.x[0][0], du ), numeric.mul( eigs.E.x[0][1], dv ) );
+ var p2 = numeric.add( numeric.mul( eigs.E.x[1][0], du ), numeric.mul( eigs.E.x[1][1], dv ) );
+
+ return { point: derivs[0][0], normal: n, mean: mean, gaussian: gaussian, shapeOperator: shapeOperator, k1: k1, k2: k2, p1: p1, p2: p2, p1p : eigs.E.x[0], p2p: eigs.E.x[1] };
+
+};
+
//
// ####curve_knot_insert( degree, knots, control_points, u, s, r )
View
6 build/verb.min.js
@@ -1,3 +1,3 @@
-/*! verb 2014-01-21 */
-function crossprod(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]}if("object"!=typeof exports||void 0===exports)var verb={},numeric=window.numeric,binomial=window.binomial,labor=window.labor;else var verb=module.exports={},numeric=require("numeric"),binomial=require("binomial"),labor=require("labor");verb.geom=verb.geom||{},verb.core=verb.core||{},verb.eval=verb.eval||{},verb.intersect=verb.intersect||{},verb.eval.nurbs=verb.eval.nurbs||{},verb.eval.geom=verb.eval.geom||{},verb.eval.mesh=verb.eval.mesh||{},verb.EPSILON=1e-8,verb.TOLERANCE=.001,verb.init=function(){verb.nurbsEngine=new verb.core.Engine(verb.eval.nurbs),verb.geom.NurbsGeometry.prototype.nurbsEngine=verb.nurbsEngine},Function.prototype.method=function(e,r){return this.prototype[e]=r,this},Function.method("inherits",function(e){return this.prototype=new e,this.prototype,this.prototype.constructor=e,this}),Array.prototype.flatten=function(){if(0==this.length)return[];for(var e=[],r=0;this.length>r;r++)e=this[r]instanceof Array?e.concat(this[r].flatten()):e.concat(this[r]);return e},numeric.normalized=function(e){return numeric.div(e,numeric.norm2(e))},numeric.cross=function(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]},verb.left=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(0,r)},verb.right=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r)},verb.rightWithPivot=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r-1)},verb.unique=function(e,r){if(0===e.length)return[];for(var n=[e.pop()],t=0;e.length>t;t++){for(var i=e.pop(),s=!0,a=0;n.length>a;a++)if(r(i,n[t])){s=!1;break}s&&n.push(i)}return n},verb.range=function(e,r,n){1>=arguments.length&&(r=e||0,e=0),n=arguments[2]||1;for(var t=Math.max(Math.ceil((r-e)/n),0),i=0,s=Array(t);t>i;)s[i++]=e,e+=n;return s},verb.core.Engine=function(e){var r="function"==typeof Worker&&(e.use_pool||void 0===e.use_pool),n=e.num_workers||2,t=e.tolerance||1e-4,i=e.url||"js/verbEval.js",s=e.library||verb.eval.nurbs,a=e.error_handler||function(e){console.warn(e)},o=void 0,u=function(){try{o=new labor.Pool(i,n),o.start()}catch(e){return a("Failed to initialize labor.Pool: "+e),!1}return!0},v=function(e,r){return s[e].apply(null,r)};this.start=function(){r&&u()},this.eval=function(e,n,t){return t?(r&&(o||void 0===o&&u())?o.addWork(e,n,t):setTimeout(function(){t(v(e,n))},0),void 0):v(e,n)},this.setTolerance=function(e){t=e},this.setUsePool=function(e){return e&&void 0===o&&u()?(r=e,!0):e?!1:(o=null,delete o,!0)},this.setErrorHandler=function(e){a=e},this.setNumThreads=function(e){n=e}},verb.core.WatchObject=function(){var e={change:{}},r={},t=0,i=this,s=function(r,t){if("string"==typeof r){for(ele in e[r])e[r][ele](t);for(ele in e.change)e.change[ele](t)}else for(n in r)s(n,t)};this.get=function(e){return r[e]},this.set=function(n,t){var a=r[n];r[n]=t,e[n]=e[n]||{},s(n,{name:n,old:a,"new":t,target:i,type:"full"})},this.setAll=function(n){var t={};for(propName in n)t[propName]=r[propName],r[propName]=n[propName],e[propName]=e[propName]||{};s(n,{old:t,"new":n,target:i,type:"multi"})},this.setAt=function(e,n,t){var a=r[e];if(!(void 0===a||a.length>=n||0>n)){var o=r[e][n];r[e][n]=t,s(e,{name:e,index:n,old:o,"new":t,target:i,type:"index"})}},this.watch=function(n,i){return void 0!==r[n]&&i?(t++,e[n][t]=i,t++):void 0},this.watchAll=function(e,r){for(var n=[],t=0;e.length>t;t++)n.push(this.watch(e[t],r));return n},this.ignore=function(r,n){void 0!==e[r]&&void 0!==e[r][n]&&(e[r][n]=void 0)}},verb.core.uid=function(){var e=0;return function(){return e++}}(),verb.geom.Geometry=function(){verb.core.WatchObject.call(this);var e=verb.core.uid();this.uniqueId=function(){return e}}.inherits(verb.core.WatchObject),verb.geom.NurbsGeometry=function(){verb.geom.Geometry.call(this)}.inherits(verb.geom.Geometry),verb.geom.NurbsCurve=function(e,r,n,t){verb.geom.NurbsGeometry.call(this),this.setAll({controlPoints:r,weights:n,knots:t?t.slice(0):[],degree:e})}.inherits(verb.geom.NurbsGeometry),verb.geom.NurbsCurve.prototype.point=function(e,r){return this.nurbsEngine.eval("rational_curve_point",[this.get("degree"),this.get("knots"),this.homogenize(),e],r)},verb.geom.NurbsCurve.prototype.derivatives=function(e,r,n){return this.nurbsEngine.eval("rational_curve_derivs",[this.get("degree"),this.get("knots"),this.homogenize(),e,r],n)},verb.geom.NurbsCurve.prototype.tesselate=function(e,r){var e=e||{};return e.tolerance=e.tolerance||verb.EPSILON,this.nurbsEngine.eval("rational_curve_adaptive_sample",[this.get("degree"),this.get("knots"),this.homogenize(),e.tolerance],r)},verb.geom.NurbsCurve.prototype.transform=function(e){for(var r=this.get("controlPoints"),n=0;r.length>n;n++){var t=r[1].push(1);r[n]=numeric.mul(e,t).slice(0,t.length-2)}return this.set("controlPoints",r),this},verb.geom.NurbsCurve.prototype.clone=function(){for(var e=this.get("controlPoints"),r=[],n=0;e.length>n;n++)r.push(e[n].slice(0));return new verb.geom.NurbsCurve(this.get("degree"),r,this.get("weights").slice(0),this.get("knots").slice)},verb.geom.NurbsCurve.prototype.homogenize=function(){return verb.eval.nurbs.homogenize_1d(this.get("controlPoints"),this.get("weights"))},verb.geom.NurbsCurve.prototype.update=function(){if(this.nurbsRep){var e=this.nurbsRep();this.setAll({controlPoints:e.control_points,weights:e.weights,knots:e.knots,degree:e.degree})}},verb.geom.NurbsSurface=function(e,r,n,t,i,s){verb.geom.NurbsGeometry.call(this),this.setAll({controlPoints:i,weights:s,knotsU:r?r.slice(0):[],knotsV:t?t.slice(0):[],degreeU:e,degreeV:n})}.inherits(verb.geom.NurbsGeometry),verb.geom.NurbsSurface.prototype.point=function(e,r,n){return this.nurbsEngine.eval("rational_surface_point",[this.get("degreeU"),this.get("knotsU"),this.get("degreeV"),this.get("knotsV"),this.homogenize(),e,r],n)},verb.geom.NurbsSurface.prototype.derivatives=function(e,r,n,t){return this.nurbsEngine.eval("rational_surface_derivs",[this.get("degreeU"),this.get("knotsU"),this.get("degreeV"),this.get("knotsV"),this.homogenize(),n,e,r],t)},verb.geom.NurbsSurface.prototype.tesselate=function(e,r){var n=20,t=20;return e&&(n=e.minDivsV||n,t=e.minDivsU||t),this.nurbsEngine.eval("tesselate_rational_surface_naive",[this.get("degreeU"),this.get("knotsU"),this.get("degreeV"),this.get("knotsV"),this.homogenize(),t,n],r)},verb.geom.NurbsSurface.prototype.transform=function(e){for(var r=this.get("controlPoints"),n=0;r.length>n;n++)for(var t=0;r[n].length>t;t++){var i=r[1].push(1);r[n]=numeric.mul(e,i).slice(0,i.length-2)}return this.set("controlPoints",r),this},verb.geom.NurbsSurface.prototype.clone=function(){for(var e=this.get("controlPoints"),r=[],n=0;e.length>n;n++){r.push([]);for(var t=0;e[n].length>t;t++)r[n].push(e[n][t].slice(0))}for(var i=this.get("weights"),s=[],n=0;i.length>n;n++)s.push(i[n].slice(0));return new verb.geom.NurbsSurface(this.get("degreeU"),this.get("knotsU").slice(0),this.get("degreeV"),this.get("knotsV").slice(0),r,s)},verb.geom.NurbsSurface.prototype.homogenize=function(){return verb.eval.nurbs.homogenize_2d(this.get("controlPoints"),this.get("weights"))},verb.geom.NurbsSurface.prototype.update=function(){if(this.nurbsRep){var e=this.nurbsRep();this.setAll({controlPoints:e.control_points,weights:e.weights,knotsU:e.knots_u,knotsV:e.knots_v,degreeU:e.degree_u,degreeV:e.degree_v})}},verb.geom.Arc=function(e,r,n,t,i){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:n,radius:t,interval:i}),this.update(),this.watchAll(["center","xaxis","yaxis","radius","interval"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Arc.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("radius"),this.get("interval").get("min"),this.get("interval").get("max")])},verb.geom.BezierCurve=function(e,r){verb.geom.NurbsCurve.call(this),this.setAll({controlPoints:e?e.slice(0):[],weights:r?r.slice(0):void 0}),this.update()}.inherits(verb.geom.NurbsCurve),verb.geom.BezierCurve.prototype.nurbsRep=function(){for(var e=this.get("controlPoints"),r=this.get("weights"),n=e.length-1,t=[],i=0;n+1>i;i++)t.push(0);for(var i=0;n+1>i;i++)t.push(1);if(void 0===r){r=[];for(var i=0;e.length>i;i++)r.push(1)}return{degree:n,knots:t,control_points:e,weights:r}},verb.geom.BoundingBox=function(){this.initialized=!1,this.min=[0,0,0],this.max=[0,0,0];var e=Array.prototype.slice.call(arguments,0);1===e.length&&e[0]instanceof Array&&e[0][0]instanceof Array?this.add_elements_sync(e[0]):this.add_elements_sync(e)},verb.geom.BoundingBox.prototype.add_elements=function(e,r){var n=this;setTimeout(function(){e.forEach(function(e){n.add(e)}),r(n)},0)},verb.geom.BoundingBox.prototype.add_elements_sync=function(e){var r=this;return e.forEach(function(e){r.add(e)}),this},verb.geom.BoundingBox.prototype.add=function(e){return this.initialized?(e[0]>this.max[0]&&(this.max[0]=e[0]),e[1]>this.max[1]&&(this.max[1]=e[1]),e[2]>this.max[2]&&(this.max[2]=e[2]),e[0]<this.min[0]&&(this.min[0]=e[0]),e[1]<this.min[1]&&(this.min[1]=e[1]),e[2]<this.min[2]&&(this.min[2]=e[2]),this):(this.min=e.slice(0),this.max=e.slice(0),this.initialized=!0,this)},verb.geom.BoundingBox.prototype.contains=function(e,r){return this.initialized?this.intersects(new verb.geom.BoundingBox(e),r):!1},verb.geom.BoundingBox.prototype.TOLERANCE=1e-4,verb.geom.BoundingBox.prototype.intervals_overlap=function(e,r,n,t,i){var i=i||verb.geom.BoundingBox.prototype.TOLERANCE,s=Math.min(e,r)-i,a=Math.max(e,r)+i,o=Math.min(n,t)-i,u=Math.max(n,t)+i;return s>=o&&u>=s||a>=o&&u>=a||o>=s&&a>=o||u>=s&&a>=u?!0:!1},verb.geom.BoundingBox.prototype.intersects=function(e,r){if(!this.initialized||!e.initialized)return!1;var n=this.min,t=this.max,i=e.min,s=e.max;return this.intervals_overlap(n[0],t[0],i[0],s[0],r)&&this.intervals_overlap(n[1],t[1],i[1],s[1],r)&&this.intervals_overlap(n[2],t[2],i[2],s[2],r)?!0:!1},verb.geom.BoundingBox.prototype.clear=function(){return this.initialized=!1,this},verb.geom.BoundingBox.prototype.get_longest_axis=function(){var e=[this.get_axis_length(0),this.get_axis_length(1),this.get_axis_length(2)];return e.indexOf(Math.max.apply(Math,e))},verb.geom.BoundingBox.prototype.get_axis_length=function(e){return 0>e||e>2?0:Math.abs(this.min[e]-this.max[e])},verb.geom.BoundingBox.prototype.intersect=function(e,r){if(!this.initialized)return null;var n=this.min,t=this.max,i=e.min,s=e.max;if(!this.intersects(e,r))return null;var a=Math.min(t[0],s[0]),o=Math.max(n[0],i[0]),u=Math.min(t[1],s[1]),v=Math.max(n[1],i[1]),l=Math.min(t[2],s[2]),b=Math.max(n[2],i[2]),c=[a,u,l],h=[o,v,b];return new verb.geom.BoundingBox(h,c)},verb.geom.Circle=function(e,r,n,t){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:n,radius:t}),this.update(),this.watchAll(["center","xaxis","yaxis","radius"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Circle.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("radius"),0,2*Math.PI])},verb.geom.Cone=function(e,r,n,t,i){verb.geom.NurbsSurface.call(this),this.setAll({axis:e,xaxis:r,base:n,height:t,radius:i});var s=this.nurbsRep();verb.geom.NurbsSurface.call(this,s.degree_u,s.knots_u,s.degree_v,s.knots_v,s.control_points,s.weights),this.watchAll(["axis","xaxis","base","height","radius"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Cone.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_cone_surface",[this.get("axis"),this.get("xaxis"),this.get("base"),this.get("height"),this.get("radius")])},verb.geom.Cylinder=function(e,r,n,t,i){this.setAll({axis:e,xaxis:r,base:n,height:t,radius:i});var s=this.nurbsRep();verb.geom.NurbsSurface.call(this,s.degree_u,s.knots_u,s.degree_v,s.knots_v,s.control_points,s.weights),this.watchAll(["axis","xaxis","base","height","radius"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Cylinder.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_cylinder_surface",[this.get("axis"),this.get("xaxis"),this.get("base"),this.get("height"),this.get("radius")])},verb.geom.Ellipse=function(e,r,n,t,i){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:n,xradius:t,yradius:i}),this.update(),this.watchAll(["center","xaxis","yaxis","xradius","yradius"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Ellipse.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_ellipse_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("xradius"),this.get("yradius"),0,2*Math.PI])},verb.geom.EllipseArc=function(e,r,n,t,i,s){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:n,xradius:t,yradius:i,interval:s}),this.update(),this.watchAll(["center","xaxis","yaxis","xradius","yradius","interval"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.EllipseArc.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_ellipse_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("xradius"),this.get("yradius"),this.get("interval").get("min"),this.get("interval").get("max")])},verb.geom.Extrusion=function(e,r,n){verb.geom.NurbsSurface.call(this),this.setAll({profile:e,axis:r,length:n}),this.update(),this.watchAll(["axis","length"],this.update),e.watchAll(["knots","degree","controlPoints","weights"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Extrusion.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_extruded_surface",[this.get("axis"),this.get("length"),this.get("profile").get("knots"),this.get("profile").get("degree"),this.get("profile").get("controlPoints"),this.get("profile").get("weights")])},verb.geom.FourPointSurface=function(e,r,n,t){verb.geom.NurbsSurface.call(this),this.setAll({p1:e,p2:r,p3:n,p4:t}),this.update(),this.watchAll(["p1","p2","p3","p4"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.FourPointSurface.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_4pt_surface",[this.get("p1"),this.get("p2"),this.get("p3"),this.get("p4")])},verb.geom.Interval=function(e,r){verb.core.WatchObject.call(this),this.setAll({min:e,max:r})}.inherits(verb.core.WatchObject),verb.geom.Interval2=function(e,r,n,t){verb.core.WatchObject.call(this),this.setAll({uinterval:new verb.geom.Interval(e,r),vinterval:new verb.geom.Interval(n,t)})}.inherits(verb.core.WatchObject),verb.geom.Line=function(e,r){verb.geom.NurbsCurve.call(this),this.setAll({start:e,end:r}),this.update(),this.watchAll(["start","end"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Line.prototype.nurbsRep=function(){return{knots:[0,0,1,1],control_points:[this.get("start"),this.get("end")],weights:[1,1],degree:1}},verb.geom.PlanarSurface=function(e,r,n,t,i){verb.geom.NurbsSurface.call(this),this.setAll({base:e,uaxis:r,vaxis:n,ulength:t,vlength:i}),this.update(),this.watchAll(["base","uaxis","vaxis","ulength","vlength"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.PlanarSurface.prototype.nurbsRep=function(){var e=this.get("base"),r=numeric.mul(this.get("uaxis"),this.get("ulength")),n=numeric.mul(this.get("vaxis"),this.get("vlength")),t=numeric.add(e,r),i=numeric.add(e,n,r),s=numeric.add(e,n);return this.nurbsEngine.eval("get_4pt_surface",[e,t,i,s])},verb.geom.PolyLine=function(e){verb.geom.NurbsCurve.call(this),this.setAll({control_points:e?e.slice(0):[]}),this.update()}.inherits(verb.geom.NurbsCurve),verb.geom.PolyLine.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_polyline_curve",[this.get("control_points")])},verb.geom.RevolvedSurface=function(e,r,n,t){verb.geom.NurbsSurface.call(this),this.setAll({center:e,axis:r,angle:n,profile:t}),this.update(),this.watchAll(["center","axis","angle","profile"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.RevolvedSurface.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_revolved_surface",[this.get("center"),this.get("axis"),this.get("angle"),this.get("profile").get("knots"),this.get("profile").get("degree"),this.get("profile").get("controlPoints"),this.get("profile").get("weights")])},verb.geom.Sphere=function(e,r){verb.geom.NurbsSurface.call(this),this.setAll({center:e,radius:r}),this.update(),this.watchAll(["center","radius"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Sphere.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_sphere_surface",[this.get("center"),[0,0,1],[1,0,0],this.get("radius")])},verb.geom.SweepOneRail=function(e,r){verb.geom.NurbsSurface.call(this),this.setAll({rail:e,profile:r}),this.update(),this.watchAll(["rail","profile"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.SweepOneRail.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_sweep1_surface",[this.get("profile").get("knots"),this.get("profile").get("degree"),this.get("profile").get("controlPoints"),this.get("profile").get("weights"),this.get("rail").get("knots"),this.get("rail").get("degree"),this.get("rail").get("controlPoints"),this.get("rail").get("weights")])},verb.intersect.curveCurve=function(e,r,n){return verb.nurbsEngine.eval("intersect_rational_curves_by_aabb_refine",[e.get("degree"),e.get("knots"),e.homogenize(),r.get("degree"),r.get("knots"),r.homogenize(),verb.TOLERANCE,verb.TOLERANCE],n)},verb.intersect.curveSurface=function(e,r,n,t){return n=n||{tolerance:verb.TOLERANCE,sampleTolerance:verb.TOLERANCE,uDivs:20,vDivs:20},verb.nurbsEngine.eval("intersect_rational_curve_surface_by_aabb_refine",[r.get("degreeU"),r.get("knotsU"),r.get("degreeV"),r.get("knotsV"),r.homogenize(),e.get("degree"),e.get("knots"),e.homogenize(),n.sampleTolerance,n.tolerance,n.uDivs,n.vDivs],t)},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb_refine=function(e,r,n,t,i,s,a,o,u,v,l,b){var c=verb.eval.nurbs.intersect_rational_curve_surface_by_aabb(e,r,n,t,i,s,a,o,u,v,l,b);return c.map(function(u){var v=[u.p,u.uv[0],u.uv[1]],l=verb.eval.nurbs.refine_rational_curve_surface_intersection(e,r,n,t,i,s,a,o,v);return u.p=l[0],u.uv[0]=l[1],u.uv[1]=l[2],u.distance=l[3],delete u.face,u})},verb.eval.nurbs.refine_rational_curve_surface_intersection=function(e,r,n,t,i,s,a,o,u){var v=function(u){var v=verb.eval.nurbs.rational_curve_point(s,a,o,u[0]),l=verb.eval.nurbs.rational_surface_point(e,r,n,t,i,u[1],u[2]),b=numeric.sub(v,l);return numeric.dot(b,b)},l=numeric.uncmin(v,u);return l.solution.concat(l.f)},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb=function(e,r,n,t,i,s,a,o,u,v,l,b){var c=verb.eval.nurbs.rational_curve_adaptive_sample(s,a,o,u,!0),h=verb.eval.nurbs.tesselate_rational_surface_naive(e,r,n,t,i,l,b),_=c.map(function(e){return e[0]}),g=c.map(function(e){return e.slice(1)}),m=verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(g,_,h,verb.range(h.faces.length),v);return verb.unique(m,function(e,r){return v>numeric.norm2(numeric.sub(e.point,r.point))&&v>Math.abs(e.p-r.p)&&v>numeric.norm2(numeric.sub(e.uv,r.uv))})},verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb=function(e,r,n,t,i){var s=new verb.geom.BoundingBox(e),a=verb.eval.mesh.make_mesh_aabb(n.points,n.faces,t);if(!s.intersects(a,i))return[];if(2!==e.length||1!==t.length){if(1===t.length){var o=verb.left(e),u=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,v,n,t,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,l,n,t,i))}if(2===e.length){var b=verb.eval.mesh.sort_tris_on_longest_axis(a,n.points,n.faces,t),c=verb.left(b),h=verb.right(b);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,n,c,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,n,h,i))}var b=verb.eval.mesh.sort_tris_on_longest_axis(a,n.points,n.faces,t),c=verb.left(b),h=verb.right(b),o=verb.left(e),u=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,v,n,c,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,v,n,h,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,l,n,c,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,l,n,h,i))}var _=verb.eval.geom.intersect_segment_with_tri(e[0],e[1],n.points,n.faces[t[0]]);if(null!=_){var g=_.p*(r[1]-r[0])+r[0],m=n.faces[t][0],f=n.faces[t][1],p=n.faces[t][2],d=n.uvs[m],y=n.uvs[f],x=n.uvs[p],k=numeric.sub(y,d),w=numeric.sub(x,d),N=numeric.add(d,numeric.mul(_.s,k),numeric.mul(_.t,w));return[{point:_.point,p:g,uv:N,face:t[0]}]}return[]},verb.eval.geom.intersect_segment_with_tri=function(e,r,n,t){var i=n[t[0]],s=n[t[1]],a=n[t[2]],o=numeric.sub(s,i),u=numeric.sub(a,i),v=numeric.cross(o,u),l=numeric.sub(r,e),b=numeric.sub(e,i),c=-numeric.dot(v,b),h=numeric.dot(v,l);if(Math.abs(h)<verb.EPSILON)return null;var _=c/h;if(0>_||_>1)return null;var g=numeric.add(e,numeric.mul(_,l)),m=numeric.dot(o,u),f=numeric.dot(o,o),p=numeric.dot(u,u),d=numeric.sub(g,i),y=numeric.dot(d,o),x=numeric.dot(d,u),k=m*m-f*p,w=(m*x-p*y)/k,N=(m*y-f*x)/k;return w>1+verb.EPSILON||N>1+verb.EPSILON||-verb.EPSILON>N||-verb.EPSILON>w||w+N>1+verb.EPSILON?null:{point:g,s:w,t:N,p:_}},verb.eval.geom.intersect_segment_with_plane=function(e,r,n,t){var i=numeric.dot(t,numeric.sub(e,r));if(EPSILON>abs(i))return null;var s=numeric.dot(t,numeric.sub(n,e));return{p:s/i}},verb.eval.geom.intersect_aabb_trees=function(e,r,n,t,i,s){var a=i.bounding_box.intersects(s.bounding_box);return a?0===i.children.length&&0===s.children.length?[[i.triangle,s.triangle]]:0===i.children.length&&0!=s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i,s.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i,s.children[1])):0!=i.children.length&&0===s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],s).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],s)):0!=i.children.length&&0!=s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],s.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],s.children[1])).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],s.children[0])).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],s.children[1])):void 0:[]},verb.eval.mesh.make_mesh_aabb_tree=function(e,r,n){var t={bounding_box:verb.eval.mesh.make_mesh_aabb(e,r,n),children:[]};if(1===n.length)return t.triangle=n[0],t;var i=verb.eval.mesh.sort_tris_on_longest_axis(t.bounding_box,e,r,n),s=i.slice(0,Math.floor(i.length/2)),a=i.slice(Math.floor(i.length/2),i.length);return t.children=[verb.eval.mesh.make_mesh_aabb_tree(e,r,s),verb.eval.mesh.make_mesh_aabb_tree(e,r,a)],t},verb.eval.mesh.make_mesh_aabb=function(e,r,n){var t=new verb.geom.BoundingBox;return n.forEach(function(n){t.add(e[r[n][0]]),t.add(e[r[n][1]]),t.add(e[r[n][2]])}),t},verb.eval.mesh.sort_tris_on_longest_axis=function(e,r,n,t){for(var i=e.get_longest_axis(),s=[],a=t.length-1;a>=0;a--){var o=t[a],u=verb.eval.mesh.get_min_coordinate_on_axis(r,n[o],i);s.push([u,o])}s.sort(function(e,r){return e[0]>r[0]});for(var v=[],a=0,l=s.length;l>a;a++)v.push(s[a][1]);return v},verb.eval.mesh.get_min_coordinate_on_axis=function(e,r,n){for(var t=[],i=0;3>i;i++)t.push(e[r[i]][n]);return Math.min.apply(Math,t)},verb.eval.geom.get_tri_centroid=function(e,r){for(var n=[0,0,0],t=0;3>t;t++)for(var i=0;3>i;i++)n[i]+=e[r[t]][i];for(var t=0;3>t;t++)n[t]/=3;return n},verb.eval.geom.get_tri_norm=function(e,r){var n=e[r[0]],t=e[r[1]],i=e[r[2]],s=numeric.sub(t,n),a=numeric.sub(i,n),o=numeric.cross(s,a);return numeric.mul(1/numeric.norm2(o),o)},verb.eval.nurbs.intersect_rational_curves_by_aabb_refine=function(e,r,n,t,i,s,a,o){var u=verb.eval.nurbs.intersect_rational_curves_by_aabb(e,r,n,t,i,s,a,o);return u.map(function(a){return verb.eval.nurbs.refine_rational_curve_intersection(e,r,n,t,i,s,a)})},verb.eval.nurbs.refine_rational_curve_intersection=function(e,r,n,t,i,s,a){var o=function(a){var o=verb.eval.nurbs.rational_curve_point(e,r,n,a[0]),u=verb.eval.nurbs.rational_curve_point(t,i,s,a[1]),v=numeric.sub(o,u);return numeric.dot(v,v)},u=numeric.uncmin(o,a);return u.solution.concat(u.f)},verb.eval.nurbs.intersect_rational_curves_by_aabb=function(e,r,n,t,i,s,a,o){var u=verb.eval.nurbs.rational_curve_adaptive_sample(e,r,n,a,!0),v=verb.eval.nurbs.rational_curve_adaptive_sample(t,i,s,a,!0),l=u.map(function(e){return e[0]}),b=v.map(function(e){return e[0]}),c=u.map(function(e){return e.slice(1)}),h=v.map(function(e){return e.slice(1)});return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(c,h,l,b,o)},verb.eval.nurbs.intersect_parametric_polylines_by_aabb=function(e,r,n,t,i){var s=new verb.geom.BoundingBox(e),a=new verb.geom.BoundingBox(r);if(!s.intersects(a,i))return[];if(2!==e.length||2!==r.length){if(2===e.length){var o=Math.ceil(r.length/2),u=r.slice(0,o),v=r.slice(o-1),l=t.slice(0,o),b=t.slice(o-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,u,n,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,v,n,b,i))}if(2===r.length){var c=Math.ceil(e.length/2),h=e.slice(0,c),_=e.slice(c-1),g=n.slice(0,c),m=n.slice(c-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,r,g,t,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,r,m,t,i))}var c=Math.ceil(e.length/2),h=e.slice(0,c),_=e.slice(c-1),g=n.slice(0,c),m=n.slice(c-1),o=Math.ceil(r.length/2),u=r.slice(0,o),v=r.slice(o-1),l=t.slice(0,o),b=t.slice(o-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,u,g,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,v,g,b,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,u,m,l,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,v,m,b,i))}var f=verb.eval.geom.intersect_segments(e[0],e[1],r[0],r[1],i);return null!=f?(f[0][0]=f[0][0]*(n[1]-n[0])+n[0],f[1][0]=f[1][0]*(t[1]-t[0])+t[0],[[f[0][0],f[1][0]]]):[]},verb.eval.geom.intersect_segments=function(e,r,n,t,i){var s=numeric.sub(r,e),a=Math.sqrt(numeric.dot(s,s)),o=numeric.mul(1/a,s),u=numeric.sub(t,n),v=Math.sqrt(numeric.dot(u,u)),l=numeric.mul(1/v,u),b=verb.eval.geom.intersect_rays(e,o,n,l);if(null!=b){var c=Math.min(Math.max(0,b[0]/a),1),h=Math.min(Math.max(0,b[1]/v),1),_=numeric.add(numeric.mul(c,s),e),g=numeric.add(numeric.mul(h,u),n),m=numeric.norm2Squared(numeric.sub(_,g));if(i*i>m)return[[c].concat(_),[h].concat(g)]}return null},verb.eval.geom.closest_point_on_ray=function(e,r,n){var t=numeric.sub(e,r),i=numeric.dot(t,n),s=numeric.add(r,numeric.mul(i,n));return s},verb.eval.geom.intersect_rays=function(e,r,n,t){var i=numeric.dot(r,t),s=numeric.dot(r,n),a=numeric.dot(r,e),o=numeric.dot(t,n),u=numeric.dot(t,e),v=numeric.dot(r,r),l=numeric.dot(t,t),b=v*l-i*i;if(Math.abs(b)<verb.EPSILON)return null;var c=i*(s-a)-v*(o-u),h=c/b,_=(s-a+h*i)/v;return[_,h]},verb.eval.mesh.intersect_meshes_by_aabb=function(e,r,n,t,i){var s=verb.range(r.length),a=verb.range(i.length),o=verb.eval.mesh.make_mesh_aabb_tree(e,r,s),u=verb.eval.mesh.make_mesh_aabb_tree(t,i,a);verb.eval.mesh.intersect_aabb_tree(e,r,t,i,o,u)},verb.eval.geom.intersect_tris=function(e,r,n,t,i){for(var s=[e[tr1[0]],e[tr1[1]]],a=[e[tr1[1]],e[tr1[2]]],o=[e[tr1[2]],e[tr1[0]]],u=[t[tr2[0]],t[tr2[1]]],v=[t[tr2[1]],t[tr2[2]]],l=[t[tr2[2]],t[tr2[0]]],b=[s,a,o],c=[u,v,l],h=[],_=verb.eval.geom.get_tri_norm(t,i),g=t[tr2[0]],m=0;3>m;m++){var f=verb.eval.geom.intersect_segment_with_plane(b[m][0],c[m][1],g,_);f.intersects&&h.push(f)}if(2!==h.length)return null;for(var p=[h[0].point,h[1].point],d=[],m=0;3>m;m++){var y=verb.eval.geom.intersect_segments(p[0],p[1],p,b1,tol);y&&d.push(y)}0===d.length||1===d.length||2===d.length},verb.eval.nurbs.tesselate_rational_surface_naive=function(e,r,n,t,i,s,a){1>s&&(s=1),1>a&&(a=1);for(var o=1/s,u=1/a,v=[],l=[],b=[],c=0;s+1>c;c++)for(var h=0;a+1>h;h++){var _=c*o,g=h*u;l.push([_,g]);var m=verb.eval.nurbs.rational_surface_derivs(e,r,n,t,i,1,_,g),f=m[0][0];v.push(f);var p=numeric.cross(m[0][1],m[1][0]);b.push(p)}for(var d=[],c=0;s>c;c++)for(var h=0;a>h;h++){var y=c*(a+1)+h,x=(c+1)*(a+1)+h,k=x+1,w=y+1,N=[y,x,k],z=[y,k,w];d.push(N),d.push(z)}return{points:v,faces:d,uvs:l,normals:b}},verb.eval.nurbs.rational_curve_regular_sample=function(e,r,n,t,i){return verb.eval.nurbs.rational_curve_regular_sample_range(e,r,n,0,1,t,i)},verb.eval.nurbs.rational_curve_regular_sample_range=function(e,r,n,t,i,s,a){1>s&&(s=2);for(var o=[],u=(i-t)/(s-1),v=0,l=0;s>l;l++)v=t+u*l,a?o.push([v].concat(verb.eval.nurbs.rational_curve_point(e,r,n,v))):o.push(verb.eval.nurbs.rational_curve_point(e,r,n,v));return o},verb.eval.nurbs.rational_curve_adaptive_sample=function(e,r,n,t,i){return 1===e?i?n.map(function(e,n){return[r[n+1]].concat(verb.eval.nurbs.dehomogenize(e))}):n.map(verb.eval.nurbs.dehomogenize):verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,0,1,t,i)},verb.eval.nurbs.rational_curve_adaptive_sample_range=function(e,r,n,t,i,s,a){var o=verb.eval.nurbs.rational_curve_point(e,r,n,t),u=verb.eval.nurbs.rational_curve_point(e,r,n,i),v=.5+.2*Math.random(),l=t+(i-t)*v,b=verb.eval.nurbs.rational_curve_point(e,r,n,l),c=numeric.sub(o,u),h=numeric.sub(o,b);if(s>numeric.dot(c,c)&&numeric.dot(h,h)>s||!verb.eval.nurbs.three_points_are_flat(o,b,u,s)){var _=t+.5*(i-t),g=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,t,_,s,a),m=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,_,i,s,a);return g.slice(0,-1).concat(m)}return a?[[t].concat(o),[i].concat(u)]:[o,u]},verb.eval.nurbs.three_points_are_flat=function(e,r,n,t){var i=numeric.sub(r,e),s=numeric.sub(n,e),a=crossprod(i,s),o=numeric.dot(a,a);return t>o},verb.eval.nurbs.get_sweep1_surface=function(e,r,n,t,i,s,a,o){for(var u=verb.eval.nurbs.homogenize_1d(a,o),v=verb.eval.nurbs.rational_curve_point(s,i,u,0),l=1/a.length,b=[],c=[],h=0;a.length>h;h++){for(var _=verb.eval.nurbs.rational_curve_point(s,i,u,h*l),g=numeric.sub(_,v),m=[],f=[],p=0;n.length>p;p++)m.push(numeric.add(g,n[p])),f.push(t[p]*o[h]);b.push(m),c.push(f)}return{knots_u:i,knots_v:e,control_points:b,degree_u:s,degree_v:r,weights:c}},verb.eval.nurbs.get_ellipse_arc=function(e,r,n,t,i,s,a){s>a&&(a=2*Math.PI+s);var o=a-s,u=0;u=Math.PI/2>=o?1:Math.PI>=o?2:3*Math.PI/2>=o?3:4;var v=o/u,l=Math.cos(v/2),b=numeric.add(e,numeric.mul(t,Math.cos(s),r),numeric.mul(i,Math.sin(s),n)),c=numeric.sub(numeric.mul(Math.cos(s),n),numeric.mul(Math.sin(s),r)),h=verb.eval.nurbs.zeros_1d(2*u),_=verb.eval.nurbs.zeros_1d(2*u+3),g=0,m=s,f=verb.eval.nurbs.zeros_1d(2*u);h[0]=b,f[0]=1;for(var p=1;u>=p;p++){m+=v;var d=numeric.add(e,numeric.mul(t,Math.cos(m),r),numeric.mul(i,Math.sin(m),n));f[g+2]=1,h[g+2]=d;var y=numeric.sub(numeric.mul(Math.cos(m),n),numeric.mul(Math.sin(m),r)),x=verb.eval.geom.intersect_rays(b,numeric.mul(1/numeric.norm2(c),c),d,numeric.mul(1/numeric.norm2(y),y)),k=numeric.add(b,numeric.mul(c,x[0]));f[g+1]=l,h[g+1]=k,g+=2,u>p&&(b=d,c=y)}for(var w=2*u+1,p=0;3>p;p++)_[p]=0,_[p+w]=1;switch(u){case 1:break;case 2:_[3]=_[4]=.5;break;case 3:_[3]=_[4]=1/3,_[5]=_[6]=2/3;break;case 4:_[3]=_[4]=.25,_[5]=_[6]=.5,_[7]=_[8]=.75}return{knots:_,control_points:h,degree:2,weights:f}},verb.eval.nurbs.get_sphere_surface=function(e,r,n,t){var i=verb.eval.nurbs.get_arc(e,numeric.mul(r,-1),n,t,0,Math.PI);return verb.eval.nurbs.get_revolved_surface(e,r,2*Math.PI,i.knots,i.degree,i.control_points,i.weights)},verb.eval.nurbs.get_polyline_curve=function(e){for(var r=e.length-1,n=1/r,t=[0,0],i=1;r>i;i++)t.push(i*n);t.push(1),t.push(1);for(var s=[],i=0;e.length>i;i++)s.push(1);return{knots:t,control_points:e.slice(0),degree:1,weights:s}},verb.eval.nurbs.get_4pt_surface=function(e,r,n,t){return{knots_u:[0,0,1,1],knots_v:[0,0,1,1],control_points:[[e,t],[r,n]],degree_u:1,degree_v:1,weights:[[1,1],[1,1]]}},verb.eval.nurbs.get_cylinder_surface=function(e,r,n,t,i){var s=crossprod(e,r),a=(2*Math.PI,verb.eval.nurbs.get_arc(n,r,s,i,0,2*Math.PI));return verb.eval.nurbs.get_extruded_surface(e,t,a.knots,a.degree,a.control_points,a.weights)},verb.eval.nurbs.get_cone_surface=function(e,r,n,t,i){var s=2*Math.PI,a=1,o=[numeric.add(n,numeric.mul(t,e)),numeric.add(n,numeric.mul(i,r))],u=[0,0,1,1],v=[1,1];
-return verb.eval.nurbs.get_revolved_surface(n,e,s,u,a,o,v)},verb.eval.nurbs.get_extruded_surface=function(e,r,n,t,i,s){for(var a=verb.eval.nurbs.zeros_2d(2,i.length),o=verb.eval.nurbs.zeros_2d(2,i.length),u=0;i.length>u;u++)a[0][u]=i[u],o[0][u]=s[u];for(var v=numeric.mul(e,r),u=0;i.length>u;u++)a[1][u]=numeric.add(v,i[u]),o[1][u]=s[u];return{knots_u:[0,0,1,1],knots_v:n,control_points:a,degree_u:1,degree_v:t,weights:o}},verb.eval.nurbs.get_revolved_surface=function(e,r,n,t,i,s,a){var o,u,v,l;Math.PI/2>=n?(o=1,u=verb.eval.nurbs.zeros_1d(6+2*(o-1))):Math.PI>=n?(o=2,u=verb.eval.nurbs.zeros_1d(6+2*(o-1)),u[3]=u[4]=.5):3*Math.PI/2>=n?(o=3,u=verb.eval.nurbs.zeros_1d(6+2*(o-1)),u[3]=u[4]=1/3,u[5]=u[6]=2/3):(o=4,u=verb.eval.nurbs.zeros_1d(6+2*(o-1)),u[3]=u[4]=.25,u[5]=u[6]=.5,u[7]=u[8]=.75);for(var b=n/o,c=3+2*(o-1),h=0;3>h;c++,h++)u[h]=0,u[c]=1;for(var _=Math.cos(b/2),g=0,m=verb.eval.nurbs.zeros_1d(o+1),f=verb.eval.nurbs.zeros_1d(o+1),v=verb.eval.nurbs.zeros_2d(2*o+1,s.length),l=verb.eval.nurbs.zeros_2d(2*o+1,s.length),h=1;o>=h;h++)g+=b,f[h]=Math.cos(g),m[h]=Math.sin(g);for(c=0;s.length>c;c++){var p=verb.eval.geom.closest_point_on_ray(s[c],e,r),d=numeric.sub(s[c],p),y=numeric.norm2(d),x=crossprod(r,d);y>verb.EPSILON&&(d=numeric.mul(1/y,d),x=numeric.mul(1/y,x)),v[0][c]=s[c];var k=s[c];l[0][c]=a[c];for(var w=x,N=0,g=0,h=1;o>=h;h++){var z=0==y?p:numeric.add(p,numeric.mul(y,f[h],d),numeric.mul(y,m[h],x));v[N+2][c]=z,l[N+2][c]=a[c];var M=numeric.sub(numeric.mul(f[h],x),numeric.mul(m[h],d));if(0==y)v[N+1][c]=p;else{var A=verb.eval.geom.intersect_rays(k,numeric.mul(1/numeric.norm2(w),w),z,numeric.mul(1/numeric.norm2(M),M)),E=numeric.add(k,numeric.mul(w,A[0]));v[N+1][c]=E}l[N+1][c]=_*a[c],N+=2,o>h&&(k=z,w=M)}}return{knots_u:u,knots_v:t,control_points:v,degree_u:2,degree_v:i,weights:l}},verb.eval.nurbs.get_arc=function(e,r,n,t,i,s){return verb.eval.nurbs.get_ellipse_arc(e,r,n,t,t,i,s)},verb.eval.nurbs.curve_knot_insert=function(e,r,n,t,i,s){var a=(n[0].length,r.length-e-2),o=n.length,u=verb.eval.nurbs.knot_span(e,t,r),v=a+e+1,l=o+s,b=Array(e+1),c=Array(r.length+s),h=Array(l),_=0;for(_=0;u>=_;_++)c[_]=r[_];for(_=1;s>=_;_++)c[u+_]=t;for(_=u+1;v>=_;_++)c[_+s]=r[_];for(_=0;u-e>=_;_++)h[_]=n[_];for(_=u-i;a>=_;_++)h[_+s]=n[_];for(_=0;e-i>=_;_++)b[_]=n[u-e+1];for(var g=0,m=0,f=1;s>=f;f++){for(g=u-e+f,_=0;e-f-i>=_;_++)m=(t-r[g+_])/(r[_+u+1]-r[g+_]),b[_]=numeric.add(numeric.mul(m,b[_+1]),numeric.mul(1-m,b[_]));h[g]=b[0],h[u+s-f-i]=b[e-f-i]}for(_=g+1;u-i>_;_++)h[_]=b[_-g];return[c,h]},verb.eval.nurbs.rational_surface_derivs=function(e,r,n,t,i,s,a,o){var u=verb.eval.nurbs.surface_derivs(e,r,n,t,i,s,a,o),v=verb.eval.nurbs.separate_homo_derivs_2d(u),l=v[0],b=v[1],c=0,h=0,_=0,g=0,m=[],f=l[0][0].length;for(c=0;s>=c;c++)for(m.push([]),g=0;s-c>=g;g++){var o=l[c][g];for(_=1;g>=_;_++)o=numeric.sub(o,numeric.mul(numeric.mul(binomial.get(g,_),b[0][_]),m[c][g-_]));for(h=1;c>=h;h++){o=numeric.sub(o,numeric.mul(numeric.mul(binomial.get(c,h),b[h][0]),m[c-h][g]));var p=verb.eval.nurbs.zeros_1d(f);for(_=1;g>=_;_++)p=numeric.add(p,numeric.mul(numeric.mul(binomial.get(g,_),b[h][_]),m[c-h][g-_]));o=numeric.sub(o,numeric.mul(binomial.get(c,h),p))}m[c].push(numeric.mul(1/b[0][0],o))}return m},verb.eval.nurbs.rational_surface_point=function(e,r,n,t,i,s,a){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.surface_point(e,r,n,t,i,s,a))},verb.eval.nurbs.rational_curve_derivs=function(e,r,n,t,i){var s=verb.eval.nurbs.separate_homo_derivs_1d(verb.eval.nurbs.curve_derivs(e,r,n,t,i)),a=s[0],o=s[1],u=0,v=0,l=[];for(u=0;i>=u;u++){var b=a[u];for(v=1;u>=v;v++)b=numeric.sub(b,numeric.mul(numeric.mul(binomial.get(u,v),o[v]),l[u-v]));l.push(numeric.mul(1/o[0],b))}return l},verb.eval.nurbs.separate_homo_derivs_1d=function(e){for(var r=e[0].length,n=r-1,t=[],i=[],s=0,a=e.length;a>s;s++)t.push(e[s].slice(0,n)),i.push(e[s][n]);return[t,i]},verb.eval.nurbs.separate_homo_derivs_2d=function(e){for(var r=[],n=[],t=0,i=e.length;i>t;t++){var s=verb.eval.nurbs.separate_homo_derivs_1d(e[t]);r.push(s[0]),n.push(s[1])}return[r,n]},verb.eval.nurbs.rational_curve_point=function(e,r,n,t){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.curve_point(e,r,n,t))},verb.eval.nurbs.dehomogenize=function(e){for(var r=e.length,n=[],t=e[r-1],i=0;e.length-1>i;i++)n.push(e[i]/t);return n},verb.eval.nurbs.homogenize_1d=function(e,r){for(var n=e.length,t=e[0].length,i=0,s=[],a=0,o=[],u=0;n>u;u++){var v=[];for(o=e[u],a=r[u],i=0;t>i;i++)v.push(o[i]*a);v.push(a),s.push(v)}return s},verb.eval.nurbs.homogenize_2d=function(e,r){for(var n=e.length,t=(e[0].length,e[0][0].length,[]),i=0;n>i;i++)t.push(verb.eval.nurbs.homogenize_1d(e[i],r[i]));return t},verb.eval.nurbs.surface_derivs=function(e,r,n,t,i,s,a,o){var u=r.length-e-2,v=t.length-n-2;return verb.eval.nurbs.surface_derivs_given_n_m(u,e,r,v,n,t,i,s,a,o)},verb.eval.nurbs.surface_derivs_given_n_m=function(e,r,n,t,i,s,a,o,u,v){if(verb.eval.nurbs.are_valid_relations(r,a.length,n.length)===!1||verb.eval.nurbs.are_valid_relations(i,a[0].length,s.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var l=a[0][0].length,b=Math.min(o,r),c=Math.min(o,i),h=verb.eval.nurbs.zeros_3d(b+1,c+1,l),_=verb.eval.nurbs.knot_span_given_n(e,r,u,n),g=verb.eval.nurbs.knot_span_given_n(t,i,v,s),m=verb.eval.nurbs.deriv_basis_functions_given_n_i(_,u,r,e,n),f=verb.eval.nurbs.deriv_basis_functions_given_n_i(g,v,i,t,s),p=verb.eval.nurbs.zeros_2d(i+1,l),d=0,y=0,x=0,k=0,w=0;for(d=0;b>=d;d++){for(y=0;i>=y;y++)for(p[y]=verb.eval.nurbs.zeros_1d(l),x=0;r>=x;x++)p[y]=numeric.add(p[y],numeric.mul(m[d][x],a[_-r+x][g-i+y]));for(w=Math.min(o-d,c),k=0;w>=k;k++)for(h[d][k]=verb.eval.nurbs.zeros_1d(l),y=0;i>=y;y++)h[d][k]=numeric.add(h[d][k],numeric.mul(f[k][y],p[y]))}return h},verb.eval.nurbs.surface_point=function(e,r,n,t,i,s,a){var o=r.length-e-2,u=t.length-n-2;return verb.eval.nurbs.surface_point_given_n_m(o,e,r,u,n,t,i,s,a)},verb.eval.nurbs.volume_point=function(e,r,n,t,i,s,a,o,u,v){var l=r.length-e-2,b=t.length-n-2,c=s.length-i-2;return verb.eval.nurbs.volume_point_given_n_m_l(l,e,r,b,n,t,c,i,s,a,o,u,v)},verb.eval.nurbs.volume_point_given_n_m_l=function(e,r,n,t,i,s,a,o,u,v,l,b,c){if(!verb.eval.nurbs.are_valid_relations(r,v.length,n.length)||!verb.eval.nurbs.are_valid_relations(i,v[0].length,s.length)||!verb.eval.nurbs.are_valid_relations(o,v[0][0].length,u.length))return console.error("Invalid relations between control points and knot vector"),null;for(var h=v[0][0][0].length,_=verb.eval.nurbs.knot_span_given_n(e,r,l,n),g=verb.eval.nurbs.knot_span_given_n(t,i,b,s),m=verb.eval.nurbs.knot_span_given_n(a,o,c,u),f=verb.eval.nurbs.basis_functions_given_knot_span_index(_,l,r,n),p=verb.eval.nurbs.basis_functions_given_knot_span_index(g,b,i,s),d=verb.eval.nurbs.basis_functions_given_knot_span_index(m,c,o,u),y=_-r,x=g,k=m,w=verb.eval.nurbs.zeros_1d(h),N=verb.eval.nurbs.zeros_1d(h),z=verb.eval.nurbs.zeros_1d(h),M=0,A=0,E=0;o>=E;E++){for(z=verb.eval.nurbs.zeros_1d(h),k=m-o+E,M=0;i>=M;M++){for(N=verb.eval.nurbs.zeros_1d(h),x=g-i+M,A=0;r>=A;A++)N=numeric.add(N,numeric.mul(f[A],v[y+A][x][k]));z=numeric.add(z,numeric.mul(p[M],N))}w=numeric.add(w,numeric.mul(d[E],z))}return w},verb.eval.nurbs.surface_point_given_n_m=function(e,r,n,t,i,s,a,o,u){if(verb.eval.nurbs.are_valid_relations(r,a.length,n.length)===!1||verb.eval.nurbs.are_valid_relations(i,a[0].length,s.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var v=a[0][0].length,l=verb.eval.nurbs.knot_span_given_n(e,r,o,n),b=verb.eval.nurbs.knot_span_given_n(t,i,u,s),c=verb.eval.nurbs.basis_functions_given_knot_span_index(l,o,r,n),h=verb.eval.nurbs.basis_functions_given_knot_span_index(b,u,i,s),_=l-r,g=b,m=verb.eval.nurbs.zeros_1d(v),f=verb.eval.nurbs.zeros_1d(v),p=0,d=0;for(p=0;i>=p;p++){for(f=verb.eval.nurbs.zeros_1d(v),g=b-i+p,d=0;r>=d;d++)f=numeric.add(f,numeric.mul(c[d],a[_+d][g]));m=numeric.add(m,numeric.mul(h[p],f))}return m},verb.eval.nurbs.curve_derivs=function(e,r,n,t,i){var s=r.length-e-2;return verb.eval.nurbs.curve_derivs_given_n(s,e,r,n,t,i)},verb.eval.nurbs.curve_derivs_given_n=function(e,r,n,t,i,s){if(verb.eval.nurbs.are_valid_relations(r,t.length,n.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var a=t[0].length,o=Math.min(s,r),u=verb.eval.nurbs.zeros_2d(o+1,a),v=verb.eval.nurbs.knot_span_given_n(e,r,i,n),l=verb.eval.nurbs.deriv_basis_functions_given_n_i(v,i,r,o,n),b=0,c=0;for(b=0;o>=b;b++)for(c=0;r>=c;c++)u[b]=numeric.add(u[b],numeric.mul(l[b][c],t[v-r+c]));return u},verb.eval.nurbs.are_valid_relations=function(e,r,n){return 0===r+e+1-n?!0:!1},verb.eval.nurbs.curve_point=function(e,r,n,t){var i=r.length-e-2;return verb.eval.nurbs.curve_point_given_n(i,e,r,n,t)},verb.eval.nurbs.curve_point_given_n=function(e,r,n,t,i){if(verb.eval.nurbs.are_valid_relations(r,t.length,n.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;for(var s=verb.eval.nurbs.knot_span_given_n(e,r,i,n),a=verb.eval.nurbs.basis_functions_given_knot_span_index(s,i,r,n),o=verb.eval.nurbs.zeros_1d(t[0].length),u=0;r>=u;u++)o=numeric.add(o,numeric.mul(a[u],t[s-r+u]));return o},verb.eval.nurbs.zeros_1d=function(e){e=e>0?e:0;for(var r=[];e--;)r.push(0);return r},verb.eval.nurbs.zeros_2d=function(e,r){r=r>0?r:0,e=e>0?e:0;for(var n=[],t=r,i=e;e--;){for(n.push([]);t--;)n[i-e-1].push(0);t=r}return n},verb.eval.nurbs.zeros_3d=function(e,r,n){r=r>0?r:0,e=e>0?e:0;for(var t=[],i=r,s=e;e--;){for(t.push([]);i--;)t[s-e-1].push(verb.eval.nurbs.zeros_1d(n));i=r}return t},verb.eval.nurbs.deriv_basis_functions=function(e,r,n){var t=verb.eval.nurbs.knot_span(r,e,n),i=n.length-1,s=i-r-1;return verb.eval.nurbs.deriv_basis_functions_given_n_i(t,e,r,s,n)},verb.eval.nurbs.deriv_basis_functions_given_n_i=function(e,r,n,t,i){var s=verb.eval.nurbs.zeros_2d(n+1,n+1),a=Array(n+1),o=Array(n+1),u=0,v=0,l=1,b=0;for(s[0][0]=1,l=1;n>=l;l++){for(a[l]=r-i[e+1-l],o[l]=i[e+l]-r,u=0,b=0;l>b;b++)s[l][b]=o[b+1]+a[l-b],v=s[b][l-1]/s[l][b],s[b][l]=u+o[b+1]*v,u=a[l-b]*v;s[l][l]=u}var c=verb.eval.nurbs.zeros_2d(t+1,n+1),h=verb.eval.nurbs.zeros_2d(2,n+1),_=1,g=0,m=1,f=0,p=0,d=0,y=0,x=0;for(l=0;n>=l;l++)c[0][l]=s[l][n];for(b=0;n>=b;b++)for(g=0,m=1,h[0][0]=1,_=1;t>=_;_++){for(f=0,p=b-_,d=n-_,b>=_&&(h[m][0]=h[g][0]/s[d+1][p],f=h[m][0]*s[p][d]),y=p>=-1?1:-p,x=d>=b-1?_-1:n-b,l=y;x>=l;l++)h[m][l]=(h[g][l]-h[g][l-1])/s[d+1][p+l],f+=h[m][l]*s[p+l][d];d>=b&&(h[m][_]=-h[g][_-1]/s[d+1][b],f+=h[m][_]*s[b][d]),c[_][b]=f,l=g,g=m,m=l}for(b=n,_=1;t>=_;_++){for(l=0;n>=l;l++)c[_][l]*=b;b*=n-_}return c},verb.eval.nurbs.basis_functions=function(e,r,n){var t=verb.eval.nurbs.knot_span(e,r,n);return verb.eval.nurbs.basis_functions_given_knot_span_index(t,e,r,n)},verb.eval.nurbs.basis_functions_given_knot_span_index=function(e,r,n,t){var i=Array(n+1),s=Array(n+1),a=Array(n+1),o=0,u=0;i[0]=1;for(var v=1;n>=v;v++){s[v]=r-t[e+1-v],a[v]=t[e+v]-r,o=0;for(var l=0;v>l;l++)u=i[l]/(a[l+1]+s[v-l]),i[l]=o+a[l+1]*u,o=s[v-l]*u;i[v]=o}return i},verb.eval.nurbs.knot_span=function(e,r,n){var t=n.length-1,i=t-e-1;return verb.eval.nurbs.knot_span_given_n(i,e,r,n)},verb.eval.nurbs.knot_span_given_n=function(e,r,n,t){if(n>=t[e+1])return e;if(t[r]>n)return r;for(var i=r,s=e+1,a=Math.floor((i+s)/2);t[a]>n||n>=t[a+1];)t[a]>n?s=a:i=a,a=Math.floor((i+s)/2);return a};
+/*! verb 2014-02-01 */
+function getEastNeighbor(e,r,t,n,i,s){return t===i-1?null:s[e+1]}function getNorthNeighbor(e,r,t,n,i,s){return 0===r?null:s[e-i]}function getSouthNeighbor(e,r,t,n,i,s){return r===n-1?null:s[e+i]}function getWestNeighbor(e,r,t,n,i,s){return 0===t?null:s[e-1]}function crossprod(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]}if("object"!=typeof exports||void 0===exports)var verb={},numeric=window.numeric,binomial=window.binomial,labor=window.labor;else var verb=module.exports={},numeric=require("numeric"),binomial=require("binomial"),labor=require("labor");verb.geom=verb.geom||{},verb.core=verb.core||{},verb.eval=verb.eval||{},verb.intersect=verb.intersect||{},verb.eval.nurbs=verb.eval.nurbs||{},verb.eval.geom=verb.eval.geom||{},verb.eval.mesh=verb.eval.mesh||{},verb.EPSILON=1e-8,verb.TOLERANCE=.001,verb.init=function(){verb.nurbsEngine=new verb.core.Engine(verb.eval.nurbs),verb.geom.NurbsGeometry.prototype.nurbsEngine=verb.nurbsEngine},Function.prototype.method=function(e,r){return this.prototype[e]=r,this},Function.method("inherits",function(e){return this.prototype=new e,this.prototype,this.prototype.constructor=e,this}),Array.prototype.flatten=function(){if(0==this.length)return[];for(var e=[],r=0;this.length>r;r++)e=this[r]instanceof Array?e.concat(this[r].flatten()):e.concat(this[r]);return e},numeric.normalized=function(e){return numeric.div(e,numeric.norm2(e))},numeric.cross=function(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]},verb.left=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(0,r)},verb.right=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r)},verb.rightWithPivot=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r-1)},verb.unique=function(e,r){if(0===e.length)return[];for(var t=[e.pop()],n=0;e.length>n;n++){for(var i=e.pop(),s=!0,a=0;t.length>a;a++)if(r(i,t[n])){s=!1;break}s&&t.push(i)}return t},verb.range=function(e,r,t){1>=arguments.length&&(r=e||0,e=0),t=arguments[2]||1;for(var n=Math.max(Math.ceil((r-e)/t),0),i=0,s=Array(n);n>i;)s[i++]=e,e+=t;return s},verb.core.Engine=function(e){var r="function"==typeof Worker&&(e.use_pool||void 0===e.use_pool),t=e.num_workers||2,n=e.tolerance||1e-4,i=e.url||"js/verbEval.js",s=e.library||verb.eval.nurbs,a=e.error_handler||function(e){console.warn(e)},o=void 0,u=function(){try{o=new labor.Pool(i,t),o.start()}catch(e){return a("Failed to initialize labor.Pool: "+e),!1}return!0},v=function(e,r){return s[e].apply(null,r)};this.start=function(){r&&u()},this.eval=function(e,t,n){return n?(r&&(o||void 0===o&&u())?o.addWork(e,t,n):setTimeout(function(){n(v(e,t))},0),void 0):v(e,t)},this.setTolerance=function(e){n=e},this.setUsePool=function(e){return e&&void 0===o&&u()?(r=e,!0):e?!1:(o=null,delete o,!0)},this.setErrorHandler=function(e){a=e},this.setNumThreads=function(e){t=e}},verb.core.WatchObject=function(){var e={change:{}},r={},t=0,i=this,s=function(r,t){if("string"==typeof r){for(ele in e[r])e[r][ele](t);for(ele in e.change)e.change[ele](t)}else for(n in r)s(n,t)};this.get=function(e){return r[e]},this.set=function(t,n){var a=r[t];r[t]=n,e[t]=e[t]||{},s(t,{name:t,old:a,"new":n,target:i,type:"full"})},this.setAll=function(t){var n={};for(propName in t)n[propName]=r[propName],r[propName]=t[propName],e[propName]=e[propName]||{};s(t,{old:n,"new":t,target:i,type:"multi"})},this.setAt=function(e,t,n){var a=r[e];if(!(void 0===a||a.length>=t||0>t)){var o=r[e][t];r[e][t]=n,s(e,{name:e,index:t,old:o,"new":n,target:i,type:"index"})}},this.watch=function(n,i){return void 0!==r[n]&&i?(t++,e[n][t]=i,t++):void 0},this.watchAll=function(e,r){for(var t=[],n=0;e.length>n;n++)t.push(this.watch(e[n],r));return t},this.ignore=function(r,t){void 0!==e[r]&&void 0!==e[r][t]&&(e[r][t]=void 0)}},verb.core.uid=function(){var e=0;return function(){return e++}}(),verb.geom.Geometry=function(){verb.core.WatchObject.call(this);var e=verb.core.uid();this.uniqueId=function(){return e}}.inherits(verb.core.WatchObject),verb.geom.NurbsGeometry=function(){verb.geom.Geometry.call(this)}.inherits(verb.geom.Geometry),verb.geom.NurbsCurve=function(e,r,t,n){verb.geom.NurbsGeometry.call(this),this.setAll({controlPoints:r,weights:t,knots:n?n.slice(0):[],degree:e})}.inherits(verb.geom.NurbsGeometry),verb.geom.NurbsCurve.prototype.point=function(e,r){return this.nurbsEngine.eval("rational_curve_point",[this.get("degree"),this.get("knots"),this.homogenize(),e],r)},verb.geom.NurbsCurve.prototype.derivatives=function(e,r,t){return this.nurbsEngine.eval("rational_curve_derivs",[this.get("degree"),this.get("knots"),this.homogenize(),e,r],t)},verb.geom.NurbsCurve.prototype.tesselate=function(e,r){var e=e||{};return e.tolerance=e.tolerance||verb.EPSILON,this.nurbsEngine.eval("rational_curve_adaptive_sample",[this.get("degree"),this.get("knots"),this.homogenize(),e.tolerance],r)},verb.geom.NurbsCurve.prototype.transform=function(e){for(var r=this.get("controlPoints"),t=0;r.length>t;t++){var n=r[1].push(1);r[t]=numeric.mul(e,n).slice(0,n.length-2)}return this.set("controlPoints",r),this},verb.geom.NurbsCurve.prototype.clone=function(){for(var e=this.get("controlPoints"),r=[],t=0;e.length>t;t++)r.push(e[t].slice(0));return new verb.geom.NurbsCurve(this.get("degree"),r,this.get("weights").slice(0),this.get("knots").slice)},verb.geom.NurbsCurve.prototype.homogenize=function(){return verb.eval.nurbs.homogenize_1d(this.get("controlPoints"),this.get("weights"))},verb.geom.NurbsCurve.prototype.update=function(){if(this.nurbsRep){var e=this.nurbsRep();this.setAll({controlPoints:e.control_points,weights:e.weights,knots:e.knots,degree:e.degree})}},verb.geom.NurbsSurface=function(e,r,t,n,i,s){verb.geom.NurbsGeometry.call(this),this.setAll({controlPoints:i,weights:s,knotsU:r?r.slice(0):[],knotsV:n?n.slice(0):[],degreeU:e,degreeV:t})}.inherits(verb.geom.NurbsGeometry),verb.geom.NurbsSurface.prototype.point=function(e,r,t){return this.nurbsEngine.eval("rational_surface_point",[this.get("degreeU"),this.get("knotsU"),this.get("degreeV"),this.get("knotsV"),this.homogenize(),e,r],t)},verb.geom.NurbsSurface.prototype.derivatives=function(e,r,t,n){return this.nurbsEngine.eval("rational_surface_derivs",[this.get("degreeU"),this.get("knotsU"),this.get("degreeV"),this.get("knotsV"),this.homogenize(),t,e,r],n)},verb.geom.NurbsSurface.prototype.tesselate=function(e,r){var t=20,n=20;return e&&(t=e.minDivsV||t,n=e.minDivsU||n),this.nurbsEngine.eval("tesselate_rational_surface_naive",[this.get("degreeU"),this.get("knotsU"),this.get("degreeV"),this.get("knotsV"),this.homogenize(),n,t],r)},verb.geom.NurbsSurface.prototype.transform=function(e){for(var r=this.get("controlPoints"),t=0;r.length>t;t++)for(var n=0;r[t].length>n;n++){var i=r[1].push(1);r[t]=numeric.mul(e,i).slice(0,i.length-2)}return this.set("controlPoints",r),this},verb.geom.NurbsSurface.prototype.clone=function(){for(var e=this.get("controlPoints"),r=[],t=0;e.length>t;t++){r.push([]);for(var n=0;e[t].length>n;n++)r[t].push(e[t][n].slice(0))}for(var i=this.get("weights"),s=[],t=0;i.length>t;t++)s.push(i[t].slice(0));return new verb.geom.NurbsSurface(this.get("degreeU"),this.get("knotsU").slice(0),this.get("degreeV"),this.get("knotsV").slice(0),r,s)},verb.geom.NurbsSurface.prototype.homogenize=function(){return verb.eval.nurbs.homogenize_2d(this.get("controlPoints"),this.get("weights"))},verb.geom.NurbsSurface.prototype.update=function(){if(this.nurbsRep){var e=this.nurbsRep();this.setAll({controlPoints:e.control_points,weights:e.weights,knotsU:e.knots_u,knotsV:e.knots_v,degreeU:e.degree_u,degreeV:e.degree_v})}},verb.geom.Arc=function(e,r,t,n,i){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:t,radius:n,interval:i}),this.update(),this.watchAll(["center","xaxis","yaxis","radius","interval"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Arc.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("radius"),this.get("interval").get("min"),this.get("interval").get("max")])},verb.geom.BezierCurve=function(e,r){verb.geom.NurbsCurve.call(this),this.setAll({controlPoints:e?e.slice(0):[],weights:r?r.slice(0):void 0}),this.update()}.inherits(verb.geom.NurbsCurve),verb.geom.BezierCurve.prototype.nurbsRep=function(){for(var e=this.get("controlPoints"),r=this.get("weights"),t=e.length-1,n=[],i=0;t+1>i;i++)n.push(0);for(var i=0;t+1>i;i++)n.push(1);if(void 0===r){r=[];for(var i=0;e.length>i;i++)r.push(1)}return{degree:t,knots:n,control_points:e,weights:r}},verb.geom.BoundingBox=function(){this.initialized=!1,this.min=[0,0,0],this.max=[0,0,0];var e=Array.prototype.slice.call(arguments,0);1===e.length&&e[0]instanceof Array&&e[0][0]instanceof Array?this.add_elements_sync(e[0]):this.add_elements_sync(e)},verb.geom.BoundingBox.prototype.add_elements=function(e,r){var t=this;setTimeout(function(){e.forEach(function(e){t.add(e)}),r(t)},0)},verb.geom.BoundingBox.prototype.add_elements_sync=function(e){var r=this;return e.forEach(function(e){r.add(e)}),this},verb.geom.BoundingBox.prototype.add=function(e){return this.initialized?(e[0]>this.max[0]&&(this.max[0]=e[0]),e[1]>this.max[1]&&(this.max[1]=e[1]),e[2]>this.max[2]&&(this.max[2]=e[2]),e[0]<this.min[0]&&(this.min[0]=e[0]),e[1]<this.min[1]&&(this.min[1]=e[1]),e[2]<this.min[2]&&(this.min[2]=e[2]),this):(this.min=e.slice(0),this.max=e.slice(0),this.initialized=!0,this)},verb.geom.BoundingBox.prototype.contains=function(e,r){return this.initialized?this.intersects(new verb.geom.BoundingBox(e),r):!1},verb.geom.BoundingBox.prototype.TOLERANCE=1e-4,verb.geom.BoundingBox.prototype.intervals_overlap=function(e,r,t,n,i){var i=i||verb.geom.BoundingBox.prototype.TOLERANCE,s=Math.min(e,r)-i,a=Math.max(e,r)+i,o=Math.min(t,n)-i,u=Math.max(t,n)+i;return s>=o&&u>=s||a>=o&&u>=a||o>=s&&a>=o||u>=s&&a>=u?!0:!1},verb.geom.BoundingBox.prototype.intersects=function(e,r){if(!this.initialized||!e.initialized)return!1;var t=this.min,n=this.max,i=e.min,s=e.max;return this.intervals_overlap(t[0],n[0],i[0],s[0],r)&&this.intervals_overlap(t[1],n[1],i[1],s[1],r)&&this.intervals_overlap(t[2],n[2],i[2],s[2],r)?!0:!1},verb.geom.BoundingBox.prototype.clear=function(){return this.initialized=!1,this},verb.geom.BoundingBox.prototype.get_longest_axis=function(){var e=[this.get_axis_length(0),this.get_axis_length(1),this.get_axis_length(2)];return e.indexOf(Math.max.apply(Math,e))},verb.geom.BoundingBox.prototype.get_axis_length=function(e){return 0>e||e>2?0:Math.abs(this.min[e]-this.max[e])},verb.geom.BoundingBox.prototype.intersect=function(e,r){if(!this.initialized)return null;var t=this.min,n=this.max,i=e.min,s=e.max;if(!this.intersects(e,r))return null;var a=Math.min(n[0],s[0]),o=Math.max(t[0],i[0]),u=Math.min(n[1],s[1]),v=Math.max(t[1],i[1]),l=Math.min(n[2],s[2]),c=Math.max(t[2],i[2]),b=[a,u,l],h=[o,v,c];return new verb.geom.BoundingBox(h,b)},verb.geom.Circle=function(e,r,t,n){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:t,radius:n}),this.update(),this.watchAll(["center","xaxis","yaxis","radius"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Circle.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("radius"),0,2*Math.PI])},verb.geom.Cone=function(e,r,t,n,i){verb.geom.NurbsSurface.call(this),this.setAll({axis:e,xaxis:r,base:t,height:n,radius:i});var s=this.nurbsRep();verb.geom.NurbsSurface.call(this,s.degree_u,s.knots_u,s.degree_v,s.knots_v,s.control_points,s.weights),this.watchAll(["axis","xaxis","base","height","radius"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Cone.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_cone_surface",[this.get("axis"),this.get("xaxis"),this.get("base"),this.get("height"),this.get("radius")])},verb.geom.Cylinder=function(e,r,t,n,i){this.setAll({axis:e,xaxis:r,base:t,height:n,radius:i});var s=this.nurbsRep();verb.geom.NurbsSurface.call(this,s.degree_u,s.knots_u,s.degree_v,s.knots_v,s.control_points,s.weights),this.watchAll(["axis","xaxis","base","height","radius"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Cylinder.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_cylinder_surface",[this.get("axis"),this.get("xaxis"),this.get("base"),this.get("height"),this.get("radius")])},verb.geom.Ellipse=function(e,r,t,n,i){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:t,xradius:n,yradius:i}),this.update(),this.watchAll(["center","xaxis","yaxis","xradius","yradius"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Ellipse.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_ellipse_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("xradius"),this.get("yradius"),0,2*Math.PI])},verb.geom.EllipseArc=function(e,r,t,n,i,s){verb.geom.NurbsCurve.call(this),this.setAll({center:e,xaxis:r,yaxis:t,xradius:n,yradius:i,interval:s}),this.update(),this.watchAll(["center","xaxis","yaxis","xradius","yradius","interval"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.EllipseArc.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_ellipse_arc",[this.get("center"),this.get("xaxis"),this.get("yaxis"),this.get("xradius"),this.get("yradius"),this.get("interval").get("min"),this.get("interval").get("max")])},verb.geom.Extrusion=function(e,r,t){verb.geom.NurbsSurface.call(this),this.setAll({profile:e,axis:r,length:t}),this.update(),this.watchAll(["axis","length"],this.update),e.watchAll(["knots","degree","controlPoints","weights"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Extrusion.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_extruded_surface",[this.get("axis"),this.get("length"),this.get("profile").get("knots"),this.get("profile").get("degree"),this.get("profile").get("controlPoints"),this.get("profile").get("weights")])},verb.geom.FourPointSurface=function(e,r,t,n){verb.geom.NurbsSurface.call(this),this.setAll({p1:e,p2:r,p3:t,p4:n}),this.update(),this.watchAll(["p1","p2","p3","p4"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.FourPointSurface.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_4pt_surface",[this.get("p1"),this.get("p2"),this.get("p3"),this.get("p4")])},verb.geom.Interval=function(e,r){verb.core.WatchObject.call(this),this.setAll({min:e,max:r})}.inherits(verb.core.WatchObject),verb.geom.Interval2=function(e,r,t,n){verb.core.WatchObject.call(this),this.setAll({uinterval:new verb.geom.Interval(e,r),vinterval:new verb.geom.Interval(t,n)})}.inherits(verb.core.WatchObject),verb.geom.Line=function(e,r){verb.geom.NurbsCurve.call(this),this.setAll({start:e,end:r}),this.update(),this.watchAll(["start","end"],this.update)}.inherits(verb.geom.NurbsCurve),verb.geom.Line.prototype.nurbsRep=function(){return{knots:[0,0,1,1],control_points:[this.get("start"),this.get("end")],weights:[1,1],degree:1}},verb.geom.PlanarSurface=function(e,r,t,n,i){verb.geom.NurbsSurface.call(this),this.setAll({base:e,uaxis:r,vaxis:t,ulength:n,vlength:i}),this.update(),this.watchAll(["base","uaxis","vaxis","ulength","vlength"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.PlanarSurface.prototype.nurbsRep=function(){var e=this.get("base"),r=numeric.mul(this.get("uaxis"),this.get("ulength")),t=numeric.mul(this.get("vaxis"),this.get("vlength")),n=numeric.add(e,r),i=numeric.add(e,t,r),s=numeric.add(e,t);return this.nurbsEngine.eval("get_4pt_surface",[e,n,i,s])},verb.geom.PolyLine=function(e){verb.geom.NurbsCurve.call(this),this.setAll({control_points:e?e.slice(0):[]}),this.update()}.inherits(verb.geom.NurbsCurve),verb.geom.PolyLine.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_polyline_curve",[this.get("control_points")])},verb.geom.RevolvedSurface=function(e,r,t,n){verb.geom.NurbsSurface.call(this),this.setAll({center:e,axis:r,angle:t,profile:n}),this.update(),this.watchAll(["center","axis","angle","profile"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.RevolvedSurface.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_revolved_surface",[this.get("center"),this.get("axis"),this.get("angle"),this.get("profile").get("knots"),this.get("profile").get("degree"),this.get("profile").get("controlPoints"),this.get("profile").get("weights")])},verb.geom.Sphere=function(e,r){verb.geom.NurbsSurface.call(this),this.setAll({center:e,radius:r}),this.update(),this.watchAll(["center","radius"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.Sphere.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_sphere_surface",[this.get("center"),[0,0,1],[1,0,0],this.get("radius")])},verb.geom.SweepOneRail=function(e,r){verb.geom.NurbsSurface.call(this),this.setAll({rail:e,profile:r}),this.update(),this.watchAll(["rail","profile"],this.update)}.inherits(verb.geom.NurbsSurface),verb.geom.SweepOneRail.prototype.nurbsRep=function(){return this.nurbsEngine.eval("get_sweep1_surface",[this.get("profile").get("knots"),this.get("profile").get("degree"),this.get("profile").get("controlPoints"),this.get("profile").get("weights"),this.get("rail").get("knots"),this.get("rail").get("degree"),this.get("rail").get("controlPoints"),this.get("rail").get("weights")])},verb.intersect.curveCurve=function(e,r,t){return verb.nurbsEngine.eval("intersect_rational_curves_by_aabb_refine",[e.get("degree"),e.get("knots"),e.homogenize(),r.get("degree"),r.get("knots"),r.homogenize(),verb.TOLERANCE,verb.TOLERANCE],t)},verb.intersect.curveSurface=function(e,r,t,n){return t=t||{tolerance:verb.TOLERANCE,sampleTolerance:verb.TOLERANCE,uDivs:20,vDivs:20},verb.nurbsEngine.eval("intersect_rational_curve_surface_by_aabb_refine",[r.get("degreeU"),r.get("knotsU"),r.get("degreeV"),r.get("knotsV"),r.homogenize(),e.get("degree"),e.get("knots"),e.homogenize(),t.sampleTolerance,t.tolerance,t.uDivs,t.vDivs],n)},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb_refine=function(e,r,t,n,i,s,a,o,u,v,l,c){var b=verb.eval.nurbs.intersect_rational_curve_surface_by_aabb(e,r,t,n,i,s,a,o,u,v,l,c);return b.map(function(u){var v=[u.p,u.uv[0],u.uv[1]],l=verb.eval.nurbs.refine_rational_curve_surface_intersection(e,r,t,n,i,s,a,o,v);return u.p=l[0],u.uv[0]=l[1],u.uv[1]=l[2],u.distance=l[3],delete u.face,u})},verb.eval.nurbs.refine_rational_curve_surface_intersection=function(e,r,t,n,i,s,a,o,u){var v=function(u){var v=verb.eval.nurbs.rational_curve_point(s,a,o,u[0]),l=verb.eval.nurbs.rational_surface_point(e,r,t,n,i,u[1],u[2]),c=numeric.sub(v,l);return numeric.dot(c,c)},l=numeric.uncmin(v,u);return l.solution.concat(l.f)},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb=function(e,r,t,n,i,s,a,o,u,v,l,c){var b=verb.eval.nurbs.rational_curve_adaptive_sample(s,a,o,u,!0),h=verb.eval.nurbs.tesselate_rational_surface_naive(e,r,t,n,i,l,c),g=b.map(function(e){return e[0]}),_=b.map(function(e){return e.slice(1)}),m=verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(_,g,h,verb.range(h.faces.length),v);return verb.unique(m,function(e,r){return v>numeric.norm2(numeric.sub(e.point,r.point))&&v>Math.abs(e.p-r.p)&&v>numeric.norm2(numeric.sub(e.uv,r.uv))})},verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb=function(e,r,t,n,i){var s=new verb.geom.BoundingBox(e),a=verb.eval.mesh.make_mesh_aabb(t.points,t.faces,n);if(!s.intersects(a,i))return[];if(2!==e.length||1!==n.length){if(1===n.length){var o=verb.left(e),u=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,v,t,n,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,l,t,n,i))}if(2===e.length){var c=verb.eval.mesh.sort_tris_on_longest_axis(a,t.points,t.faces,n),b=verb.left(c),h=verb.right(c);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,t,b,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,t,h,i))}var c=verb.eval.mesh.sort_tris_on_longest_axis(a,t.points,t.faces,n),b=verb.left(c),h=verb.right(c),o=verb.left(e),u=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,v,t,b,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,v,t,h,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,l,t,b,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,l,t,h,i))}var g=verb.eval.geom.intersect_segment_with_tri(e[0],e[1],t.points,t.faces[n[0]]);if(null!=g){var _=g.p*(r[1]-r[0])+r[0],m=t.faces[n][0],f=t.faces[n][1],d=t.faces[n][2],p=t.uvs[m],y=t.uvs[f],x=t.uvs[d],N=numeric.sub(y,p),k=numeric.sub(x,p),w=numeric.add(p,numeric.mul(g.s,N),numeric.mul(g.t,k));return[{point:g.point,p:_,uv:w,face:n[0]}]}return[]},verb.eval.geom.intersect_segment_with_tri=function(e,r,t,n){var i=t[n[0]],s=t[n[1]],a=t[n[2]],o=numeric.sub(s,i),u=numeric.sub(a,i),v=numeric.cross(o,u),l=numeric.sub(r,e),c=numeric.sub(e,i),b=-numeric.dot(v,c),h=numeric.dot(v,l);if(Math.abs(h)<verb.EPSILON)return null;var g=b/h;if(0>g||g>1)return null;var _=numeric.add(e,numeric.mul(g,l)),m=numeric.dot(o,u),f=numeric.dot(o,o),d=numeric.dot(u,u),p=numeric.sub(_,i),y=numeric.dot(p,o),x=numeric.dot(p,u),N=m*m-f*d,k=(m*x-d*y)/N,w=(m*y-f*x)/N;return k>1+verb.EPSILON||w>1+verb.EPSILON||-verb.EPSILON>w||-verb.EPSILON>k||k+w>1+verb.EPSILON?null:{point:_,s:k,t:w,p:g}},verb.eval.geom.intersect_segment_with_plane=function(e,r,t,n){var i=numeric.dot(n,numeric.sub(e,r));if(EPSILON>abs(i))return null;var s=numeric.dot(n,numeric.sub(t,e));return{p:s/i}},verb.eval.geom.intersect_aabb_trees=function(e,r,t,n,i,s){var a=i.bounding_box.intersects(s.bounding_box);return a?0===i.children.length&&0===s.children.length?[[i.triangle,s.triangle]]:0===i.children.length&&0!=s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,t,n,i,s.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,t,n,i,s.children[1])):0!=i.children.length&&0===s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,t,n,i.children[0],s).concat(verb.eval.geom.intersect_aabb_trees(e,r,t,n,i.children[1],s)):0!=i.children.length&&0!=s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,t,n,i.children[0],s.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,t,n,i.children[0],s.children[1])).concat(verb.eval.geom.intersect_aabb_trees(e,r,t,n,i.children[1],s.children[0])).concat(verb.eval.geom.intersect_aabb_trees(e,r,t,n,i.children[1],s.children[1])):void 0:[]},verb.eval.mesh.make_mesh_aabb_tree=function(e,r,t){var n={bounding_box:verb.eval.mesh.make_mesh_aabb(e,r,t),children:[]};if(1===t.length)return n.triangle=t[0],n;var i=verb.eval.mesh.sort_tris_on_longest_axis(n.bounding_box,e,r,t),s=i.slice(0,Math.floor(i.length/2)),a=i.slice(Math.floor(i.length/2),i.length);return n.children=[verb.eval.mesh.make_mesh_aabb_tree(e,r,s),verb.eval.mesh.make_mesh_aabb_tree(e,r,a)],n},verb.eval.mesh.make_mesh_aabb=function(e,r,t){var n=new verb.geom.BoundingBox;return t.forEach(function(t){n.add(e[r[t][0]]),n.add(e[r[t][1]]),n.add(e[r[t][2]])}),n},verb.eval.mesh.sort_tris_on_longest_axis=function(e,r,t,n){for(var i=e.get_longest_axis(),s=[],a=n.length-1;a>=0;a--){var o=n[a],u=verb.eval.mesh.get_min_coordinate_on_axis(r,t[o],i);s.push([u,o])}s.sort(function(e,r){return e[0]>r[0]});for(var v=[],a=0,l=s.length;l>a;a++)v.push(s[a][1]);return v},verb.eval.mesh.get_min_coordinate_on_axis=function(e,r,t){for(var n=[],i=0;3>i;i++)n.push(e[r[i]][t]);return Math.min.apply(Math,n)},verb.eval.geom.get_tri_centroid=function(e,r){for(var t=[0,0,0],n=0;3>n;n++)for(var i=0;3>i;i++)t[i]+=e[r[n]][i];for(var n=0;3>n;n++)t[n]/=3;return t},verb.eval.geom.get_tri_norm=function(e,r){var t=e[r[0]],n=e[r[1]],i=e[r[2]],s=numeric.sub(n,t),a=numeric.sub(i,t),o=numeric.cross(s,a);return numeric.mul(1/numeric.norm2(o),o)},verb.eval.nurbs.intersect_rational_curves_by_aabb_refine=function(e,r,t,n,i,s,a,o){var u=verb.eval.nurbs.intersect_rational_curves_by_aabb(e,r,t,n,i,s,a,o);return u.map(function(a){return verb.eval.nurbs.refine_rational_curve_intersection(e,r,t,n,i,s,a)})},verb.eval.nurbs.refine_rational_curve_intersection=function(e,r,t,n,i,s,a){var o=function(a){var o=verb.eval.nurbs.rational_curve_point(e,r,t,a[0]),u=verb.eval.nurbs.rational_curve_point(n,i,s,a[1]),v=numeric.sub(o,u);return numeric.dot(v,v)},u=numeric.uncmin(o,a);return u.solution.concat(u.f)},verb.eval.nurbs.intersect_rational_curves_by_aabb=function(e,r,t,n,i,s,a,o){var u=verb.eval.nurbs.rational_curve_adaptive_sample(e,r,t,a,!0),v=verb.eval.nurbs.rational_curve_adaptive_sample(n,i,s,a,!0),l=u.map(function(e){return e[0]}),c=v.map(function(e){return e[0]}),b=u.map(function(e){return e.slice(1)}),h=v.map(function(e){return e.slice(1)});return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(b,h,l,c,o)},verb.eval.nurbs.intersect_parametric_polylines_by_aabb=function(e,r,t,n,i){var s=new verb.geom.BoundingBox(e),a=new verb.geom.BoundingBox(r);if(!s.intersects(a,i))return[];if(2!==e.length||2!==r.length){if(2===e.length){var o=Math.ceil(r.length/2),u=r.slice(0,o),v=r.slice(o-1),l=n.slice(0,o),c=n.slice(o-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,u,t,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,v,t,c,i))}if(2===r.length){var b=Math.ceil(e.length/2),h=e.slice(0,b),g=e.slice(b-1),_=t.slice(0,b),m=t.slice(b-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,r,_,n,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(g,r,m,n,i))}var b=Math.ceil(e.length/2),h=e.slice(0,b),g=e.slice(b-1),_=t.slice(0,b),m=t.slice(b-1),o=Math.ceil(r.length/2),u=r.slice(0,o),v=r.slice(o-1),l=n.slice(0,o),c=n.slice(o-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,u,_,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,v,_,c,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(g,u,m,l,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(g,v,m,c,i))}var f=verb.eval.geom.intersect_segments(e[0],e[1],r[0],r[1],i);return null!=f?(f[0][0]=f[0][0]*(t[1]-t[0])+t[0],f[1][0]=f[1][0]*(n[1]-n[0])+n[0],[[f[0][0],f[1][0]]]):[]},verb.eval.geom.intersect_segments=function(e,r,t,n,i){var s=numeric.sub(r,e),a=Math.sqrt(numeric.dot(s,s)),o=numeric.mul(1/a,s),u=numeric.sub(n,t),v=Math.sqrt(numeric.dot(u,u)),l=numeric.mul(1/v,u),c=verb.eval.geom.intersect_rays(e,o,t,l);if(null!=c){var b=Math.min(Math.max(0,c[0]/a),1),h=Math.min(Math.max(0,c[1]/v),1),g=numeric.add(numeric.mul(b,s),e),_=numeric.add(numeric.mul(h,u),t),m=numeric.norm2Squared(numeric.sub(g,_));if(i*i>m)return[[b].concat(g),[h].concat(_)]}return null},verb.eval.geom.closest_point_on_ray=function(e,r,t){var n=numeric.sub(e,r),i=numeric.dot(n,t),s=numeric.add(r,numeric.mul(i,t));return s},verb.eval.geom.intersect_rays=function(e,r,t,n){var i=numeric.dot(r,n),s=numeric.dot(r,t),a=numeric.dot(r,e),o=numeric.dot(n,t),u=numeric.dot(n,e),v=numeric.dot(r,r),l=numeric.dot(n,n),c=v*l-i*i;if(Math.abs(c)<verb.EPSILON)return null;var b=i*(s-a)-v*(o-u),h=b/c,g=(s-a+h*i)/v;return[g,h]},verb.eval.mesh.intersect_meshes_by_aabb=function(e,r,t,n,i){var s=verb.range(r.length),a=verb.range(i.length),o=verb.eval.mesh.make_mesh_aabb_tree(e,r,s),u=verb.eval.mesh.make_mesh_aabb_tree(n,i,a);verb.eval.mesh.intersect_aabb_tree(e,r,n,i,o,u)},verb.eval.geom.intersect_tris=function(e,r,t,n,i){for(var s=[e[tr1[0]],e[tr1[1]]],a=[e[tr1[1]],e[tr1[2]]],o=[e[tr1[2]],e[tr1[0]]],u=[n[tr2[0]],n[tr2[1]]],v=[n[tr2[1]],n[tr2[2]]],l=[n[tr2[2]],n[tr2[0]]],c=[s,a,o],b=[u,v,l],h=[],g=verb.eval.geom.get_tri_norm(n,i),_=n[tr2[0]],m=0;3>m;m++){var f=verb.eval.geom.intersect_segment_with_plane(c[m][0],b[m][1],_,g);f.intersects&&h.push(f)}if(2!==h.length)return null;for(var d=[h[0].point,h[1].point],p=[],m=0;3>m;m++){var y=verb.eval.geom.intersect_segments(d[0],d[1],d,b1,tol);y&&p.push(y)}0===p.length||1===p.length||2===p.length},verb.eval.nurbs.tesselate_rational_surface_naive=function(e,r,t,n,i,s,a){1>s&&(s=1),1>a&&(a=1);for(var o=1/s,u=1/a,v=[],l=[],c=[],b=0;s+1>b;b++)for(var h=0;a+1>h;h++){var g=b*o,_=h*u;l.push([g,_]);var m=verb.eval.nurbs.rational_surface_derivs(e,r,t,n,i,1,g,_),f=m[0][0];v.push(f);var d=numeric.cross(m[0][1],m[1][0]);c.push(d)}for(var p=[],b=0;s>b;b++)for(var h=0;a>h;h++){var y=b*(a+1)+h,x=(b+1)*(a+1)+h,N=x+1,k=y+1,w=[y,x,N],E=[y,N,k];p.push(w),p.push(E)}return{points:v,faces:p,uvs:l,normals:c}},verb.eval.nurbs.rational_curve_regular_sample=function(e,r,t,n,i){return verb.eval.nurbs.rational_curve_regular_sample_range(e,r,t,0,1,n,i)},verb.eval.nurbs.rational_curve_regular_sample_range=function(e,r,t,n,i,s,a){1>s&&(s=2);for(var o=[],u=(i-n)/(s-1),v=0,l=0;s>l;l++)v=n+u*l,a?o.push([v].concat(verb.eval.nurbs.rational_curve_point(e,r,t,v))):o.push(verb.eval.nurbs.rational_curve_point(e,r,t,v));return o},verb.eval.nurbs.rational_curve_adaptive_sample=function(e,r,t,n,i){return 1===e?i?t.map(function(e,t){return[r[t+1]].concat(verb.eval.nurbs.dehomogenize(e))}):t.map(verb.eval.nurbs.dehomogenize):verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,t,0,1,n,i)},verb.eval.nurbs.rational_curve_adaptive_sample_range=function(e,r,t,n,i,s,a){var o=verb.eval.nurbs.rational_curve_point(e,r,t,n),u=verb.eval.nurbs.rational_curve_point(e,r,t,i),v=.5+.2*Math.random(),l=n+(i-n)*v,c=verb.eval.nurbs.rational_curve_point(e,r,t,l),b=numeric.sub(o,u),h=numeric.sub(o,c);if(s>numeric.dot(b,b)&&numeric.dot(h,h)>s||!verb.eval.nurbs.three_points_are_flat(o,c,u,s)){var g=n+.5*(i-n),_=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,t,n,g,s,a),m=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,t,g,i,s,a);return _.slice(0,-1).concat(m)}return a?[[n].concat(o),[i].concat(u)]:[o,u]},verb.eval.nurbs.three_points_are_flat=function(e,r,t,n){var i=numeric.sub(r,e),s=numeric.sub(t,e),a=crossprod(i,s),o=numeric.dot(a,a);return n>o},verb.eval.nurbs.divide_rational_surface_adaptive=function(e,r,t,n,i,s){for(var a={degree_u:e,knots_u:r,degree_v:t,knots_v:n,homo_control_points:i},o=s.minDivsU,u=s.minDivsV,v=Math.max.apply(null,r),l=Math.min.apply(null,r),c=Math.max.apply(null,n),b=Math.min.apply(null,n),h=(v-l)/o,g=(c-b)/u,_=[],m=0;o>m;m++)for(var f=0;u>f;f++){var d=l+h*m,p=l+h*(m+1),y=b+g*f,x=b+g*(f+1);_.push(new verb.eval.nurbs.AdaptiveRefinementNode(a,d,p,y,x,null,null))}for(var m=0;o>m;m++)for(var f=0;u>f;f++){var N=m*u+f,k=getNorthNeighbor(N,m,f,o,u,_),w=getEastNeighbor(N,m,f,o,u,_),E=getSouthNeighbor(N,m,f,o,u,_),A=getWestNeighbor(N,m,f,o,u,_);_[N].neighbors=[k,w,E,A],_.divide(s)}return _},verb.eval.nurbs.is_rational_surface_domain_flat=function(e){var r=verb.eval.nurbs.rational_surface_point,t=(u[1]-u[0]/2)*(.1*Math.random()+1),n=(v[1]-v[0]/2)*(.1*Math.random()+1),i=r(e.degree_u,e.knots_u,e.degree_v,e.knots_v,e.homo_control_points,u[0],v[0]),s=r(e.degree_u,e.knots_u,e.degree_v,e.knots_v,e.homo_control_points,u[0]+t,v[0]+n),a=r(e.degree_u,e.knots_u,e.degree_v,e.knots_v,e.homo_control_points,u[1],v[1]);return verb.eval.nurbs.three_points_are_flat(i,s,a,tol)},verb.eval.nurbs.triangulate_adaptive_refinement_node_tree=function(e){var r={uvs:[],points:[],normals:[],faces:[]};return r.faces=e.map(function(e){e.triangulate(r)}).flatten(),r},verb.eval.nurbs.tesselate_rational_surface_adaptive=function(e,r,t,n,i,s){verb.eval.nurbs.divide_rational_surface_adaptive(e,r,t,n,i,s);var a=verb.eval.nurbs.triangulate_adaptive_refinement_node_tree(arrTree);return verb.eval.nurbs.unique_mesh(a)},verb.eval.nurbs.unique_mesh=function(e){return e},Array.prototype.where=function(e){if(0===this.length)return this;for(var r=[],t=0;this.length>t;t++)e(this[t])&&r.push(this[t]);return r},verb.eval.nurbs.AdaptiveRefinementNode=function(e,r,t,n,i,s,a){this.srf=e,this.u0=r,this.u1=t,this.v0=n,this.v1=i,this.parentNode=s,this.neighbors=a,this.leafEdgeUvs=[[r,n],[t,n],[t,i],[r,i]],this.cachedEdgeUvs=[]},verb.eval.nurbs.AdaptiveRefinementNode.prototype.isLeaf=function(){return void 0===this.children},verb.eval.nurbs.AdaptiveRefinementNode.prototype.evalSurface=function(){var e=verb.eval.nurbs.rational_surface_derivs(this.srf.degree_u,this.srf.knots_u,this.srf.degree_v,this.srf.knots_v,this.srf.homo_control_points,1,pt_u,pt_v),r=e[0][0];
+points.push(r);var t=numeric.cross(e[0][1],e[1][0]);return{point:r,normal:t}},verb.eval.nurbs.AdaptiveRefinementNode.prototype.getEdgeUvs=function(e){return this.isLeaf()?[this.leafEdgeUvs[e]]:(this.cachedEdgeUvs[e]=this.cachedEdgeUvs[e]||this.children[e].getEdgeUvs(e).concat(this.children[(e+1)%4].getEdgeUvs(e)),this.cachedEdgeUvs[e])},verb.eval.nurbs.AdaptiveRefinementNode.prototype.getAllEdgeUvs=function(e){var r=[this.leafEdgeUvs[e]];if(null===this.neighbors[e])return r;var t=this.neighbors[e].getEdgeUvs((e+2)%4),n=e%2,i=this,s=[function(e){return e[0]>i.u0+verb.EPSILON&&e[0]<i.u1-verb.EPSILON},function(e){return e[1]>i.v0+verb.EPSILON&&e[1]<i.v1-verb.EPSILON}];return r.concat(t.where(s[n]).reverse())},verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulateLeaf=function(e){for(var r=e.points.length-1,t=[],n=0;4>n;n++)t.concat(this.getAllEdgeUvs(n));if(t.forEach(function(r){e.uvs.push(r);var t=this.evalSurface(r);e.points.push(t.point),e.normals.push(t.normal)}),4===t.length)return e.faces.push([r+1,r+4,r+2]),e.faces.push([r+4,r+3,r+2]),void 0;this.u05=this.u05||(this.u0+this.u1)/2,this.v05=this.v05||(this.v0+this.v1)/2,e.uvs.push([this.u05,this.v05]);var i=this.evalSurface([this.u05,this.v05]);e.points.push(i.point),e.normals.push(i.normal);for(var s=e.points.length-1,n=0;t.length>n;n++)e.faces.push([s,(r+n+2)%t.length,(r+n+1)%t.length])},verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulate=function(e){return this.isLeaf()?this.triangulateLeaf(e):(this.children.forEach(function(r){null!==r&&r.triangulate(e)}),void 0)},verb.eval.nurbs.AdaptiveRefinementNode.prototype.shouldDivide=function(e,r){return e.minDepth&&e.minDepth>r?!0:this.srf&&!verb.eval.nurbs.is_rational_surface_domain_flat(this.srf,this.u0,this.u1,this.v0,this.v1,e)?!0:!1},verb.eval.nurbs.AdaptiveRefinementNode.prototype.divide=function(e,r){void 0===r&&(r=0),this.shouldDivide(e,r)&&(r++,this.u05=(this.u0+this.u1)/2,this.v05=(this.v0+this.v1)/2,this.children=[new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u0,this.u05,this.v0,this.v05,this),new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u05,this.u1,this.v0,this.v05,this),new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u05,this.u1,this.v05,this.v1,this),new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u0,this.u05,this.v05,this.v1,this)],this.children[0].neighbors=[this.neighbors[0],this.children[1],this.children[3],this.neighbors[3]],this.children[1].neighbors=[this.neighbors[0],this.neighbors[1],this.children[2],this.children[0]],this.children[2].neighbors=[this.children[1],this.neighbors[1],this.neighbors[2],this.children[3]],this.children[3].neighbors=[this.children[0],this.children[2],this.neighbors[2],this.neighbors[3]],this.children.forEach(function(t){t.divide(e,r)}))},verb.eval.nurbs.get_sweep1_surface=function(e,r,t,n,i,s,a,o){for(var u=verb.eval.nurbs.homogenize_1d(a,o),v=verb.eval.nurbs.rational_curve_point(s,i,u,0),l=1/a.length,c=[],b=[],h=0;a.length>h;h++){for(var g=verb.eval.nurbs.rational_curve_point(s,i,u,h*l),_=numeric.sub(g,v),m=[],f=[],d=0;t.length>d;d++)m.push(numeric.add(_,t[d])),f.push(n[d]*o[h]);c.push(m),b.push(f)}return{knots_u:i,knots_v:e,control_points:c,degree_u:s,degree_v:r,weights:b}},verb.eval.nurbs.get_ellipse_arc=function(e,r,t,n,i,s,a){s>a&&(a=2*Math.PI+s);var o=a-s,u=0;u=Math.PI/2>=o?1:Math.PI>=o?2:3*Math.PI/2>=o?3:4;var v=o/u,l=Math.cos(v/2),c=numeric.add(e,numeric.mul(n,Math.cos(s),r),numeric.mul(i,Math.sin(s),t)),b=numeric.sub(numeric.mul(Math.cos(s),t),numeric.mul(Math.sin(s),r)),h=verb.eval.nurbs.zeros_1d(2*u),g=verb.eval.nurbs.zeros_1d(2*u+3),_=0,m=s,f=verb.eval.nurbs.zeros_1d(2*u);h[0]=c,f[0]=1;for(var d=1;u>=d;d++){m+=v;var p=numeric.add(e,numeric.mul(n,Math.cos(m),r),numeric.mul(i,Math.sin(m),t));f[_+2]=1,h[_+2]=p;var y=numeric.sub(numeric.mul(Math.cos(m),t),numeric.mul(Math.sin(m),r)),x=verb.eval.geom.intersect_rays(c,numeric.mul(1/numeric.norm2(b),b),p,numeric.mul(1/numeric.norm2(y),y)),N=numeric.add(c,numeric.mul(b,x[0]));f[_+1]=l,h[_+1]=N,_+=2,u>d&&(c=p,b=y)}for(var k=2*u+1,d=0;3>d;d++)g[d]=0,g[d+k]=1;switch(u){case 1:break;case 2:g[3]=g[4]=.5;break;case 3:g[3]=g[4]=1/3,g[5]=g[6]=2/3;break;case 4:g[3]=g[4]=.25,g[5]=g[6]=.5,g[7]=g[8]=.75}return{knots:g,control_points:h,degree:2,weights:f}},verb.eval.nurbs.get_sphere_surface=function(e,r,t,n){var i=verb.eval.nurbs.get_arc(e,numeric.mul(r,-1),t,n,0,Math.PI);return verb.eval.nurbs.get_revolved_surface(e,r,2*Math.PI,i.knots,i.degree,i.control_points,i.weights)},verb.eval.nurbs.get_polyline_curve=function(e){for(var r=e.length-1,t=1/r,n=[0,0],i=1;r>i;i++)n.push(i*t);n.push(1),n.push(1);for(var s=[],i=0;e.length>i;i++)s.push(1);return{knots:n,control_points:e.slice(0),degree:1,weights:s}},verb.eval.nurbs.get_4pt_surface=function(e,r,t,n){return{knots_u:[0,0,1,1],knots_v:[0,0,1,1],control_points:[[e,n],[r,t]],degree_u:1,degree_v:1,weights:[[1,1],[1,1]]}},verb.eval.nurbs.get_cylinder_surface=function(e,r,t,n,i){var s=crossprod(e,r),a=(2*Math.PI,verb.eval.nurbs.get_arc(t,r,s,i,0,2*Math.PI));return verb.eval.nurbs.get_extruded_surface(e,n,a.knots,a.degree,a.control_points,a.weights)},verb.eval.nurbs.get_cone_surface=function(e,r,t,n,i){var s=2*Math.PI,a=1,o=[numeric.add(t,numeric.mul(n,e)),numeric.add(t,numeric.mul(i,r))],u=[0,0,1,1],v=[1,1];return verb.eval.nurbs.get_revolved_surface(t,e,s,u,a,o,v)},verb.eval.nurbs.get_extruded_surface=function(e,r,t,n,i,s){for(var a=verb.eval.nurbs.zeros_2d(3,i.length),o=verb.eval.nurbs.zeros_2d(3,i.length),u=numeric.mul(e,r),v=numeric.mul(e,.5*r),l=0;i.length>l;l++)a[0][l]=i[l],a[1][l]=numeric.add(v,i[l]),a[2][l]=numeric.add(u,i[l]),o[0][l]=s[l],o[1][l]=s[l],o[2][l]=s[l];return{knots_u:[0,0,0,1,1,1],knots_v:t,control_points:a,degree_u:2,degree_v:n,weights:o}},verb.eval.nurbs.get_revolved_surface=function(e,r,t,n,i,s,a){var o,u,v,l;Math.PI/2>=t?(o=1,u=verb.eval.nurbs.zeros_1d(6+2*(o-1))):Math.PI>=t?(o=2,u=verb.eval.nurbs.zeros_1d(6+2*(o-1)),u[3]=u[4]=.5):3*Math.PI/2>=t?(o=3,u=verb.eval.nurbs.zeros_1d(6+2*(o-1)),u[3]=u[4]=1/3,u[5]=u[6]=2/3):(o=4,u=verb.eval.nurbs.zeros_1d(6+2*(o-1)),u[3]=u[4]=.25,u[5]=u[6]=.5,u[7]=u[8]=.75);for(var c=t/o,b=3+2*(o-1),h=0;3>h;b++,h++)u[h]=0,u[b]=1;for(var g=Math.cos(c/2),_=0,m=verb.eval.nurbs.zeros_1d(o+1),f=verb.eval.nurbs.zeros_1d(o+1),v=verb.eval.nurbs.zeros_2d(2*o+1,s.length),l=verb.eval.nurbs.zeros_2d(2*o+1,s.length),h=1;o>=h;h++)_+=c,f[h]=Math.cos(_),m[h]=Math.sin(_);for(b=0;s.length>b;b++){var d=verb.eval.geom.closest_point_on_ray(s[b],e,r),p=numeric.sub(s[b],d),y=numeric.norm2(p),x=crossprod(r,p);y>verb.EPSILON&&(p=numeric.mul(1/y,p),x=numeric.mul(1/y,x)),v[0][b]=s[b];var N=s[b];l[0][b]=a[b];for(var k=x,w=0,_=0,h=1;o>=h;h++){var E=0==y?d:numeric.add(d,numeric.mul(y,f[h],p),numeric.mul(y,m[h],x));v[w+2][b]=E,l[w+2][b]=a[b];var A=numeric.sub(numeric.mul(f[h],x),numeric.mul(m[h],p));if(0==y)v[w+1][b]=d;else{var M=verb.eval.geom.intersect_rays(N,numeric.mul(1/numeric.norm2(k),k),E,numeric.mul(1/numeric.norm2(A),A)),z=numeric.add(N,numeric.mul(k,M[0]));v[w+1][b]=z}l[w+1][b]=g*a[b],w+=2,o>h&&(N=E,k=A)}}return{knots_u:u,knots_v:n,control_points:v,degree_u:2,degree_v:i,weights:l}},verb.eval.nurbs.get_arc=function(e,r,t,n,i,s){return verb.eval.nurbs.get_ellipse_arc(e,r,t,n,n,i,s)},verb.eval.nurbs.curve_knot_insert=function(e,r,t,n,i,s){var a=(t[0].length,r.length-e-2),o=t.length,u=verb.eval.nurbs.knot_span(e,n,r),v=a+e+1,l=o+s,c=Array(e+1),b=Array(r.length+s),h=Array(l),g=0;for(g=0;u>=g;g++)b[g]=r[g];for(g=1;s>=g;g++)b[u+g]=n;for(g=u+1;v>=g;g++)b[g+s]=r[g];for(g=0;u-e>=g;g++)h[g]=t[g];for(g=u-i;a>=g;g++)h[g+s]=t[g];for(g=0;e-i>=g;g++)c[g]=t[u-e+1];for(var _=0,m=0,f=1;s>=f;f++){for(_=u-e+f,g=0;e-f-i>=g;g++)m=(n-r[_+g])/(r[g+u+1]-r[_+g]),c[g]=numeric.add(numeric.mul(m,c[g+1]),numeric.mul(1-m,c[g]));h[_]=c[0],h[u+s-f-i]=c[e-f-i]}for(g=_+1;u-i>g;g++)h[g]=c[g-_];return[b,h]},verb.eval.nurbs.rational_surface_derivs=function(e,r,t,n,i,s,a,o){var u=verb.eval.nurbs.surface_derivs(e,r,t,n,i,s,a,o),v=verb.eval.nurbs.separate_homo_derivs_2d(u),l=v[0],c=v[1],b=0,h=0,g=0,_=0,m=[],f=l[0][0].length;for(b=0;s>=b;b++)for(m.push([]),_=0;s-b>=_;_++){var o=l[b][_];for(g=1;_>=g;g++)o=numeric.sub(o,numeric.mul(numeric.mul(binomial.get(_,g),c[0][g]),m[b][_-g]));for(h=1;b>=h;h++){o=numeric.sub(o,numeric.mul(numeric.mul(binomial.get(b,h),c[h][0]),m[b-h][_]));var d=verb.eval.nurbs.zeros_1d(f);for(g=1;_>=g;g++)d=numeric.add(d,numeric.mul(numeric.mul(binomial.get(_,g),c[h][g]),m[b-h][_-g]));o=numeric.sub(o,numeric.mul(binomial.get(b,h),d))}m[b].push(numeric.mul(1/c[0][0],o))}return m},verb.eval.nurbs.rational_surface_point=function(e,r,t,n,i,s,a){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.surface_point(e,r,t,n,i,s,a))},verb.eval.nurbs.rational_curve_derivs=function(e,r,t,n,i){var s=verb.eval.nurbs.separate_homo_derivs_1d(verb.eval.nurbs.curve_derivs(e,r,t,n,i)),a=s[0],o=s[1],u=0,v=0,l=[];for(u=0;i>=u;u++){var c=a[u];for(v=1;u>=v;v++)c=numeric.sub(c,numeric.mul(numeric.mul(binomial.get(u,v),o[v]),l[u-v]));l.push(numeric.mul(1/o[0],c))}return l},verb.eval.nurbs.separate_homo_derivs_1d=function(e){for(var r=e[0].length,t=r-1,n=[],i=[],s=0,a=e.length;a>s;s++)n.push(e[s].slice(0,t)),i.push(e[s][t]);return[n,i]},verb.eval.nurbs.separate_homo_derivs_2d=function(e){for(var r=[],t=[],n=0,i=e.length;i>n;n++){var s=verb.eval.nurbs.separate_homo_derivs_1d(e[n]);r.push(s[0]),t.push(s[1])}return[r,t]},verb.eval.nurbs.rational_curve_point=function(e,r,t,n){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.curve_point(e,r,t,n))},verb.eval.nurbs.dehomogenize=function(e){for(var r=e.length,t=[],n=e[r-1],i=0;e.length-1>i;i++)t.push(e[i]/n);return t},verb.eval.nurbs.homogenize_1d=function(e,r){for(var t=e.length,n=e[0].length,i=0,s=[],a=0,o=[],u=0;t>u;u++){var v=[];for(o=e[u],a=r[u],i=0;n>i;i++)v.push(o[i]*a);v.push(a),s.push(v)}return s},verb.eval.nurbs.homogenize_2d=function(e,r){for(var t=e.length,n=(e[0].length,e[0][0].length,[]),i=0;t>i;i++)n.push(verb.eval.nurbs.homogenize_1d(e[i],r[i]));return n},verb.eval.nurbs.rational_surface_curvature=function(e,r,t,n,i,s,a){var o=verb.eval.nurbs.rational_surface_derivs(e,r,t,n,i,2,s,a),u=o[0][1],v=o[1][0],l=o[0][2],c=o[2][0],b=o[1][1],h=numeric.cross(u,v),g=numeric.dot(l,h),_=numeric.dot(b,h),m=numeric.dot(c,h),f=[[g,_],[_,m]],d=numeric.eig(f),p=d.lambda.x[0],y=d.lambda.x[1],x=.5*(p+y),N=p*y,k=numeric.add(numeric.mul(d.E.x[0][0],u),numeric.mul(d.E.x[0][1],v)),w=numeric.add(numeric.mul(d.E.x[1][0],u),numeric.mul(d.E.x[1][1],v));return{point:o[0][0],normal:h,mean:x,gaussian:N,shapeOperator:f,k1:p,k2:y,p1:k,p2:w,p1p:d.E.x[0],p2p:d.E.x[1]}},verb.eval.nurbs.surface_derivs=function(e,r,t,n,i,s,a,o){var u=r.length-e-2,v=n.length-t-2;return verb.eval.nurbs.surface_derivs_given_n_m(u,e,r,v,t,n,i,s,a,o)},verb.eval.nurbs.surface_derivs_given_n_m=function(e,r,t,n,i,s,a,o,u,v){if(verb.eval.nurbs.are_valid_relations(r,a.length,t.length)===!1||verb.eval.nurbs.are_valid_relations(i,a[0].length,s.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var l=a[0][0].length,c=Math.min(o,r),b=Math.min(o,i),h=verb.eval.nurbs.zeros_3d(c+1,b+1,l),g=verb.eval.nurbs.knot_span_given_n(e,r,u,t),_=verb.eval.nurbs.knot_span_given_n(n,i,v,s),m=verb.eval.nurbs.deriv_basis_functions_given_n_i(g,u,r,e,t),f=verb.eval.nurbs.deriv_basis_functions_given_n_i(_,v,i,n,s),d=verb.eval.nurbs.zeros_2d(i+1,l),p=0,y=0,x=0,N=0,k=0;for(p=0;c>=p;p++){for(y=0;i>=y;y++)for(d[y]=verb.eval.nurbs.zeros_1d(l),x=0;r>=x;x++)d[y]=numeric.add(d[y],numeric.mul(m[p][x],a[g-r+x][_-i+y]));for(k=Math.min(o-p,b),N=0;k>=N;N++)for(h[p][N]=verb.eval.nurbs.zeros_1d(l),y=0;i>=y;y++)h[p][N]=numeric.add(h[p][N],numeric.mul(f[N][y],d[y]))}return h},verb.eval.nurbs.surface_point=function(e,r,t,n,i,s,a){var o=r.length-e-2,u=n.length-t-2;return verb.eval.nurbs.surface_point_given_n_m(o,e,r,u,t,n,i,s,a)},verb.eval.nurbs.volume_point=function(e,r,t,n,i,s,a,o,u,v){var l=r.length-e-2,c=n.length-t-2,b=s.length-i-2;return verb.eval.nurbs.volume_point_given_n_m_l(l,e,r,c,t,n,b,i,s,a,o,u,v)},verb.eval.nurbs.volume_point_given_n_m_l=function(e,r,t,n,i,s,a,o,u,v,l,c,b){if(!verb.eval.nurbs.are_valid_relations(r,v.length,t.length)||!verb.eval.nurbs.are_valid_relations(i,v[0].length,s.length)||!verb.eval.nurbs.are_valid_relations(o,v[0][0].length,u.length))return console.error("Invalid relations between control points and knot vector"),null;for(var h=v[0][0][0].length,g=verb.eval.nurbs.knot_span_given_n(e,r,l,t),_=verb.eval.nurbs.knot_span_given_n(n,i,c,s),m=verb.eval.nurbs.knot_span_given_n(a,o,b,u),f=verb.eval.nurbs.basis_functions_given_knot_span_index(g,l,r,t),d=verb.eval.nurbs.basis_functions_given_knot_span_index(_,c,i,s),p=verb.eval.nurbs.basis_functions_given_knot_span_index(m,b,o,u),y=g-r,x=_,N=m,k=verb.eval.nurbs.zeros_1d(h),w=verb.eval.nurbs.zeros_1d(h),E=verb.eval.nurbs.zeros_1d(h),A=0,M=0,z=0;o>=z;z++){for(E=verb.eval.nurbs.zeros_1d(h),N=m-o+z,A=0;i>=A;A++){for(w=verb.eval.nurbs.zeros_1d(h),x=_-i+A,M=0;r>=M;M++)w=numeric.add(w,numeric.mul(f[M],v[y+M][x][N]));E=numeric.add(E,numeric.mul(d[A],w))}k=numeric.add(k,numeric.mul(p[z],E))}return k},verb.eval.nurbs.surface_point_given_n_m=function(e,r,t,n,i,s,a,o,u){if(verb.eval.nurbs.are_valid_relations(r,a.length,t.length)===!1||verb.eval.nurbs.are_valid_relations(i,a[0].length,s.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var v=a[0][0].length,l=verb.eval.nurbs.knot_span_given_n(e,r,o,t),c=verb.eval.nurbs.knot_span_given_n(n,i,u,s),b=verb.eval.nurbs.basis_functions_given_knot_span_index(l,o,r,t),h=verb.eval.nurbs.basis_functions_given_knot_span_index(c,u,i,s),g=l-r,_=c,m=verb.eval.nurbs.zeros_1d(v),f=verb.eval.nurbs.zeros_1d(v),d=0,p=0;for(d=0;i>=d;d++){for(f=verb.eval.nurbs.zeros_1d(v),_=c-i+d,p=0;r>=p;p++)f=numeric.add(f,numeric.mul(b[p],a[g+p][_]));m=numeric.add(m,numeric.mul(h[d],f))}return m},verb.eval.nurbs.curve_derivs=function(e,r,t,n,i){var s=r.length-e-2;return verb.eval.nurbs.curve_derivs_given_n(s,e,r,t,n,i)},verb.eval.nurbs.curve_derivs_given_n=function(e,r,t,n,i,s){if(verb.eval.nurbs.are_valid_relations(r,n.length,t.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var a=n[0].length,o=Math.min(s,r),u=verb.eval.nurbs.zeros_2d(o+1,a),v=verb.eval.nurbs.knot_span_given_n(e,r,i,t),l=verb.eval.nurbs.deriv_basis_functions_given_n_i(v,i,r,o,t),c=0,b=0;for(c=0;o>=c;c++)for(b=0;r>=b;b++)u[c]=numeric.add(u[c],numeric.mul(l[c][b],n[v-r+b]));return u},verb.eval.nurbs.are_valid_relations=function(e,r,t){return 0===r+e+1-t?!0:!1},verb.eval.nurbs.curve_point=function(e,r,t,n){var i=r.length-e-2;return verb.eval.nurbs.curve_point_given_n(i,e,r,t,n)},verb.eval.nurbs.curve_point_given_n=function(e,r,t,n,i){if(verb.eval.nurbs.are_valid_relations(r,n.length,t.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;for(var s=verb.eval.nurbs.knot_span_given_n(e,r,i,t),a=verb.eval.nurbs.basis_functions_given_knot_span_index(s,i,r,t),o=verb.eval.nurbs.zeros_1d(n[0].length),u=0;r>=u;u++)o=numeric.add(o,numeric.mul(a[u],n[s-r+u]));return o},verb.eval.nurbs.zeros_1d=function(e){e=e>0?e:0;for(var r=[];e--;)r.push(0);return r},verb.eval.nurbs.zeros_2d=function(e,r){r=r>0?r:0,e=e>0?e:0;for(var t=[],n=r,i=e;e--;){for(t.push([]);n--;)t[i-e-1].push(0);n=r}return t},verb.eval.nurbs.zeros_3d=function(e,r,t){r=r>0?r:0,e=e>0?e:0;for(var n=[],i=r,s=e;e--;){for(n.push([]);i--;)n[s-e-1].push(verb.eval.nurbs.zeros_1d(t));i=r}return n},verb.eval.nurbs.deriv_basis_functions=function(e,r,t){var n=verb.eval.nurbs.knot_span(r,e,t),i=t.length-1,s=i-r-1;return verb.eval.nurbs.deriv_basis_functions_given_n_i(n,e,r,s,t)},verb.eval.nurbs.deriv_basis_functions_given_n_i=function(e,r,t,n,i){var s=verb.eval.nurbs.zeros_2d(t+1,t+1),a=Array(t+1),o=Array(t+1),u=0,v=0,l=1,c=0;for(s[0][0]=1,l=1;t>=l;l++){for(a[l]=r-i[e+1-l],o[l]=i[e+l]-r,u=0,c=0;l>c;c++)s[l][c]=o[c+1]+a[l-c],v=s[c][l-1]/s[l][c],s[c][l]=u+o[c+1]*v,u=a[l-c]*v;s[l][l]=u}var b=verb.eval.nurbs.zeros_2d(n+1,t+1),h=verb.eval.nurbs.zeros_2d(2,t+1),g=1,_=0,m=1,f=0,d=0,p=0,y=0,x=0;for(l=0;t>=l;l++)b[0][l]=s[l][t];for(c=0;t>=c;c++)for(_=0,m=1,h[0][0]=1,g=1;n>=g;g++){for(f=0,d=c-g,p=t-g,c>=g&&(h[m][0]=h[_][0]/s[p+1][d],f=h[m][0]*s[d][p]),y=d>=-1?1:-d,x=p>=c-1?g-1:t-c,l=y;x>=l;l++)h[m][l]=(h[_][l]-h[_][l-1])/s[p+1][d+l],f+=h[m][l]*s[d+l][p];p>=c&&(h[m][g]=-h[_][g-1]/s[p+1][c],f+=h[m][g]*s[c][p]),b[g][c]=f,l=_,_=m,m=l}for(c=t,g=1;n>=g;g++){for(l=0;t>=l;l++)b[g][l]*=c;c*=t-g}return b},verb.eval.nurbs.basis_functions=function(e,r,t){var n=verb.eval.nurbs.knot_span(e,r,t);return verb.eval.nurbs.basis_functions_given_knot_span_index(n,e,r,t)},verb.eval.nurbs.basis_functions_given_knot_span_index=function(e,r,t,n){var i=Array(t+1),s=Array(t+1),a=Array(t+1),o=0,u=0;i[0]=1;for(var v=1;t>=v;v++){s[v]=r-n[e+1-v],a[v]=n[e+v]-r,o=0;for(var l=0;v>l;l++)u=i[l]/(a[l+1]+s[v-l]),i[l]=o+a[l+1]*u,o=s[v-l]*u;i[v]=o}return i},verb.eval.nurbs.knot_span=function(e,r,t){var n=t.length-1,i=n-e-1;return verb.eval.nurbs.knot_span_given_n(i,e,r,t)},verb.eval.nurbs.knot_span_given_n=function(e,r,t,n){if(t>=n[e+1])return e;if(n[r]>t)return r;for(var i=r,s=e+1,a=Math.floor((i+s)/2);n[a]>t||t>=n[a+1];)n[a]>t?s=a:i=a,a=Math.floor((i+s)/2);return a};
View
254 build/verbEval.js
@@ -1494,7 +1494,7 @@ verb.eval.nurbs.divide_rational_surface_adaptive = function( degree_u, knots_u,
, v0 = min_v + v_interval * j
, v1 = min_v + v_interval * (j + 1);
- divs.push( new AdaptiveRefinementNode( srf, u0, u1, v0, v1, null, null ) );
+ divs.push( new verb.eval.nurbs.AdaptiveRefinementNode( srf, u0, u1, v0, v1, null, null ) );
}
}
@@ -1560,7 +1560,46 @@ verb.eval.nurbs.unique_mesh = function( mesh ) {
}
-function AdaptiveRefinementNode( srf, u0, u1, v0, v1, parentNode, neighbors ) {
+
+Array.prototype.where = function( predicate ){
+
+ if (this.length === 0) return this;
+
+ var res = [];
+
+ for (var i = 0; i < this.length; i++){
+ if ( predicate( this[i] ) ) res.push( this[i] );
+ }
+
+ return res;
+
+}
+
+verb.eval.nurbs.AdaptiveRefinementNode = function( srf, u0, u1, v0, v1, parentNode, neighbors ) {
+
+ //
+ // Structure of the child nodes
+ // in the adaptive refinement tree
+ //
+ // +--> u
+ // |
+ // v
+ // v
+ //
+ // neighbors[0]
+ //
+ // (u0,v0)---(u05,v0)---(u1,v0)
+ // | | |
+ // | 0 | 1 |
+ // | | |
+ // neighbors[3] (u0,v05)--(u05,v05)--(u1,v05) neighbors[1]
+ // | | |
+ // | 3 | 2 |
+ // | | |
+ // (u0,v1)---(u05,v1)---(u1,v1)
+ //
+ // neighbors[2]
+ //
this.srf = srf;
this.u0 = u0;
@@ -1574,11 +1613,12 @@ function AdaptiveRefinementNode( srf, u0, u1, v0, v1, parentNode, neighbors ) {
}
-AdaptiveRefinementNode.prototype.isLeaf = function(){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.isLeaf = function(){
return (this.children === undefined);
};
-AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
+
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
var derivs = verb.eval.nurbs.rational_surface_derivs( this.srf.degree_u,
this.srf.knots_u,
@@ -1598,54 +1638,43 @@ AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
};
-Array.prototype.where = function( predicate ){
-
- if (length === 0) return this;
- var res = [];
-
- for (var i = 0; i < this.length; i++){
- if ( predicate( this[i] ) ) res.push( res[i] );
- }
-
- return res;
-
-}
-
-AdaptiveRefinementNode.prototype.getEdgeUvs = function( edgeIndex ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.getEdgeUvs = function( edgeIndex ){
// if its a leaf, there are no children to obtain uvs from
- if ( this.isLeaf() ) return this.leafEdgeUvs[ edgeIndex ];
+ if ( this.isLeaf() ) return [ this.leafEdgeUvs[ edgeIndex ] ]
// get the uvs owned by the children along this edge
this.cachedEdgeUvs[edgeIndex] = this.cachedEdgeUvs[edgeIndex] || this.children[ edgeIndex ].getEdgeUvs( edgeIndex )
.concat( this.children[ (edgeIndex + 1) % 4 ].getEdgeUvs( edgeIndex ));
return this.cachedEdgeUvs[edgeIndex];
};
-AdaptiveRefinementNode.prototype.getAllEdgeUvs = function( edgeIndex ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.getAllEdgeUvs = function( edgeIndex ){
- var baseArr = [ leafEdgeUvs[edgeIndex] ];
+ var baseArr = [ this.leafEdgeUvs[edgeIndex] ];
- if (this.neighbors[edgeIndex] === null) return baseArr;
+ if ( this.neighbors[edgeIndex] === null ) return baseArr;
// get opposite edges uvs
var uvs = this.neighbors[edgeIndex].getEdgeUvs( ( edgeIndex + 2 ) % 4 );
var funcIndex = edgeIndex % 2;
+ var that = this;
+
// range clipping functions
var rangeFuncMap = [
- function(x){ return x[0] > u0 + verb.EPSILON && x[0] < u1 - verb.EPSILON; },
- function(x){ return x[1] > v0 + verb.EPSILON && x[1] < v1 - verb.EPSILON; }
+ function(x){ return x[0] > that.u0 + verb.EPSILON && x[0] < that.u1 - verb.EPSILON; },
+ function(x){ return x[1] > that.v0 + verb.EPSILON && x[1] < that.v1 - verb.EPSILON; }
];
// clip the range of uvs to match this one
- return baseArr.concat( uvs.slice(0).reverse().where( rangeFuncMap[ funcIndex ] ) ) ;
+ return baseArr.concat( uvs.where( rangeFuncMap[ funcIndex ] ).reverse() ) ;
};
-AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
var baseIndex = mesh.points.length - 1;
@@ -1682,7 +1711,7 @@ AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
// make point at center of face
mesh.uvs.push( [ this.u05, this.v05 ] );
- var center = this.evalSurface( this.u05, this.v05 );
+ var center = this.evalSurface( [ this.u05, this.v05 ] );
mesh.points.push( center.point );
mesh.normals.push( center.normal );
@@ -1700,7 +1729,7 @@ AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
};
-AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
if ( this.isLeaf() ) return this.triangulateLeaf( mesh );
@@ -1712,44 +1741,37 @@ AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
};
-AdaptiveRefinementNode.prototype.divide = function( options ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.shouldDivide = function( options, currentDepth ){
- //
- // Structure of the child nodes
- // in the adaptive refinement tree
- //
- // +--> u
- // |
- // v
- // v
- //
- // neighbors[0]
- //
- // (u0,v0)---(u05,v0)---(u1,v0)
- // | | |
- // | 0 | 1 |
- // | | |
- // neighbors[3] (u0,v05)--(u05,v05)--(u1,v05) neighbors[1]
- // | | |
- // | 3 | 2 |
- // | | |
- // (u0,v1)---(u05,v1)---(u1,v1)
- //
- // neighbors[2]
- //
+ if ( ( options.minDepth && currentDepth < options.minDepth ) ){
+ return true;
+ } else if ( this.srf && !verb.eval.nurbs.is_rational_surface_domain_flat( this.srf, this.u0, this.u1, this.v0, this.v1, options ) ){
+ return true;
+ }
- if ( verb.eval.nurbs.is_rational_surface_domain_flat( this.srf, this.u0, this.u1, this.v0, this.v1, options ) )
- return;
+ return false;
- // divide the domain
+}
+
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.divide = function( options, currentDepth ){
+
+ // initialize currentDepth if it's not present
+ if (currentDepth === undefined) currentDepth = 0;
+
+ if ( !this.shouldDivide( options, currentDepth ) ) return;
+ // increment the depth
+ currentDepth++;
+
+ // divide the domain
this.u05 = (this.u0 + this.u1) / 2;
this.v05 = (this.v0 + this.v1) / 2;
- this.children = [ new AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v0, this.v05, this ),
- new AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v0, this.v05, this ),
- new AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v05, this.v1, this ),
- new AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v05, this.v1, this ) ];
+ // create the children
+ this.children = [ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v0, this.v05, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v0, this.v05, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v05, this.v1, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v05, this.v1, this ) ];
// correctly assign neighbors
this.children[0].neighbors = [ this.neighbors[0], this.children[1], this.children[3], this.neighbors[3] ];
@@ -1758,7 +1780,7 @@ AdaptiveRefinementNode.prototype.divide = function( options ){
this.children[3].neighbors = [ this.children[0], this.children[2], this.neighbors[2], this.neighbors[3] ];
// divide all children recursively
- this.children.forEach(function(x){ x.divide( options ); });
+ this.children.forEach(function(x){ x.divide( options,currentDepth ); })
};
@@ -2080,28 +2102,28 @@ verb.eval.nurbs.get_cone_surface = function( axis, xaxis, base, height, radius )
verb.eval.nurbs.get_extruded_surface = function( axis, length, prof_knots, prof_degree, prof_control_points, prof_weights){
- var control_points = verb.eval.nurbs.zeros_2d( 2, prof_control_points.length )
- , weights = verb.eval.nurbs.zeros_2d( 2, prof_control_points.length );
+ var control_points = verb.eval.nurbs.zeros_2d( 3, prof_control_points.length )
+ , weights = verb.eval.nurbs.zeros_2d( 3, prof_control_points.length );
+
+ var translation = numeric.mul(axis, length);
+ var halfTranslation = numeric.mul(axis, 0.5 * length);
// original control points
for (var j = 0; j < prof_control_points.length; j++){
control_points[0][j] = prof_control_points[j];
- weights[0][j] = prof_weights[j];
- }
-
- // build translated control points
- var translation = numeric.mul(axis, length);
+ control_points[1][j] = numeric.add( halfTranslation, prof_control_points[j] );
+ control_points[2][j] = numeric.add( translation, prof_control_points[j] );
- for (var j = 0; j < prof_control_points.length; j++){
- control_points[1][j] = numeric.add( translation, prof_control_points[j] );
+ weights[0][j] = prof_weights[j];
weights[1][j] = prof_weights[j];
+ weights[2][j] = prof_weights[j];
}
// return all parameters
- return {"knots_u": [0,0,1,1],
+ return {"knots_u": [0,0,0,1,1,1],
"knots_v": prof_knots,
"control_points": control_points,
- "degree_u": 1,
+ "degree_u": 2,
"degree_v": prof_degree,
"weights": weights };
}
@@ -2285,6 +2307,96 @@ verb.eval.nurbs.get_arc = function( center, xaxis, yaxis, radius, start_angle, e
+//
+// ####surface_curvature( degree_u, knots_u, degree_v, knots_v, control_points, u, v, options )
+//
+// Compute the gaussian curvature on a non-uniform, non-rational B spline surface
+//
+// **params**
+// + *Number*, integer degree of surface in u direction
+// + *Array*, array of nondecreasing knot values in u direction
+// + *Number*, integer degree of surface in v direction
+// + *Array*, array of nondecreasing knot values in v direction
+// + *Array*, 3d array of control points, where rows are the u dir, and columns run alonsg the positive v direction,
+// and where each control point is an array of length (dim)
+// + *Number*, u parameter at which to evaluate the derivatives
+// + *Number*, v parameter at which to evaluate the derivatives
+//
+// **returns**
+// + *Array*, a point represented by an array of length (dim)
+//
+
+verb.eval.nurbs.rational_surface_curvature = function( degree_u, knots_u, degree_v, knots_v, homo_control_points, u, v ) {
+
+ // compute the first fundamental form
+
+ // symmetric matrix where
+ //
+ // I = [ E F; F G ]
+ //
+ // where:
+ //
+ // E = Xu * Xu
+ // F = Xu * Xv
+ // G = Xv * Xv
+
+ // second fundamental form (shape operator)
+
+ // symmetric matrix where
+ //
+ // II = [ L M; M N ]
+ //
+ // where:
+ //
+ // L = Xuu * n
+ // M = Xuv * n
+ // N = Xvv * n
+
+ // principal curvatures are the eigenvalues of the second fundamental form
+
+ var derivs = verb.eval.nurbs.rational_surface_derivs( degree_u,
+ knots_u,
+ degree_v,
+ knots_v,
+ homo_control_points,
+ 2, u, v );
+
+ // structure of the derivatives
+
+ // pos du vuu
+ // dv duv
+ // dvv
+
+
+ var du = derivs[0][1];
+ var dv = derivs[1][0];
+ var duu = derivs[0][2];
+ var dvv = derivs[2][0];
+ var duv = derivs[1][1];
+
+ var n = numeric.cross( du, dv );
+ var L = numeric.dot( duu, n );
+ var M = numeric.dot( duv, n );
+ var N = numeric.dot( dvv, n );
+
+ var shapeOperator = [ [ L, M ], [ M, N ] ];
+
+ var eigs = numeric.eig( shapeOperator );
+
+ // contains: lambda - x
+ // E - x
+
+ var k1 = eigs.lambda.x[0];
+ var k2 = eigs.lambda.x[1];
+ var mean = 0.5 * ( k1 + k2 );
+ var gaussian = k1 * k2;
+ var p1 = numeric.add( numeric.mul( eigs.E.x[0][0], du ), numeric.mul( eigs.E.x[0][1], dv ) );
+ var p2 = numeric.add( numeric.mul( eigs.E.x[1][0], du ), numeric.mul( eigs.E.x[1][1], dv ) );
+
+ return { point: derivs[0][0], normal: n, mean: mean, gaussian: gaussian, shapeOperator: shapeOperator, k1: k1, k2: k2, p1: p1, p2: p2, p1p : eigs.E.x[0], p2p: eigs.E.x[1] };
+
+};
+
//
// ####curve_knot_insert( degree, knots, control_points, u, s, r )
View
5 build/verbEval.min.js
@@ -1,2 +1,3 @@
-/*! verb 2014-01-21 */
-function crossprod(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]}if("object"!=typeof exports||void 0===exports)importScripts("labor.js"),importScripts("binomial.js"),importScripts("numeric-1.2.6.min.js");else var labor=require("labor");var verb=verb||{};verb.eval=verb.eval||{},verb.eval.nurbs=verb.eval.nurbs||{},verb.eval.mesh=verb.eval.mesh||{},verb.eval.geom=verb.eval.geom||{},verb.geom=verb.geom||{},verb.EPSILON=1e-8,verb.TOLERANCE=.001;var router=new labor.Router(verb.eval.nurbs);numeric.normalized=function(e){return numeric.div(e,numeric.norm2(e))},numeric.cross=function(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]},verb.left=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(0,r)},verb.right=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r)},verb.rightWithPivot=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r-1)},verb.unique=function(e,r){if(0===e.length)return[];for(var n=[e.pop()],t=0;e.length>t;t++){for(var i=e.pop(),a=!0,s=0;n.length>s;s++)if(r(i,n[t])){a=!1;break}a&&n.push(i)}return n},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb_refine=function(e,r,n,t,i,a,s,u,o,v,l,b){var c=verb.eval.nurbs.intersect_rational_curve_surface_by_aabb(e,r,n,t,i,a,s,u,o,v,l,b);return c.map(function(o){var v=[o.p,o.uv[0],o.uv[1]],l=verb.eval.nurbs.refine_rational_curve_surface_intersection(e,r,n,t,i,a,s,u,v);return o.p=l[0],o.uv[0]=l[1],o.uv[1]=l[2],o.distance=l[3],delete o.face,o})},verb.eval.nurbs.refine_rational_curve_surface_intersection=function(e,r,n,t,i,a,s,u,o){var v=function(o){var v=verb.eval.nurbs.rational_curve_point(a,s,u,o[0]),l=verb.eval.nurbs.rational_surface_point(e,r,n,t,i,o[1],o[2]),b=numeric.sub(v,l);return numeric.dot(b,b)},l=numeric.uncmin(v,o);return l.solution.concat(l.f)},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb=function(e,r,n,t,i,a,s,u,o,v,l,b){var c=verb.eval.nurbs.rational_curve_adaptive_sample(a,s,u,o,!0),_=verb.eval.nurbs.tesselate_rational_surface_naive(e,r,n,t,i,l,b),h=c.map(function(e){return e[0]}),m=c.map(function(e){return e.slice(1)}),g=verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(m,h,_,verb.range(_.faces.length),v);return verb.unique(g,function(e,r){return v>numeric.norm2(numeric.sub(e.point,r.point))&&v>Math.abs(e.p-r.p)&&v>numeric.norm2(numeric.sub(e.uv,r.uv))})},verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb=function(e,r,n,t,i){var a=new verb.geom.BoundingBox(e),s=verb.eval.mesh.make_mesh_aabb(n.points,n.faces,t);if(!a.intersects(s,i))return[];if(2!==e.length||1!==t.length){if(1===t.length){var u=verb.left(e),o=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,v,n,t,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,l,n,t,i))}if(2===e.length){var b=verb.eval.mesh.sort_tris_on_longest_axis(s,n.points,n.faces,t),c=verb.left(b),_=verb.right(b);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,n,c,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,n,_,i))}var b=verb.eval.mesh.sort_tris_on_longest_axis(s,n.points,n.faces,t),c=verb.left(b),_=verb.right(b),u=verb.left(e),o=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,v,n,c,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,v,n,_,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,l,n,c,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,l,n,_,i))}var h=verb.eval.geom.intersect_segment_with_tri(e[0],e[1],n.points,n.faces[t[0]]);if(null!=h){var m=h.p*(r[1]-r[0])+r[0],g=n.faces[t][0],f=n.faces[t][1],d=n.faces[t][2],p=n.uvs[g],y=n.uvs[f],x=n.uvs[d],k=numeric.sub(y,p),M=numeric.sub(x,p),z=numeric.add(p,numeric.mul(h.s,k),numeric.mul(h.t,M));return[{point:h.point,p:m,uv:z,face:t[0]}]}return[]},verb.eval.geom.intersect_segment_with_tri=function(e,r,n,t){var i=n[t[0]],a=n[t[1]],s=n[t[2]],u=numeric.sub(a,i),o=numeric.sub(s,i),v=numeric.cross(u,o),l=numeric.sub(r,e),b=numeric.sub(e,i),c=-numeric.dot(v,b),_=numeric.dot(v,l);if(Math.abs(_)<verb.EPSILON)return null;var h=c/_;if(0>h||h>1)return null;var m=numeric.add(e,numeric.mul(h,l)),g=numeric.dot(u,o),f=numeric.dot(u,u),d=numeric.dot(o,o),p=numeric.sub(m,i),y=numeric.dot(p,u),x=numeric.dot(p,o),k=g*g-f*d,M=(g*x-d*y)/k,z=(g*y-f*x)/k;return M>1+verb.EPSILON||z>1+verb.EPSILON||-verb.EPSILON>z||-verb.EPSILON>M||M+z>1+verb.EPSILON?null:{point:m,s:M,t:z,p:h}},verb.eval.geom.intersect_segment_with_plane=function(e,r,n,t){var i=numeric.dot(t,numeric.sub(e,r));if(EPSILON>abs(i))return null;var a=numeric.dot(t,numeric.sub(n,e));return{p:a/i}},verb.eval.geom.intersect_aabb_trees=function(e,r,n,t,i,a){var s=i.bounding_box.intersects(a.bounding_box);return s?0===i.children.length&&0===a.children.length?[[i.triangle,a.triangle]]:0===i.children.length&&0!=a.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i,a.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i,a.children[1])):0!=i.children.length&&0===a.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],a).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],a)):0!=i.children.length&&0!=a.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],a.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],a.children[1])).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],a.children[0])).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],a.children[1])):void 0:[]},verb.eval.mesh.make_mesh_aabb_tree=function(e,r,n){var t={bounding_box:verb.eval.mesh.make_mesh_aabb(e,r,n),children:[]};if(1===n.length)return t.triangle=n[0],t;var i=verb.eval.mesh.sort_tris_on_longest_axis(t.bounding_box,e,r,n),a=i.slice(0,Math.floor(i.length/2)),s=i.slice(Math.floor(i.length/2),i.length);return t.children=[verb.eval.mesh.make_mesh_aabb_tree(e,r,a),verb.eval.mesh.make_mesh_aabb_tree(e,r,s)],t},verb.eval.mesh.make_mesh_aabb=function(e,r,n){var t=new verb.geom.BoundingBox;return n.forEach(function(n){t.add(e[r[n][0]]),t.add(e[r[n][1]]),t.add(e[r[n][2]])}),t},verb.eval.mesh.sort_tris_on_longest_axis=function(e,r,n,t){for(var i=e.get_longest_axis(),a=[],s=t.length-1;s>=0;s--){var u=t[s],o=verb.eval.mesh.get_min_coordinate_on_axis(r,n[u],i);a.push([o,u])}a.sort(function(e,r){return e[0]>r[0]});for(var v=[],s=0,l=a.length;l>s;s++)v.push(a[s][1]);return v},verb.eval.mesh.get_min_coordinate_on_axis=function(e,r,n){for(var t=[],i=0;3>i;i++)t.push(e[r[i]][n]);return Math.min.apply(Math,t)},verb.eval.geom.get_tri_centroid=function(e,r){for(var n=[0,0,0],t=0;3>t;t++)for(var i=0;3>i;i++)n[i]+=e[r[t]][i];for(var t=0;3>t;t++)n[t]/=3;return n},verb.eval.geom.get_tri_norm=function(e,r){var n=e[r[0]],t=e[r[1]],i=e[r[2]],a=numeric.sub(t,n),s=numeric.sub(i,n),u=numeric.cross(a,s);return numeric.mul(1/numeric.norm2(u),u)},verb.eval.nurbs.intersect_rational_curves_by_aabb_refine=function(e,r,n,t,i,a,s,u){var o=verb.eval.nurbs.intersect_rational_curves_by_aabb(e,r,n,t,i,a,s,u);return o.map(function(s){return verb.eval.nurbs.refine_rational_curve_intersection(e,r,n,t,i,a,s)})},verb.eval.nurbs.refine_rational_curve_intersection=function(e,r,n,t,i,a,s){var u=function(s){var u=verb.eval.nurbs.rational_curve_point(e,r,n,s[0]),o=verb.eval.nurbs.rational_curve_point(t,i,a,s[1]),v=numeric.sub(u,o);return numeric.dot(v,v)},o=numeric.uncmin(u,s);return o.solution.concat(o.f)},verb.eval.nurbs.intersect_rational_curves_by_aabb=function(e,r,n,t,i,a,s,u){var o=verb.eval.nurbs.rational_curve_adaptive_sample(e,r,n,s,!0),v=verb.eval.nurbs.rational_curve_adaptive_sample(t,i,a,s,!0),l=o.map(function(e){return e[0]}),b=v.map(function(e){return e[0]}),c=o.map(function(e){return e.slice(1)}),_=v.map(function(e){return e.slice(1)});return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(c,_,l,b,u)},verb.eval.nurbs.intersect_parametric_polylines_by_aabb=function(e,r,n,t,i){var a=new verb.geom.BoundingBox(e),s=new verb.geom.BoundingBox(r);if(!a.intersects(s,i))return[];if(2!==e.length||2!==r.length){if(2===e.length){var u=Math.ceil(r.length/2),o=r.slice(0,u),v=r.slice(u-1),l=t.slice(0,u),b=t.slice(u-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,o,n,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,v,n,b,i))}if(2===r.length){var c=Math.ceil(e.length/2),_=e.slice(0,c),h=e.slice(c-1),m=n.slice(0,c),g=n.slice(c-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,r,m,t,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,r,g,t,i))}var c=Math.ceil(e.length/2),_=e.slice(0,c),h=e.slice(c-1),m=n.slice(0,c),g=n.slice(c-1),u=Math.ceil(r.length/2),o=r.slice(0,u),v=r.slice(u-1),l=t.slice(0,u),b=t.slice(u-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,o,m,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,v,m,b,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,o,g,l,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,v,g,b,i))}var f=verb.eval.geom.intersect_segments(e[0],e[1],r[0],r[1],i);return null!=f?(f[0][0]=f[0][0]*(n[1]-n[0])+n[0],f[1][0]=f[1][0]*(t[1]-t[0])+t[0],[[f[0][0],f[1][0]]]):[]},verb.eval.geom.intersect_segments=function(e,r,n,t,i){var a=numeric.sub(r,e),s=Math.sqrt(numeric.dot(a,a)),u=numeric.mul(1/s,a),o=numeric.sub(t,n),v=Math.sqrt(numeric.dot(o,o)),l=numeric.mul(1/v,o),b=verb.eval.geom.intersect_rays(e,u,n,l);if(null!=b){var c=Math.min(Math.max(0,b[0]/s),1),_=Math.min(Math.max(0,b[1]/v),1),h=numeric.add(numeric.mul(c,a),e),m=numeric.add(numeric.mul(_,o),n),g=numeric.norm2Squared(numeric.sub(h,m));if(i*i>g)return[[c].concat(h),[_].concat(m)]}return null},verb.eval.geom.closest_point_on_ray=function(e,r,n){var t=numeric.sub(e,r),i=numeric.dot(t,n),a=numeric.add(r,numeric.mul(i,n));return a},verb.eval.geom.intersect_rays=function(e,r,n,t){var i=numeric.dot(r,t),a=numeric.dot(r,n),s=numeric.dot(r,e),u=numeric.dot(t,n),o=numeric.dot(t,e),v=numeric.dot(r,r),l=numeric.dot(t,t),b=v*l-i*i;if(Math.abs(b)<verb.EPSILON)return null;var c=i*(a-s)-v*(u-o),_=c/b,h=(a-s+_*i)/v;return[h,_]},verb.eval.mesh.intersect_meshes_by_aabb=function(e,r,n,t,i){var a=verb.range(r.length),s=verb.range(i.length),u=verb.eval.mesh.make_mesh_aabb_tree(e,r,a),o=verb.eval.mesh.make_mesh_aabb_tree(t,i,s);verb.eval.mesh.intersect_aabb_tree(e,r,t,i,u,o)},verb.eval.geom.intersect_tris=function(e,r,n,t,i){for(var a=[e[tr1[0]],e[tr1[1]]],s=[e[tr1[1]],e[tr1[2]]],u=[e[tr1[2]],e[tr1[0]]],o=[t[tr2[0]],t[tr2[1]]],v=[t[tr2[1]],t[tr2[2]]],l=[t[tr2[2]],t[tr2[0]]],b=[a,s,u],c=[o,v,l],_=[],h=verb.eval.geom.get_tri_norm(t,i),m=t[tr2[0]],g=0;3>g;g++){var f=verb.eval.geom.intersect_segment_with_plane(b[g][0],c[g][1],m,h);f.intersects&&_.push(f)}if(2!==_.length)return null;for(var d=[_[0].point,_[1].point],p=[],g=0;3>g;g++){var y=verb.eval.geom.intersect_segments(d[0],d[1],d,b1,tol);y&&p.push(y)}0===p.length||1===p.length||2===p.length},verb.eval.nurbs.tesselate_rational_surface_naive=function(e,r,n,t,i,a,s){1>a&&(a=1),1>s&&(s=1);for(var u=1/a,o=1/s,v=[],l=[],b=[],c=0;a+1>c;c++)for(var _=0;s+1>_;_++){var h=c*u,m=_*o;l.push([h,m]);var g=verb.eval.nurbs.rational_surface_derivs(e,r,n,t,i,1,h,m),f=g[0][0];v.push(f);var d=numeric.cross(g[0][1],g[1][0]);b.push(d)}for(var p=[],c=0;a>c;c++)for(var _=0;s>_;_++){var y=c*(s+1)+_,x=(c+1)*(s+1)+_,k=x+1,M=y+1,z=[y,x,k],w=[y,k,M];p.push(z),p.push(w)}return{points:v,faces:p,uvs:l,normals:b}},verb.eval.nurbs.rational_curve_regular_sample=function(e,r,n,t,i){return verb.eval.nurbs.rational_curve_regular_sample_range(e,r,n,0,1,t,i)},verb.eval.nurbs.rational_curve_regular_sample_range=function(e,r,n,t,i,a,s){1>a&&(a=2);for(var u=[],o=(i-t)/(a-1),v=0,l=0;a>l;l++)v=t+o*l,s?u.push([v].concat(verb.eval.nurbs.rational_curve_point(e,r,n,v))):u.push(verb.eval.nurbs.rational_curve_point(e,r,n,v));return u},verb.eval.nurbs.rational_curve_adaptive_sample=function(e,r,n,t,i){return 1===e?i?n.map(function(e,n){return[r[n+1]].concat(verb.eval.nurbs.dehomogenize(e))}):n.map(verb.eval.nurbs.dehomogenize):verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,0,1,t,i)},verb.eval.nurbs.rational_curve_adaptive_sample_range=function(e,r,n,t,i,a,s){var u=verb.eval.nurbs.rational_curve_point(e,r,n,t),o=verb.eval.nurbs.rational_curve_point(e,r,n,i),v=.5+.2*Math.random(),l=t+(i-t)*v,b=verb.eval.nurbs.rational_curve_point(e,r,n,l),c=numeric.sub(u,o),_=numeric.sub(u,b);if(a>numeric.dot(c,c)&&numeric.dot(_,_)>a||!verb.eval.nurbs.three_points_are_flat(u,b,o,a)){var h=t+.5*(i-t),m=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,t,h,a,s),g=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,h,i,a,s);return m.slice(0,-1).concat(g)}return s?[[t].concat(u),[i].concat(o)]:[u,o]},verb.eval.nurbs.three_points_are_flat=function(e,r,n,t){var i=numeric.sub(r,e),a=numeric.sub(n,e),s=crossprod(i,a),u=numeric.dot(s,s);return t>u},verb.eval.nurbs.get_sweep1_surface=function(e,r,n,t,i,a,s,u){for(var o=verb.eval.nurbs.homogenize_1d(s,u),v=verb.eval.nurbs.rational_curve_point(a,i,o,0),l=1/s.length,b=[],c=[],_=0;s.length>_;_++){for(var h=verb.eval.nurbs.rational_curve_point(a,i,o,_*l),m=numeric.sub(h,v),g=[],f=[],d=0;n.length>d;d++)g.push(numeric.add(m,n[d])),f.push(t[d]*u[_]);b.push(g),c.push(f)}return{knots_u:i,knots_v:e,control_points:b,degree_u:a,degree_v:r,weights:c}},verb.eval.nurbs.get_ellipse_arc=function(e,r,n,t,i,a,s){a>s&&(s=2*Math.PI+a);var u=s-a,o=0;o=Math.PI/2>=u?1:Math.PI>=u?2:3*Math.PI/2>=u?3:4;var v=u/o,l=Math.cos(v/2),b=numeric.add(e,numeric.mul(t,Math.cos(a),r),numeric.mul(i,Math.sin(a),n)),c=numeric.sub(numeric.mul(Math.cos(a),n),numeric.mul(Math.sin(a),r)),_=verb.eval.nurbs.zeros_1d(2*o),h=verb.eval.nurbs.zeros_1d(2*o+3),m=0,g=a,f=verb.eval.nurbs.zeros_1d(2*o);_[0]=b,f[0]=1;for(var d=1;o>=d;d++){g+=v;var p=numeric.add(e,numeric.mul(t,Math.cos(g),r),numeric.mul(i,Math.sin(g),n));f[m+2]=1,_[m+2]=p;var y=numeric.sub(numeric.mul(Math.cos(g),n),numeric.mul(Math.sin(g),r)),x=verb.eval.geom.intersect_rays(b,numeric.mul(1/numeric.norm2(c),c),p,numeric.mul(1/numeric.norm2(y),y)),k=numeric.add(b,numeric.mul(c,x[0]));f[m+1]=l,_[m+1]=k,m+=2,o>d&&(b=p,c=y)}for(var M=2*o+1,d=0;3>d;d++)h[d]=0,h[d+M]=1;switch(o){case 1:break;case 2:h[3]=h[4]=.5;break;case 3:h[3]=h[4]=1/3,h[5]=h[6]=2/3;break;case 4:h[3]=h[4]=.25,h[5]=h[6]=.5,h[7]=h[8]=.75}return{knots:h,control_points:_,degree:2,weights:f}},verb.eval.nurbs.get_sphere_surface=function(e,r,n,t){var i=verb.eval.nurbs.get_arc(e,numeric.mul(r,-1),n,t,0,Math.PI);return verb.eval.nurbs.get_revolved_surface(e,r,2*Math.PI,i.knots,i.degree,i.control_points,i.weights)},verb.eval.nurbs.get_polyline_curve=function(e){for(var r=e.length-1,n=1/r,t=[0,0],i=1;r>i;i++)t.push(i*n);t.push(1),t.push(1);for(var a=[],i=0;e.length>i;i++)a.push(1);return{knots:t,control_points:e.slice(0),degree:1,weights:a}},verb.eval.nurbs.get_4pt_surface=function(e,r,n,t){return{knots_u:[0,0,1,1],knots_v:[0,0,1,1],control_points:[[e,t],[r,n]],degree_u:1,degree_v:1,weights:[[1,1],[1,1]]}},verb.eval.nurbs.get_cylinder_surface=function(e,r,n,t,i){var a=crossprod(e,r),s=(2*Math.PI,verb.eval.nurbs.get_arc(n,r,a,i,0,2*Math.PI));return verb.eval.nurbs.get_extruded_surface(e,t,s.knots,s.degree,s.control_points,s.weights)},verb.eval.nurbs.get_cone_surface=function(e,r,n,t,i){var a=2*Math.PI,s=1,u=[numeric.add(n,numeric.mul(t,e)),numeric.add(n,numeric.mul(i,r))],o=[0,0,1,1],v=[1,1];return verb.eval.nurbs.get_revolved_surface(n,e,a,o,s,u,v)},verb.eval.nurbs.get_extruded_surface=function(e,r,n,t,i,a){for(var s=verb.eval.nurbs.zeros_2d(2,i.length),u=verb.eval.nurbs.zeros_2d(2,i.length),o=0;i.length>o;o++)s[0][o]=i[o],u[0][o]=a[o];for(var v=numeric.mul(e,r),o=0;i.length>o;o++)s[1][o]=numeric.add(v,i[o]),u[1][o]=a[o];return{knots_u:[0,0,1,1],knots_v:n,control_points:s,degree_u:1,degree_v:t,weights:u}},verb.eval.nurbs.get_revolved_surface=function(e,r,n,t,i,a,s){var u,o,v,l;Math.PI/2>=n?(u=1,o=verb.eval.nurbs.zeros_1d(6+2*(u-1))):Math.PI>=n?(u=2,o=verb.eval.nurbs.zeros_1d(6+2*(u-1)),o[3]=o[4]=.5):3*Math.PI/2>=n?(u=3,o=verb.eval.nurbs.zeros_1d(6+2*(u-1)),o[3]=o[4]=1/3,o[5]=o[6]=2/3):(u=4,o=verb.eval.nurbs.zeros_1d(6+2*(u-1)),o[3]=o[4]=.25,o[5]=o[6]=.5,o[7]=o[8]=.75);for(var b=n/u,c=3+2*(u-1),_=0;3>_;c++,_++)o[_]=0,o[c]=1;for(var h=Math.cos(b/2),m=0,g=verb.eval.nurbs.zeros_1d(u+1),f=verb.eval.nurbs.zeros_1d(u+1),v=verb.eval.nurbs.zeros_2d(2*u+1,a.length),l=verb.eval.nurbs.zeros_2d(2*u+1,a.length),_=1;u>=_;_++)m+=b,f[_]=Math.cos(m),g[_]=Math.sin(m);for(c=0;a.length>c;c++){var d=verb.eval.geom.closest_point_on_ray(a[c],e,r),p=numeric.sub(a[c],d),y=numeric.norm2(p),x=crossprod(r,p);y>verb.EPSILON&&(p=numeric.mul(1/y,p),x=numeric.mul(1/y,x)),v[0][c]=a[c];var k=a[c];l[0][c]=s[c];for(var M=x,z=0,m=0,_=1;u>=_;_++){var w=0==y?d:numeric.add(d,numeric.mul(y,f[_],p),numeric.mul(y,g[_],x));v[z+2][c]=w,l[z+2][c]=s[c];var N=numeric.sub(numeric.mul(f[_],x),numeric.mul(g[_],p));if(0==y)v[z+1][c]=d;else{var P=verb.eval.geom.intersect_rays(k,numeric.mul(1/numeric.norm2(M),M),w,numeric.mul(1/numeric.norm2(N),N)),E=numeric.add(k,numeric.mul(M,P[0]));v[z+1][c]=E}l[z+1][c]=h*s[c],z+=2,u>_&&(k=w,M=N)}}return{knots_u:o,knots_v:t,control_points:v,degree_u:2,degree_v:i,weights:l}},verb.eval.nurbs.get_arc=function(e,r,n,t,i,a){return verb.eval.nurbs.get_ellipse_arc(e,r,n,t,t,i,a)},verb.eval.nurbs.curve_knot_insert=function(e,r,n,t,i,a){var s=(n[0].length,r.length-e-2),u=n.length,o=verb.eval.nurbs.knot_span(e,t,r),v=s+e+1,l=u+a,b=Array(e+1),c=Array(r.length+a),_=Array(l),h=0;for(h=0;o>=h;h++)c[h]=r[h];for(h=1;a>=h;h++)c[o+h]=t;for(h=o+1;v>=h;h++)c[h+a]=r[h];for(h=0;o-e>=h;h++)_[h]=n[h];for(h=o-i;s>=h;h++)_[h+a]=n[h];for(h=0;e-i>=h;h++)b[h]=n[o-e+1];for(var m=0,g=0,f=1;a>=f;f++){for(m=o-e+f,h=0;e-f-i>=h;h++)g=(t-r[m+h])/(r[h+o+1]-r[m+h]),b[h]=numeric.add(numeric.mul(g,b[h+1]),numeric.mul(1-g,b[h]));_[m]=b[0],_[o+a-f-i]=b[e-f-i]}for(h=m+1;o-i>h;h++)_[h]=b[h-m];return[c,_]},verb.eval.nurbs.rational_surface_derivs=function(e,r,n,t,i,a,s,u){var o=verb.eval.nurbs.surface_derivs(e,r,n,t,i,a,s,u),v=verb.eval.nurbs.separate_homo_derivs_2d(o),l=v[0],b=v[1],c=0,_=0,h=0,m=0,g=[],f=l[0][0].length;for(c=0;a>=c;c++)for(g.push([]),m=0;a-c>=m;m++){var u=l[c][m];for(h=1;m>=h;h++)u=numeric.sub(u,numeric.mul(numeric.mul(binomial.get(m,h),b[0][h]),g[c][m-h]));for(_=1;c>=_;_++){u=numeric.sub(u,numeric.mul(numeric.mul(binomial.get(c,_),b[_][0]),g[c-_][m]));var d=verb.eval.nurbs.zeros_1d(f);for(h=1;m>=h;h++)d=numeric.add(d,numeric.mul(numeric.mul(binomial.get(m,h),b[_][h]),g[c-_][m-h]));u=numeric.sub(u,numeric.mul(binomial.get(c,_),d))}g[c].push(numeric.mul(1/b[0][0],u))}return g},verb.eval.nurbs.rational_surface_point=function(e,r,n,t,i,a,s){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.surface_point(e,r,n,t,i,a,s))},verb.eval.nurbs.rational_curve_derivs=function(e,r,n,t,i){var a=verb.eval.nurbs.separate_homo_derivs_1d(verb.eval.nurbs.curve_derivs(e,r,n,t,i)),s=a[0],u=a[1],o=0,v=0,l=[];for(o=0;i>=o;o++){var b=s[o];for(v=1;o>=v;v++)b=numeric.sub(b,numeric.mul(numeric.mul(binomial.get(o,v),u[v]),l[o-v]));l.push(numeric.mul(1/u[0],b))}return l},verb.eval.nurbs.separate_homo_derivs_1d=function(e){for(var r=e[0].length,n=r-1,t=[],i=[],a=0,s=e.length;s>a;a++)t.push(e[a].slice(0,n)),i.push(e[a][n]);return[t,i]},verb.eval.nurbs.separate_homo_derivs_2d=function(e){for(var r=[],n=[],t=0,i=e.length;i>t;t++){var a=verb.eval.nurbs.separate_homo_derivs_1d(e[t]);r.push(a[0]),n.push(a[1])}return[r,n]},verb.eval.nurbs.rational_curve_point=function(e,r,n,t){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.curve_point(e,r,n,t))},verb.eval.nurbs.dehomogenize=function(e){for(var r=e.length,n=[],t=e[r-1],i=0;e.length-1>i;i++)n.push(e[i]/t);return n},verb.eval.nurbs.homogenize_1d=function(e,r){for(var n=e.length,t=e[0].length,i=0,a=[],s=0,u=[],o=0;n>o;o++){var v=[];for(u=e[o],s=r[o],i=0;t>i;i++)v.push(u[i]*s);v.push(s),a.push(v)}return a},verb.eval.nurbs.homogenize_2d=function(e,r){for(var n=e.length,t=(e[0].length,e[0][0].length,[]),i=0;n>i;i++)t.push(verb.eval.nurbs.homogenize_1d(e[i],r[i]));return t},verb.eval.nurbs.surface_derivs=function(e,r,n,t,i,a,s,u){var o=r.length-e-2,v=t.length-n-2;return verb.eval.nurbs.surface_derivs_given_n_m(o,e,r,v,n,t,i,a,s,u)},verb.eval.nurbs.surface_derivs_given_n_m=function(e,r,n,t,i,a,s,u,o,v){if(verb.eval.nurbs.are_valid_relations(r,s.length,n.length)===!1||verb.eval.nurbs.are_valid_relations(i,s[0].length,a.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var l=s[0][0].length,b=Math.min(u,r),c=Math.min(u,i),_=verb.eval.nurbs.zeros_3d(b+1,c+1,l),h=verb.eval.nurbs.knot_span_given_n(e,r,o,n),m=verb.eval.nurbs.knot_span_given_n(t,i,v,a),g=verb.eval.nurbs.deriv_basis_functions_given_n_i(h,o,r,e,n),f=verb.eval.nurbs.deriv_basis_functions_given_n_i(m,v,i,t,a),d=verb.eval.nurbs.zeros_2d(i+1,l),p=0,y=0,x=0,k=0,M=0;for(p=0;b>=p;p++){for(y=0;i>=y;y++)for(d[y]=verb.eval.nurbs.zeros_1d(l),x=0;r>=x;x++)d[y]=numeric.add(d[y],numeric.mul(g[p][x],s[h-r+x][m-i+y]));for(M=Math.min(u-p,c),k=0;M>=k;k++)for(_[p][k]=verb.eval.nurbs.zeros_1d(l),y=0;i>=y;y++)_[p][k]=numeric.add(_[p][k],numeric.mul(f[k][y],d[y]))}return _},verb.eval.nurbs.surface_point=function(e,r,n,t,i,a,s){var u=r.length-e-2,o=t.length-n-2;return verb.eval.nurbs.surface_point_given_n_m(u,e,r,o,n,t,i,a,s)},verb.eval.nurbs.volume_point=function(e,r,n,t,i,a,s,u,o,v){var l=r.length-e-2,b=t.length-n-2,c=a.length-i-2;return verb.eval.nurbs.volume_point_given_n_m_l(l,e,r,b,n,t,c,i,a,s,u,o,v)},verb.eval.nurbs.volume_point_given_n_m_l=function(e,r,n,t,i,a,s,u,o,v,l,b,c){if(!verb.eval.nurbs.are_valid_relations(r,v.length,n.length)||!verb.eval.nurbs.are_valid_relations(i,v[0].length,a.length)||!verb.eval.nurbs.are_valid_relations(u,v[0][0].length,o.length))return console.error("Invalid relations between control points and knot vector"),null;for(var _=v[0][0][0].length,h=verb.eval.nurbs.knot_span_given_n(e,r,l,n),m=verb.eval.nurbs.knot_span_given_n(t,i,b,a),g=verb.eval.nurbs.knot_span_given_n(s,u,c,o),f=verb.eval.nurbs.basis_functions_given_knot_span_index(h,l,r,n),d=verb.eval.nurbs.basis_functions_given_knot_span_index(m,b,i,a),p=verb.eval.nurbs.basis_functions_given_knot_span_index(g,c,u,o),y=h-r,x=m,k=g,M=verb.eval.nurbs.zeros_1d(_),z=verb.eval.nurbs.zeros_1d(_),w=verb.eval.nurbs.zeros_1d(_),N=0,P=0,E=0;u>=E;E++){for(w=verb.eval.nurbs.zeros_1d(_),k=g-u+E,N=0;i>=N;N++){for(z=verb.eval.nurbs.zeros_1d(_),x=m-i+N,P=0;r>=P;P++)z=numeric.add(z,numeric.mul(f[P],v[y+P][x][k]));w=numeric.add(w,numeric.mul(d[N],z))}M=numeric.add(M,numeric.mul(p[E],w))}return M},verb.eval.nurbs.surface_point_given_n_m=function(e,r,n,t,i,a,s,u,o){if(verb.eval.nurbs.are_valid_relations(r,s.length,n.length)===!1||verb.eval.nurbs.are_valid_relations(i,s[0].length,a.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var v=s[0][0].length,l=verb.eval.nurbs.knot_span_given_n(e,r,u,n),b=verb.eval.nurbs.knot_span_given_n(t,i,o,a),c=verb.eval.nurbs.basis_functions_given_knot_span_index(l,u,r,n),_=verb.eval.nurbs.basis_functions_given_knot_span_index(b,o,i,a),h=l-r,m=b,g=verb.eval.nurbs.zeros_1d(v),f=verb.eval.nurbs.zeros_1d(v),d=0,p=0;for(d=0;i>=d;d++){for(f=verb.eval.nurbs.zeros_1d(v),m=b-i+d,p=0;r>=p;p++)f=numeric.add(f,numeric.mul(c[p],s[h+p][m]));g=numeric.add(g,numeric.mul(_[d],f))}return g},verb.eval.nurbs.curve_derivs=function(e,r,n,t,i){var a=r.length-e-2;return verb.eval.nurbs.curve_derivs_given_n(a,e,r,n,t,i)},verb.eval.nurbs.curve_derivs_given_n=function(e,r,n,t,i,a){if(verb.eval.nurbs.are_valid_relations(r,t.length,n.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var s=t[0].length,u=Math.min(a,r),o=verb.eval.nurbs.zeros_2d(u+1,s),v=verb.eval.nurbs.knot_span_given_n(e,r,i,n),l=verb.eval.nurbs.deriv_basis_functions_given_n_i(v,i,r,u,n),b=0,c=0;for(b=0;u>=b;b++)for(c=0;r>=c;c++)o[b]=numeric.add(o[b],numeric.mul(l[b][c],t[v-r+c]));return o},verb.eval.nurbs.are_valid_relations=function(e,r,n){return 0===r+e+1-n?!0:!1},verb.eval.nurbs.curve_point=function(e,r,n,t){var i=r.length-e-2;return verb.eval.nurbs.curve_point_given_n(i,e,r,n,t)},verb.eval.nurbs.curve_point_given_n=function(e,r,n,t,i){if(verb.eval.nurbs.are_valid_relations(r,t.length,n.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;for(var a=verb.eval.nurbs.knot_span_given_n(e,r,i,n),s=verb.eval.nurbs.basis_functions_given_knot_span_index(a,i,r,n),u=verb.eval.nurbs.zeros_1d(t[0].length),o=0;r>=o;o++)u=numeric.add(u,numeric.mul(s[o],t[a-r+o]));return u},verb.eval.nurbs.zeros_1d=function(e){e=e>0?e:0;for(var r=[];e--;)r.push(0);return r},verb.eval.nurbs.zeros_2d=function(e,r){r=r>0?r:0,e=e>0?e:0;for(var n=[],t=r,i=e;e--;){for(n.push([]);t--;)n[i-e-1].push(0);t=r}return n},verb.eval.nurbs.zeros_3d=function(e,r,n){r=r>0?r:0,e=e>0?e:0;for(var t=[],i=r,a=e;e--;){for(t.push([]);i--;)t[a-e-1].push(verb.eval.nurbs.zeros_1d(n));i=r}return t},verb.eval.nurbs.deriv_basis_functions=function(e,r,n){var t=verb.eval.nurbs.knot_span(r,e,n),i=n.length-1,a=i-r-1;return verb.eval.nurbs.deriv_basis_functions_given_n_i(t,e,r,a,n)},verb.eval.nurbs.deriv_basis_functions_given_n_i=function(e,r,n,t,i){var a=verb.eval.nurbs.zeros_2d(n+1,n+1),s=Array(n+1),u=Array(n+1),o=0,v=0,l=1,b=0;for(a[0][0]=1,l=1;n>=l;l++){for(s[l]=r-i[e+1-l],u[l]=i[e+l]-r,o=0,b=0;l>b;b++)a[l][b]=u[b+1]+s[l-b],v=a[b][l-1]/a[l][b],a[b][l]=o+u[b+1]*v,o=s[l-b]*v;a[l][l]=o}var c=verb.eval.nurbs.zeros_2d(t+1,n+1),_=verb.eval.nurbs.zeros_2d(2,n+1),h=1,m=0,g=1,f=0,d=0,p=0,y=0,x=0;for(l=0;n>=l;l++)c[0][l]=a[l][n];for(b=0;n>=b;b++)for(m=0,g=1,_[0][0]=1,h=1;t>=h;h++){for(f=0,d=b-h,p=n-h,b>=h&&(_[g][0]=_[m][0]/a[p+1][d],f=_[g][0]*a[d][p]),y=d>=-1?1:-d,x=p>=b-1?h-1:n-b,l=y;x>=l;l++)_[g][l]=(_[m][l]-_[m][l-1])/a[p+1][d+l],f+=_[g][l]*a[d+l][p];p>=b&&(_[g][h]=-_[m][h-1]/a[p+1][b],f+=_[g][h]*a[b][p]),c[h][b]=f,l=m,m=g,g=l}for(b=n,h=1;t>=h;h++){for(l=0;n>=l;l++)c[h][l]*=b;b*=n-h}return c},verb.eval.nurbs.basis_functions=function(e,r,n){var t=verb.eval.nurbs.knot_span(e,r,n);return verb.eval.nurbs.basis_functions_given_knot_span_index(t,e,r,n)},verb.eval.nurbs.basis_functions_given_knot_span_index=function(e,r,n,t){var i=Array(n+1),a=Array(n+1),s=Array(n+1),u=0,o=0;i[0]=1;for(var v=1;n>=v;v++){a[v]=r-t[e+1-v],s[v]=t[e+v]-r,u=0;for(var l=0;v>l;l++)o=i[l]/(s[l+1]+a[v-l]),i[l]=u+s[l+1]*o,u=a[v-l]*o;i[v]=u}return i},verb.eval.nurbs.knot_span=function(e,r,n){var t=n.length-1,i=t-e-1;return verb.eval.nurbs.knot_span_given_n(i,e,r,n)},verb.eval.nurbs.knot_span_given_n=function(e,r,n,t){if(n>=t[e+1])return e;if(t[r]>n)return r;for(var i=r,a=e+1,s=Math.floor((i+a)/2);t[s]>n||n>=t[s+1];)t[s]>n?a=s:i=s,s=Math.floor((i+a)/2);return s};
+/*! verb 2014-02-01 */
+function getEastNeighbor(e,r,n,t,i,s){return n===i-1?null:s[e+1]}function getNorthNeighbor(e,r,n,t,i,s){return 0===r?null:s[e-i]}function getSouthNeighbor(e,r,n,t,i,s){return r===t-1?null:s[e+i]}function getWestNeighbor(e,r,n,t,i,s){return 0===n?null:s[e-1]}function crossprod(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]}if("object"!=typeof exports||void 0===exports)importScripts("labor.js"),importScripts("binomial.js"),importScripts("numeric-1.2.6.min.js");else var labor=require("labor");var verb=verb||{};verb.eval=verb.eval||{},verb.eval.nurbs=verb.eval.nurbs||{},verb.eval.mesh=verb.eval.mesh||{},verb.eval.geom=verb.eval.geom||{},verb.geom=verb.geom||{},verb.EPSILON=1e-8,verb.TOLERANCE=.001;var router=new labor.Router(verb.eval.nurbs);numeric.normalized=function(e){return numeric.div(e,numeric.norm2(e))},numeric.cross=function(e,r){return[e[1]*r[2]-e[2]*r[1],e[2]*r[0]-e[0]*r[2],e[0]*r[1]-e[1]*r[0]]},verb.left=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(0,r)},verb.right=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r)},verb.rightWithPivot=function(e){if(0===e.length)return[];var r=Math.ceil(e.length/2);return e.slice(r-1)},verb.unique=function(e,r){if(0===e.length)return[];for(var n=[e.pop()],t=0;e.length>t;t++){for(var i=e.pop(),s=!0,a=0;n.length>a;a++)if(r(i,n[t])){s=!1;break}s&&n.push(i)}return n},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb_refine=function(e,r,n,t,i,s,a,u,o,v,l,b){var c=verb.eval.nurbs.intersect_rational_curve_surface_by_aabb(e,r,n,t,i,s,a,u,o,v,l,b);return c.map(function(o){var v=[o.p,o.uv[0],o.uv[1]],l=verb.eval.nurbs.refine_rational_curve_surface_intersection(e,r,n,t,i,s,a,u,v);return o.p=l[0],o.uv[0]=l[1],o.uv[1]=l[2],o.distance=l[3],delete o.face,o})},verb.eval.nurbs.refine_rational_curve_surface_intersection=function(e,r,n,t,i,s,a,u,o){var v=function(o){var v=verb.eval.nurbs.rational_curve_point(s,a,u,o[0]),l=verb.eval.nurbs.rational_surface_point(e,r,n,t,i,o[1],o[2]),b=numeric.sub(v,l);return numeric.dot(b,b)},l=numeric.uncmin(v,o);return l.solution.concat(l.f)},verb.eval.nurbs.intersect_rational_curve_surface_by_aabb=function(e,r,n,t,i,s,a,u,o,v,l,b){var c=verb.eval.nurbs.rational_curve_adaptive_sample(s,a,u,o,!0),h=verb.eval.nurbs.tesselate_rational_surface_naive(e,r,n,t,i,l,b),_=c.map(function(e){return e[0]}),m=c.map(function(e){return e.slice(1)}),g=verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(m,_,h,verb.range(h.faces.length),v);return verb.unique(g,function(e,r){return v>numeric.norm2(numeric.sub(e.point,r.point))&&v>Math.abs(e.p-r.p)&&v>numeric.norm2(numeric.sub(e.uv,r.uv))})},verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb=function(e,r,n,t,i){var s=new verb.geom.BoundingBox(e),a=verb.eval.mesh.make_mesh_aabb(n.points,n.faces,t);if(!s.intersects(a,i))return[];if(2!==e.length||1!==t.length){if(1===t.length){var u=verb.left(e),o=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,v,n,t,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,l,n,t,i))}if(2===e.length){var b=verb.eval.mesh.sort_tris_on_longest_axis(a,n.points,n.faces,t),c=verb.left(b),h=verb.right(b);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,n,c,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(e,r,n,h,i))}var b=verb.eval.mesh.sort_tris_on_longest_axis(a,n.points,n.faces,t),c=verb.left(b),h=verb.right(b),u=verb.left(e),o=verb.rightWithPivot(e),v=verb.left(r),l=verb.rightWithPivot(r);return verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,v,n,c,i).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(u,v,n,h,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,l,n,c,i)).concat(verb.eval.nurbs.intersect_parametric_polyline_mesh_by_aabb(o,l,n,h,i))}var _=verb.eval.geom.intersect_segment_with_tri(e[0],e[1],n.points,n.faces[t[0]]);if(null!=_){var m=_.p*(r[1]-r[0])+r[0],g=n.faces[t][0],f=n.faces[t][1],d=n.faces[t][2],p=n.uvs[g],y=n.uvs[f],x=n.uvs[d],k=numeric.sub(y,p),N=numeric.sub(x,p),E=numeric.add(p,numeric.mul(_.s,k),numeric.mul(_.t,N));return[{point:_.point,p:m,uv:E,face:t[0]}]}return[]},verb.eval.geom.intersect_segment_with_tri=function(e,r,n,t){var i=n[t[0]],s=n[t[1]],a=n[t[2]],u=numeric.sub(s,i),o=numeric.sub(a,i),v=numeric.cross(u,o),l=numeric.sub(r,e),b=numeric.sub(e,i),c=-numeric.dot(v,b),h=numeric.dot(v,l);if(Math.abs(h)<verb.EPSILON)return null;var _=c/h;if(0>_||_>1)return null;var m=numeric.add(e,numeric.mul(_,l)),g=numeric.dot(u,o),f=numeric.dot(u,u),d=numeric.dot(o,o),p=numeric.sub(m,i),y=numeric.dot(p,u),x=numeric.dot(p,o),k=g*g-f*d,N=(g*x-d*y)/k,E=(g*y-f*x)/k;return N>1+verb.EPSILON||E>1+verb.EPSILON||-verb.EPSILON>E||-verb.EPSILON>N||N+E>1+verb.EPSILON?null:{point:m,s:N,t:E,p:_}},verb.eval.geom.intersect_segment_with_plane=function(e,r,n,t){var i=numeric.dot(t,numeric.sub(e,r));if(EPSILON>abs(i))return null;var s=numeric.dot(t,numeric.sub(n,e));return{p:s/i}},verb.eval.geom.intersect_aabb_trees=function(e,r,n,t,i,s){var a=i.bounding_box.intersects(s.bounding_box);return a?0===i.children.length&&0===s.children.length?[[i.triangle,s.triangle]]:0===i.children.length&&0!=s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i,s.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i,s.children[1])):0!=i.children.length&&0===s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],s).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],s)):0!=i.children.length&&0!=s.children.length?verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],s.children[0]).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[0],s.children[1])).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],s.children[0])).concat(verb.eval.geom.intersect_aabb_trees(e,r,n,t,i.children[1],s.children[1])):void 0:[]},verb.eval.mesh.make_mesh_aabb_tree=function(e,r,n){var t={bounding_box:verb.eval.mesh.make_mesh_aabb(e,r,n),children:[]};if(1===n.length)return t.triangle=n[0],t;var i=verb.eval.mesh.sort_tris_on_longest_axis(t.bounding_box,e,r,n),s=i.slice(0,Math.floor(i.length/2)),a=i.slice(Math.floor(i.length/2),i.length);return t.children=[verb.eval.mesh.make_mesh_aabb_tree(e,r,s),verb.eval.mesh.make_mesh_aabb_tree(e,r,a)],t},verb.eval.mesh.make_mesh_aabb=function(e,r,n){var t=new verb.geom.BoundingBox;return n.forEach(function(n){t.add(e[r[n][0]]),t.add(e[r[n][1]]),t.add(e[r[n][2]])}),t},verb.eval.mesh.sort_tris_on_longest_axis=function(e,r,n,t){for(var i=e.get_longest_axis(),s=[],a=t.length-1;a>=0;a--){var u=t[a],o=verb.eval.mesh.get_min_coordinate_on_axis(r,n[u],i);s.push([o,u])}s.sort(function(e,r){return e[0]>r[0]});for(var v=[],a=0,l=s.length;l>a;a++)v.push(s[a][1]);return v},verb.eval.mesh.get_min_coordinate_on_axis=function(e,r,n){for(var t=[],i=0;3>i;i++)t.push(e[r[i]][n]);return Math.min.apply(Math,t)},verb.eval.geom.get_tri_centroid=function(e,r){for(var n=[0,0,0],t=0;3>t;t++)for(var i=0;3>i;i++)n[i]+=e[r[t]][i];for(var t=0;3>t;t++)n[t]/=3;return n},verb.eval.geom.get_tri_norm=function(e,r){var n=e[r[0]],t=e[r[1]],i=e[r[2]],s=numeric.sub(t,n),a=numeric.sub(i,n),u=numeric.cross(s,a);return numeric.mul(1/numeric.norm2(u),u)},verb.eval.nurbs.intersect_rational_curves_by_aabb_refine=function(e,r,n,t,i,s,a,u){var o=verb.eval.nurbs.intersect_rational_curves_by_aabb(e,r,n,t,i,s,a,u);return o.map(function(a){return verb.eval.nurbs.refine_rational_curve_intersection(e,r,n,t,i,s,a)})},verb.eval.nurbs.refine_rational_curve_intersection=function(e,r,n,t,i,s,a){var u=function(a){var u=verb.eval.nurbs.rational_curve_point(e,r,n,a[0]),o=verb.eval.nurbs.rational_curve_point(t,i,s,a[1]),v=numeric.sub(u,o);return numeric.dot(v,v)},o=numeric.uncmin(u,a);return o.solution.concat(o.f)},verb.eval.nurbs.intersect_rational_curves_by_aabb=function(e,r,n,t,i,s,a,u){var o=verb.eval.nurbs.rational_curve_adaptive_sample(e,r,n,a,!0),v=verb.eval.nurbs.rational_curve_adaptive_sample(t,i,s,a,!0),l=o.map(function(e){return e[0]}),b=v.map(function(e){return e[0]}),c=o.map(function(e){return e.slice(1)}),h=v.map(function(e){return e.slice(1)});return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(c,h,l,b,u)},verb.eval.nurbs.intersect_parametric_polylines_by_aabb=function(e,r,n,t,i){var s=new verb.geom.BoundingBox(e),a=new verb.geom.BoundingBox(r);if(!s.intersects(a,i))return[];if(2!==e.length||2!==r.length){if(2===e.length){var u=Math.ceil(r.length/2),o=r.slice(0,u),v=r.slice(u-1),l=t.slice(0,u),b=t.slice(u-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,o,n,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(e,v,n,b,i))}if(2===r.length){var c=Math.ceil(e.length/2),h=e.slice(0,c),_=e.slice(c-1),m=n.slice(0,c),g=n.slice(c-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,r,m,t,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,r,g,t,i))}var c=Math.ceil(e.length/2),h=e.slice(0,c),_=e.slice(c-1),m=n.slice(0,c),g=n.slice(c-1),u=Math.ceil(r.length/2),o=r.slice(0,u),v=r.slice(u-1),l=t.slice(0,u),b=t.slice(u-1);return verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,o,m,l,i).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(h,v,m,b,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,o,g,l,i)).concat(verb.eval.nurbs.intersect_parametric_polylines_by_aabb(_,v,g,b,i))}var f=verb.eval.geom.intersect_segments(e[0],e[1],r[0],r[1],i);return null!=f?(f[0][0]=f[0][0]*(n[1]-n[0])+n[0],f[1][0]=f[1][0]*(t[1]-t[0])+t[0],[[f[0][0],f[1][0]]]):[]},verb.eval.geom.intersect_segments=function(e,r,n,t,i){var s=numeric.sub(r,e),a=Math.sqrt(numeric.dot(s,s)),u=numeric.mul(1/a,s),o=numeric.sub(t,n),v=Math.sqrt(numeric.dot(o,o)),l=numeric.mul(1/v,o),b=verb.eval.geom.intersect_rays(e,u,n,l);if(null!=b){var c=Math.min(Math.max(0,b[0]/a),1),h=Math.min(Math.max(0,b[1]/v),1),_=numeric.add(numeric.mul(c,s),e),m=numeric.add(numeric.mul(h,o),n),g=numeric.norm2Squared(numeric.sub(_,m));if(i*i>g)return[[c].concat(_),[h].concat(m)]}return null},verb.eval.geom.closest_point_on_ray=function(e,r,n){var t=numeric.sub(e,r),i=numeric.dot(t,n),s=numeric.add(r,numeric.mul(i,n));return s},verb.eval.geom.intersect_rays=function(e,r,n,t){var i=numeric.dot(r,t),s=numeric.dot(r,n),a=numeric.dot(r,e),u=numeric.dot(t,n),o=numeric.dot(t,e),v=numeric.dot(r,r),l=numeric.dot(t,t),b=v*l-i*i;if(Math.abs(b)<verb.EPSILON)return null;var c=i*(s-a)-v*(u-o),h=c/b,_=(s-a+h*i)/v;return[_,h]},verb.eval.mesh.intersect_meshes_by_aabb=function(e,r,n,t,i){var s=verb.range(r.length),a=verb.range(i.length),u=verb.eval.mesh.make_mesh_aabb_tree(e,r,s),o=verb.eval.mesh.make_mesh_aabb_tree(t,i,a);verb.eval.mesh.intersect_aabb_tree(e,r,t,i,u,o)},verb.eval.geom.intersect_tris=function(e,r,n,t,i){for(var s=[e[tr1[0]],e[tr1[1]]],a=[e[tr1[1]],e[tr1[2]]],u=[e[tr1[2]],e[tr1[0]]],o=[t[tr2[0]],t[tr2[1]]],v=[t[tr2[1]],t[tr2[2]]],l=[t[tr2[2]],t[tr2[0]]],b=[s,a,u],c=[o,v,l],h=[],_=verb.eval.geom.get_tri_norm(t,i),m=t[tr2[0]],g=0;3>g;g++){var f=verb.eval.geom.intersect_segment_with_plane(b[g][0],c[g][1],m,_);f.intersects&&h.push(f)}if(2!==h.length)return null;for(var d=[h[0].point,h[1].point],p=[],g=0;3>g;g++){var y=verb.eval.geom.intersect_segments(d[0],d[1],d,b1,tol);y&&p.push(y)}0===p.length||1===p.length||2===p.length},verb.eval.nurbs.tesselate_rational_surface_naive=function(e,r,n,t,i,s,a){1>s&&(s=1),1>a&&(a=1);for(var u=1/s,o=1/a,v=[],l=[],b=[],c=0;s+1>c;c++)for(var h=0;a+1>h;h++){var _=c*u,m=h*o;l.push([_,m]);var g=verb.eval.nurbs.rational_surface_derivs(e,r,n,t,i,1,_,m),f=g[0][0];v.push(f);var d=numeric.cross(g[0][1],g[1][0]);b.push(d)}for(var p=[],c=0;s>c;c++)for(var h=0;a>h;h++){var y=c*(a+1)+h,x=(c+1)*(a+1)+h,k=x+1,N=y+1,E=[y,x,k],M=[y,k,N];p.push(E),p.push(M)}return{points:v,faces:p,uvs:l,normals:b}},verb.eval.nurbs.rational_curve_regular_sample=function(e,r,n,t,i){return verb.eval.nurbs.rational_curve_regular_sample_range(e,r,n,0,1,t,i)},verb.eval.nurbs.rational_curve_regular_sample_range=function(e,r,n,t,i,s,a){1>s&&(s=2);for(var u=[],o=(i-t)/(s-1),v=0,l=0;s>l;l++)v=t+o*l,a?u.push([v].concat(verb.eval.nurbs.rational_curve_point(e,r,n,v))):u.push(verb.eval.nurbs.rational_curve_point(e,r,n,v));return u},verb.eval.nurbs.rational_curve_adaptive_sample=function(e,r,n,t,i){return 1===e?i?n.map(function(e,n){return[r[n+1]].concat(verb.eval.nurbs.dehomogenize(e))}):n.map(verb.eval.nurbs.dehomogenize):verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,0,1,t,i)},verb.eval.nurbs.rational_curve_adaptive_sample_range=function(e,r,n,t,i,s,a){var u=verb.eval.nurbs.rational_curve_point(e,r,n,t),o=verb.eval.nurbs.rational_curve_point(e,r,n,i),v=.5+.2*Math.random(),l=t+(i-t)*v,b=verb.eval.nurbs.rational_curve_point(e,r,n,l),c=numeric.sub(u,o),h=numeric.sub(u,b);if(s>numeric.dot(c,c)&&numeric.dot(h,h)>s||!verb.eval.nurbs.three_points_are_flat(u,b,o,s)){var _=t+.5*(i-t),m=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,t,_,s,a),g=verb.eval.nurbs.rational_curve_adaptive_sample_range(e,r,n,_,i,s,a);return m.slice(0,-1).concat(g)}return a?[[t].concat(u),[i].concat(o)]:[u,o]},verb.eval.nurbs.three_points_are_flat=function(e,r,n,t){var i=numeric.sub(r,e),s=numeric.sub(n,e),a=crossprod(i,s),u=numeric.dot(a,a);return t>u},verb.eval.nurbs.divide_rational_surface_adaptive=function(e,r,n,t,i,s){for(var a={degree_u:e,knots_u:r,degree_v:n,knots_v:t,homo_control_points:i},u=s.minDivsU,o=s.minDivsV,v=Math.max.apply(null,r),l=Math.min.apply(null,r),b=Math.max.apply(null,t),c=Math.min.apply(null,t),h=(v-l)/u,_=(b-c)/o,m=[],g=0;u>g;g++)for(var f=0;o>f;f++){var d=l+h*g,p=l+h*(g+1),y=c+_*f,x=c+_*(f+1);m.push(new verb.eval.nurbs.AdaptiveRefinementNode(a,d,p,y,x,null,null))}for(var g=0;u>g;g++)for(var f=0;o>f;f++){var k=g*o+f,N=getNorthNeighbor(k,g,f,u,o,m),E=getEastNeighbor(k,g,f,u,o,m),M=getSouthNeighbor(k,g,f,u,o,m),w=getWestNeighbor(k,g,f,u,o,m);m[k].neighbors=[N,E,M,w],m.divide(s)}return m},verb.eval.nurbs.is_rational_surface_domain_flat=function(e){var r=verb.eval.nurbs.rational_surface_point,n=(u[1]-u[0]/2)*(.1*Math.random()+1),t=(v[1]-v[0]/2)*(.1*Math.random()+1),i=r(e.degree_u,e.knots_u,e.degree_v,e.knots_v,e.homo_control_points,u[0],v[0]),s=r(e.degree_u,e.knots_u,e.degree_v,e.knots_v,e.homo_control_points,u[0]+n,v[0]+t),a=r(e.degree_u,e.knots_u,e.degree_v,e.knots_v,e.homo_control_points,u[1],v[1]);return verb.eval.nurbs.three_points_are_flat(i,s,a,tol)},verb.eval.nurbs.triangulate_adaptive_refinement_node_tree=function(e){var r={uvs:[],points:[],normals:[],faces:[]};return r.faces=e.map(function(e){e.triangulate(r)}).flatten(),r},verb.eval.nurbs.tesselate_rational_surface_adaptive=function(e,r,n,t,i,s){verb.eval.nurbs.divide_rational_surface_adaptive(e,r,n,t,i,s);var a=verb.eval.nurbs.triangulate_adaptive_refinement_node_tree(arrTree);return verb.eval.nurbs.unique_mesh(a)},verb.eval.nurbs.unique_mesh=function(e){return e},Array.prototype.where=function(e){if(0===this.length)return this;for(var r=[],n=0;this.length>n;n++)e(this[n])&&r.push(this[n]);return r},verb.eval.nurbs.AdaptiveRefinementNode=function(e,r,n,t,i,s,a){this.srf=e,this.u0=r,this.u1=n,this.v0=t,this.v1=i,this.parentNode=s,this.neighbors=a,this.leafEdgeUvs=[[r,t],[n,t],[n,i],[r,i]],this.cachedEdgeUvs=[]},verb.eval.nurbs.AdaptiveRefinementNode.prototype.isLeaf=function(){return void 0===this.children},verb.eval.nurbs.AdaptiveRefinementNode.prototype.evalSurface=function(){var e=verb.eval.nurbs.rational_surface_derivs(this.srf.degree_u,this.srf.knots_u,this.srf.degree_v,this.srf.knots_v,this.srf.homo_control_points,1,pt_u,pt_v),r=e[0][0];points.push(r);var n=numeric.cross(e[0][1],e[1][0]);return{point:r,normal:n}},verb.eval.nurbs.AdaptiveRefinementNode.prototype.getEdgeUvs=function(e){return this.isLeaf()?[this.leafEdgeUvs[e]]:(this.cachedEdgeUvs[e]=this.cachedEdgeUvs[e]||this.children[e].getEdgeUvs(e).concat(this.children[(e+1)%4].getEdgeUvs(e)),this.cachedEdgeUvs[e])},verb.eval.nurbs.AdaptiveRefinementNode.prototype.getAllEdgeUvs=function(e){var r=[this.leafEdgeUvs[e]];if(null===this.neighbors[e])return r;var n=this.neighbors[e].getEdgeUvs((e+2)%4),t=e%2,i=this,s=[function(e){return e[0]>i.u0+verb.EPSILON&&e[0]<i.u1-verb.EPSILON},function(e){return e[1]>i.v0+verb.EPSILON&&e[1]<i.v1-verb.EPSILON}];return r.concat(n.where(s[t]).reverse())},verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulateLeaf=function(e){for(var r=e.points.length-1,n=[],t=0;4>t;t++)n.concat(this.getAllEdgeUvs(t));if(n.forEach(function(r){e.uvs.push(r);var n=this.evalSurface(r);e.points.push(n.point),e.normals.push(n.normal)}),4===n.length)return e.faces.push([r+1,r+4,r+2]),e.faces.push([r+4,r+3,r+2]),void 0;this.u05=this.u05||(this.u0+this.u1)/2,this.v05=this.v05||(this.v0+this.v1)/2,e.uvs.push([this.u05,this.v05]);var i=this.evalSurface([this.u05,this.v05]);e.points.push(i.point),e.normals.push(i.normal);for(var s=e.points.length-1,t=0;n.length>t;t++)e.faces.push([s,(r+t+2)%n.length,(r+t+1)%n.length])},verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulate=function(e){return this.isLeaf()?this.triangulateLeaf(e):(this.children.forEach(function(r){null!==r&&r.triangulate(e)}),void 0)},verb.eval.nurbs.AdaptiveRefinementNode.prototype.shouldDivide=function(e,r){return e.minDepth&&e.minDepth>r?!0:this.srf&&!verb.eval.nurbs.is_rational_surface_domain_flat(this.srf,this.u0,this.u1,this.v0,this.v1,e)?!0:!1},verb.eval.nurbs.AdaptiveRefinementNode.prototype.divide=function(e,r){void 0===r&&(r=0),this.shouldDivide(e,r)&&(r++,this.u05=(this.u0+this.u1)/2,this.v05=(this.v0+this.v1)/2,this.children=[new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u0,this.u05,this.v0,this.v05,this),new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u05,this.u1,this.v0,this.v05,this),new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u05,this.u1,this.v05,this.v1,this),new verb.eval.nurbs.AdaptiveRefinementNode(this.srf,this.u0,this.u05,this.v05,this.v1,this)],this.children[0].neighbors=[this.neighbors[0],this.children[1],this.children[3],this.neighbors[3]],this.children[1].neighbors=[this.neighbors[0],this.neighbors[1],this.children[2],this.children[0]],this.children[2].neighbors=[this.children[1],this.neighbors[1],this.neighbors[2],this.children[3]],this.children[3].neighbors=[this.children[0],this.children[2],this.neighbors[2],this.neighbors[3]],this.children.forEach(function(n){n.divide(e,r)}))},verb.eval.nurbs.get_sweep1_surface=function(e,r,n,t,i,s,a,u){for(var o=verb.eval.nurbs.homogenize_1d(a,u),v=verb.eval.nurbs.rational_curve_point(s,i,o,0),l=1/a.length,b=[],c=[],h=0;a.length>h;h++){for(var _=verb.eval.nurbs.rational_curve_point(s,i,o,h*l),m=numeric.sub(_,v),g=[],f=[],d=0;n.length>d;d++)g.push(numeric.add(m,n[d])),f.push(t[d]*u[h]);b.push(g),c.push(f)}return{knots_u:i,knots_v:e,control_points:b,degree_u:s,degree_v:r,weights:c}},verb.eval.nurbs.get_ellipse_arc=function(e,r,n,t,i,s,a){s>a&&(a=2*Math.PI+s);var u=a-s,o=0;o=Math.PI/2>=u?1:Math.PI>=u?2:3*Math.PI/2>=u?3:4;var v=u/o,l=Math.cos(v/2),b=numeric.add(e,numeric.mul(t,Math.cos(s),r),numeric.mul(i,Math.sin(s),n)),c=numeric.sub(numeric.mul(Math.cos(s),n),numeric.mul(Math.sin(s),r)),h=verb.eval.nurbs.zeros_1d(2*o),_=verb.eval.nurbs.zeros_1d(2*o+3),m=0,g=s,f=verb.eval.nurbs.zeros_1d(2*o);h[0]=b,f[0]=1;for(var d=1;o>=d;d++){g+=v;var p=numeric.add(e,numeric.mul(t,Math.cos(g),r),numeric.mul(i,Math.sin(g),n));f[m+2]=1,h[m+2]=p;var y=numeric.sub(numeric.mul(Math.cos(g),n),numeric.mul(Math.sin(g),r)),x=verb.eval.geom.intersect_rays(b,numeric.mul(1/numeric.norm2(c),c),p,numeric.mul(1/numeric.norm2(y),y)),k=numeric.add(b,numeric.mul(c,x[0]));f[m+1]=l,h[m+1]=k,m+=2,o>d&&(b=p,c=y)}for(var N=2*o+1,d=0;3>d;d++)_[d]=0,_[d+N]=1;switch(o){case 1:break;case 2:_[3]=_[4]=.5;break;case 3:_[3]=_[4]=1/3,_[5]=_[6]=2/3;break;case 4:_[3]=_[4]=.25,_[5]=_[6]=.5,_[7]=_[8]=.75}return{knots:_,control_points:h,degree:2,weights:f}},verb.eval.nurbs.get_sphere_surface=function(e,r,n,t){var i=verb.eval.nurbs.get_arc(e,numeric.mul(r,-1),n,t,0,Math.PI);return verb.eval.nurbs.get_revolved_surface(e,r,2*Math.PI,i.knots,i.degree,i.control_points,i.weights)},verb.eval.nurbs.get_polyline_curve=function(e){for(var r=e.length-1,n=1/r,t=[0,0],i=1;r>i;i++)t.push(i*n);t.push(1),t.push(1);for(var s=[],i=0;e.length>i;i++)s.push(1);return{knots:t,control_points:e.slice(0),degree:1,weights:s}},verb.eval.nurbs.get_4pt_surface=function(e,r,n,t){return{knots_u:[0,0,1,1],knots_v:[0,0,1,1],control_points:[[e,t],[r,n]],degree_u:1,degree_v:1,weights:[[1,1],[1,1]]}},verb.eval.nurbs.get_cylinder_surface=function(e,r,n,t,i){var s=crossprod(e,r),a=(2*Math.PI,verb.eval.nurbs.get_arc(n,r,s,i,0,2*Math.PI));return verb.eval.nurbs.get_extruded_surface(e,t,a.knots,a.degree,a.control_points,a.weights)},verb.eval.nurbs.get_cone_surface=function(e,r,n,t,i){var s=2*Math.PI,a=1,u=[numeric.add(n,numeric.mul(t,e)),numeric.add(n,numeric.mul(i,r))],o=[0,0,1,1],v=[1,1];return verb.eval.nurbs.get_revolved_surface(n,e,s,o,a,u,v)},verb.eval.nurbs.get_extruded_surface=function(e,r,n,t,i,s){for(var a=verb.eval.nurbs.zeros_2d(3,i.length),u=verb.eval.nurbs.zeros_2d(3,i.length),o=numeric.mul(e,r),v=numeric.mul(e,.5*r),l=0;i.length>l;l++)a[0][l]=i[l],a[1][l]=numeric.add(v,i[l]),a[2][l]=numeric.add(o,i[l]),u[0][l]=s[l],u[1][l]=s[l],u[2][l]=s[l];return{knots_u:[0,0,0,1,1,1],knots_v:n,control_points:a,degree_u:2,degree_v:t,weights:u}},verb.eval.nurbs.get_revolved_surface=function(e,r,n,t,i,s,a){var u,o,v,l;Math.PI/2>=n?(u=1,o=verb.eval.nurbs.zeros_1d(6+2*(u-1))):Math.PI>=n?(u=2,o=verb.eval.nurbs.zeros_1d(6+2*(u-1)),o[3]=o[4]=.5):3*Math.PI/2>=n?(u=3,o=verb.eval.nurbs.zeros_1d(6+2*(u-1)),o[3]=o[4]=1/3,o[5]=o[6]=2/3):(u=4,o=verb.eval.nurbs.zeros_1d(6+2*(u-1)),o[3]=o[4]=.25,o[5]=o[6]=.5,o[7]=o[8]=.75);for(var b=n/u,c=3+2*(u-1),h=0;3>h;c++,h++)o[h]=0,o[c]=1;for(var _=Math.cos(b/2),m=0,g=verb.eval.nurbs.zeros_1d(u+1),f=verb.eval.nurbs.zeros_1d(u+1),v=verb.eval.nurbs.zeros_2d(2*u+1,s.length),l=verb.eval.nurbs.zeros_2d(2*u+1,s.length),h=1;u>=h;h++)m+=b,f[h]=Math.cos(m),g[h]=Math.sin(m);for(c=0;s.length>c;c++){var d=verb.eval.geom.closest_point_on_ray(s[c],e,r),p=numeric.sub(s[c],d),y=numeric.norm2(p),x=crossprod(r,p);y>verb.EPSILON&&(p=numeric.mul(1/y,p),x=numeric.mul(1/y,x)),v[0][c]=s[c];var k=s[c];l[0][c]=a[c];for(var N=x,E=0,m=0,h=1;u>=h;h++){var M=0==y?d:numeric.add(d,numeric.mul(y,f[h],p),numeric.mul(y,g[h],x));v[E+2][c]=M,l[E+2][c]=a[c];var w=numeric.sub(numeric.mul(f[h],x),numeric.mul(g[h],p));if(0==y)v[E+1][c]=d;else{var z=verb.eval.geom.intersect_rays(k,numeric.mul(1/numeric.norm2(N),N),M,numeric.mul(1/numeric.norm2(w),w)),A=numeric.add(k,numeric.mul(N,z[0]));v[E+1][c]=A}l[E+1][c]=_*a[c],E+=2,u>h&&(k=M,N=w)}}return{knots_u:o,knots_v:t,control_points:v,degree_u:2,degree_v:i,weights:l}},verb.eval.nurbs.get_arc=function(e,r,n,t,i,s){return verb.eval.nurbs.get_ellipse_arc(e,r,n,t,t,i,s)},verb.eval.nurbs.curve_knot_insert=function(e,r,n,t,i,s){var a=(n[0].length,r.length-e-2),u=n.length,o=verb.eval.nurbs.knot_span(e,t,r),v=a+e+1,l=u+s,b=Array(e+1),c=Array(r.length+s),h=Array(l),_=0;for(_=0;o>=_;_++)c[_]=r[_];for(_=1;s>=_;_++)c[o+_]=t;for(_=o+1;v>=_;_++)c[_+s]=r[_];for(_=0;o-e>=_;_++)h[_]=n[_];for(_=o-i;a>=_;_++)h[_+s]=n[_];for(_=0;e-i>=_;_++)b[_]=n[o-e+1];for(var m=0,g=0,f=1;s>=f;f++){for(m=o-e+f,_=0;e-f-i>=_;_++)g=(t-r[m+_])/(r[_+o+1]-r[m+_]),b[_]=numeric.add(numeric.mul(g,b[_+1]),numeric.mul(1-g,b[_]));h[m]=b[0],h[o+s-f-i]=b[e-f-i]}for(_=m+1;o-i>_;_++)h[_]=b[_-m];return[c,h]},verb.eval.nurbs.rational_surface_derivs=function(e,r,n,t,i,s,a,u){var o=verb.eval.nurbs.surface_derivs(e,r,n,t,i,s,a,u),v=verb.eval.nurbs.separate_homo_derivs_2d(o),l=v[0],b=v[1],c=0,h=0,_=0,m=0,g=[],f=l[0][0].length;for(c=0;s>=c;c++)for(g.push([]),m=0;s-c>=m;m++){var u=l[c][m];for(_=1;m>=_;_++)u=numeric.sub(u,numeric.mul(numeric.mul(binomial.get(m,_),b[0][_]),g[c][m-_]));for(h=1;c>=h;h++){u=numeric.sub(u,numeric.mul(numeric.mul(binomial.get(c,h),b[h][0]),g[c-h][m]));var d=verb.eval.nurbs.zeros_1d(f);for(_=1;m>=_;_++)d=numeric.add(d,numeric.mul(numeric.mul(binomial.get(m,_),b[h][_]),g[c-h][m-_]));u=numeric.sub(u,numeric.mul(binomial.get(c,h),d))}g[c].push(numeric.mul(1/b[0][0],u))}return g},verb.eval.nurbs.rational_surface_point=function(e,r,n,t,i,s,a){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.surface_point(e,r,n,t,i,s,a))},verb.eval.nurbs.rational_curve_derivs=function(e,r,n,t,i){var s=verb.eval.nurbs.separate_homo_derivs_1d(verb.eval.nurbs.curve_derivs(e,r,n,t,i)),a=s[0],u=s[1],o=0,v=0,l=[];for(o=0;i>=o;o++){var b=a[o];for(v=1;o>=v;v++)b=numeric.sub(b,numeric.mul(numeric.mul(binomial.get(o,v),u[v]),l[o-v]));l.push(numeric.mul(1/u[0],b))}return l},verb.eval.nurbs.separate_homo_derivs_1d=function(e){for(var r=e[0].length,n=r-1,t=[],i=[],s=0,a=e.length;a>s;s++)t.push(e[s].slice(0,n)),i.push(e[s][n]);return[t,i]},verb.eval.nurbs.separate_homo_derivs_2d=function(e){for(var r=[],n=[],t=0,i=e.length;i>t;t++){var s=verb.eval.nurbs.separate_homo_derivs_1d(e[t]);r.push(s[0]),n.push(s[1])}return[r,n]},verb.eval.nurbs.rational_curve_point=function(e,r,n,t){return verb.eval.nurbs.dehomogenize(verb.eval.nurbs.curve_point(e,r,n,t))},verb.eval.nurbs.dehomogenize=function(e){for(var r=e.length,n=[],t=e[r-1],i=0;e.length-1>i;i++)n.push(e[i]/t);return n},verb.eval.nurbs.homogenize_1d=function(e,r){for(var n=e.length,t=e[0].length,i=0,s=[],a=0,u=[],o=0;n>o;o++){var v=[];for(u=e[o],a=r[o],i=0;t>i;i++)v.push(u[i]*a);v.push(a),s.push(v)}return s},verb.eval.nurbs.homogenize_2d=function(e,r){for(var n=e.length,t=(e[0].length,e[0][0].length,[]),i=0;n>i;i++)t.push(verb.eval.nurbs.homogenize_1d(e[i],r[i]));return t},verb.eval.nurbs.rational_surface_curvature=function(e,r,n,t,i,s,a){var u=verb.eval.nurbs.rational_surface_derivs(e,r,n,t,i,2,s,a),o=u[0][1],v=u[1][0],l=u[0][2],b=u[2][0],c=u[1][1],h=numeric.cross(o,v),_=numeric.dot(l,h),m=numeric.dot(c,h),g=numeric.dot(b,h),f=[[_,m],[m,g]],d=numeric.eig(f),p=d.lambda.x[0],y=d.lambda.x[1],x=.5*(p+y),k=p*y,N=numeric.add(numeric.mul(d.E.x[0][0],o),numeric.mul(d.E.x[0][1],v)),E=numeric.add(numeric.mul(d.E.x[1][0],o),numeric.mul(d.E.x[1][1],v));return{point:u[0][0],normal:h,mean:x,gaussian:k,shapeOperator:f,k1:p,k2:y,p1:N,p2:E,p1p:d.E.x[0],p2p:d.E.x[1]}},verb.eval.nurbs.surface_derivs=function(e,r,n,t,i,s,a,u){var o=r.length-e-2,v=t.length-n-2;return verb.eval.nurbs.surface_derivs_given_n_m(o,e,r,v,n,t,i,s,a,u)},verb.eval.nurbs.surface_derivs_given_n_m=function(e,r,n,t,i,s,a,u,o,v){if(verb.eval.nurbs.are_valid_relations(r,a.length,n.length)===!1||verb.eval.nurbs.are_valid_relations(i,a[0].length,s.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var l=a[0][0].length,b=Math.min(u,r),c=Math.min(u,i),h=verb.eval.nurbs.zeros_3d(b+1,c+1,l),_=verb.eval.nurbs.knot_span_given_n(e,r,o,n),m=verb.eval.nurbs.knot_span_given_n(t,i,v,s),g=verb.eval.nurbs.deriv_basis_functions_given_n_i(_,o,r,e,n),f=verb.eval.nurbs.deriv_basis_functions_given_n_i(m,v,i,t,s),d=verb.eval.nurbs.zeros_2d(i+1,l),p=0,y=0,x=0,k=0,N=0;for(p=0;b>=p;p++){for(y=0;i>=y;y++)for(d[y]=verb.eval.nurbs.zeros_1d(l),x=0;r>=x;x++)d[y]=numeric.add(d[y],numeric.mul(g[p][x],a[_-r+x][m-i+y]));for(N=Math.min(u-p,c),k=0;N>=k;k++)for(h[p][k]=verb.eval.nurbs.zeros_1d(l),y=0;i>=y;y++)h[p][k]=numeric.add(h[p][k],numeric.mul(f[k][y],d[y]))}return h},verb.eval.nurbs.surface_point=function(e,r,n,t,i,s,a){var u=r.length-e-2,o=t.length-n-2;return verb.eval.nurbs.surface_point_given_n_m(u,e,r,o,n,t,i,s,a)},verb.eval.nurbs.volume_point=function(e,r,n,t,i,s,a,u,o,v){var l=r.length-e-2,b=t.length-n-2,c=s.length-i-2;return verb.eval.nurbs.volume_point_given_n_m_l(l,e,r,b,n,t,c,i,s,a,u,o,v)},verb.eval.nurbs.volume_point_given_n_m_l=function(e,r,n,t,i,s,a,u,o,v,l,b,c){if(!verb.eval.nurbs.are_valid_relations(r,v.length,n.length)||!verb.eval.nurbs.are_valid_relations(i,v[0].length,s.length)||!verb.eval.nurbs.are_valid_relations(u,v[0][0].length,o.length))return console.error("Invalid relations between control points and knot vector"),null;for(var h=v[0][0][0].length,_=verb.eval.nurbs.knot_span_given_n(e,r,l,n),m=verb.eval.nurbs.knot_span_given_n(t,i,b,s),g=verb.eval.nurbs.knot_span_given_n(a,u,c,o),f=verb.eval.nurbs.basis_functions_given_knot_span_index(_,l,r,n),d=verb.eval.nurbs.basis_functions_given_knot_span_index(m,b,i,s),p=verb.eval.nurbs.basis_functions_given_knot_span_index(g,c,u,o),y=_-r,x=m,k=g,N=verb.eval.nurbs.zeros_1d(h),E=verb.eval.nurbs.zeros_1d(h),M=verb.eval.nurbs.zeros_1d(h),w=0,z=0,A=0;u>=A;A++){for(M=verb.eval.nurbs.zeros_1d(h),k=g-u+A,w=0;i>=w;w++){for(E=verb.eval.nurbs.zeros_1d(h),x=m-i+w,z=0;r>=z;z++)E=numeric.add(E,numeric.mul(f[z],v[y+z][x][k]));M=numeric.add(M,numeric.mul(d[w],E))}N=numeric.add(N,numeric.mul(p[A],M))}return N},verb.eval.nurbs.surface_point_given_n_m=function(e,r,n,t,i,s,a,u,o){if(verb.eval.nurbs.are_valid_relations(r,a.length,n.length)===!1||verb.eval.nurbs.are_valid_relations(i,a[0].length,s.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var v=a[0][0].length,l=verb.eval.nurbs.knot_span_given_n(e,r,u,n),b=verb.eval.nurbs.knot_span_given_n(t,i,o,s),c=verb.eval.nurbs.basis_functions_given_knot_span_index(l,u,r,n),h=verb.eval.nurbs.basis_functions_given_knot_span_index(b,o,i,s),_=l-r,m=b,g=verb.eval.nurbs.zeros_1d(v),f=verb.eval.nurbs.zeros_1d(v),d=0,p=0;for(d=0;i>=d;d++){for(f=verb.eval.nurbs.zeros_1d(v),m=b-i+d,p=0;r>=p;p++)f=numeric.add(f,numeric.mul(c[p],a[_+p][m]));g=numeric.add(g,numeric.mul(h[d],f))}return g},verb.eval.nurbs.curve_derivs=function(e,r,n,t,i){var s=r.length-e-2;return verb.eval.nurbs.curve_derivs_given_n(s,e,r,n,t,i)},verb.eval.nurbs.curve_derivs_given_n=function(e,r,n,t,i,s){if(verb.eval.nurbs.are_valid_relations(r,t.length,n.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;var a=t[0].length,u=Math.min(s,r),o=verb.eval.nurbs.zeros_2d(u+1,a),v=verb.eval.nurbs.knot_span_given_n(e,r,i,n),l=verb.eval.nurbs.deriv_basis_functions_given_n_i(v,i,r,u,n),b=0,c=0;for(b=0;u>=b;b++)for(c=0;r>=c;c++)o[b]=numeric.add(o[b],numeric.mul(l[b][c],t[v-r+c]));return o},verb.eval.nurbs.are_valid_relations=function(e,r,n){return 0===r+e+1-n?!0:!1},verb.eval.nurbs.curve_point=function(e,r,n,t){var i=r.length-e-2;return verb.eval.nurbs.curve_point_given_n(i,e,r,n,t)},verb.eval.nurbs.curve_point_given_n=function(e,r,n,t,i){if(verb.eval.nurbs.are_valid_relations(r,t.length,n.length)===!1)return console.error("Invalid relations between control points, knot vector, and n"),null;for(var s=verb.eval.nurbs.knot_span_given_n(e,r,i,n),a=verb.eval.nurbs.basis_functions_given_knot_span_index(s,i,r,n),u=verb.eval.nurbs.zeros_1d(t[0].length),o=0;r>=o;o++)u=numeric.add(u,numeric.mul(a[o],t[s-r+o]));return u},verb.eval.nurbs.zeros_1d=function(e){e=e>0?e:0;for(var r=[];e--;)r.push(0);return r},verb.eval.nurbs.zeros_2d=function(e,r){r=r>0?r:0,e=e>0?e:0;for(var n=[],t=r,i=e;e--;){for(n.push([]);t--;)n[i-e-1].push(0);t=r}return n},verb.eval.nurbs.zeros_3d=function(e,r,n){r=r>0?r:0,e=e>0?e:0;for(var t=[],i=r,s=e;e--;){for(t.push([]);i--;)t[s-e-1].push(verb.eval.nurbs.zeros_1d(n));i=r}return t},verb.eval.nurbs.deriv_basis_functions=function(e,r,n){var t=verb.eval.nurbs.knot_span(r,e,n),i=n.length-1,s=i-r-1;return verb.eval.nurbs.deriv_basis_functions_given_n_i(t,e,r,s,n)},verb.eval.nurbs.deriv_basis_functions_given_n_i=function(e,r,n,t,i){var s=verb.eval.nurbs.zeros_2d(n+1,n+1),a=Array(n+1),u=Array(n+1),o=0,v=0,l=1,b=0;for(s[0][0]=1,l=1;n>=l;l++){for(a[l]=r-i[e+1-l],u[l]=i[e+l]-r,o=0,b=0;l>b;b++)s[l][b]=u[b+1]+a[l-b],v=s[b][l-1]/s[l][b],s[b][l]=o+u[b+1]*v,o=a[l-b]*v;s[l][l]=o}var c=verb.eval.nurbs.zeros_2d(t+1,n+1),h=verb.eval.nurbs.zeros_2d(2,n+1),_=1,m=0,g=1,f=0,d=0,p=0,y=0,x=0;for(l=0;n>=l;l++)c[0][l]=s[l][n];for(b=0;n>=b;b++)for(m=0,g=1,h[0][0]=1,_=1;t>=_;_++){for(f=0,d=b-_,p=n-_,b>=_&&(h[g][0]=h[m][0]/s[p+1][d],f=h[g][0]*s[d][p]),y=d>=-1?1:-d,x=p>=b-1?_-1:n-b,l=y;x>=l;l++)h[g][l]=(h[m][l]-h[m][l-1])/s[p+1][d+l],f+=h[g][l]*s[d+l][p];
+p>=b&&(h[g][_]=-h[m][_-1]/s[p+1][b],f+=h[g][_]*s[b][p]),c[_][b]=f,l=m,m=g,g=l}for(b=n,_=1;t>=_;_++){for(l=0;n>=l;l++)c[_][l]*=b;b*=n-_}return c},verb.eval.nurbs.basis_functions=function(e,r,n){var t=verb.eval.nurbs.knot_span(e,r,n);return verb.eval.nurbs.basis_functions_given_knot_span_index(t,e,r,n)},verb.eval.nurbs.basis_functions_given_knot_span_index=function(e,r,n,t){var i=Array(n+1),s=Array(n+1),a=Array(n+1),u=0,o=0;i[0]=1;for(var v=1;n>=v;v++){s[v]=r-t[e+1-v],a[v]=t[e+v]-r,u=0;for(var l=0;v>l;l++)o=i[l]/(a[l+1]+s[v-l]),i[l]=u+a[l+1]*o,u=s[v-l]*o;i[v]=u}return i},verb.eval.nurbs.knot_span=function(e,r,n){var t=n.length-1,i=t-e-1;return verb.eval.nurbs.knot_span_given_n(i,e,r,n)},verb.eval.nurbs.knot_span_given_n=function(e,r,n,t){if(n>=t[e+1])return e;if(t[r]>n)return r;for(var i=r,s=e+1,a=Math.floor((i+s)/2);t[a]>n||n>=t[a+1];)t[a]>n?s=a:i=a,a=Math.floor((i+s)/2);return a};
View
1,419 docs/verb.html
1,100 additions, 319 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
90 src/eval/eval.js
@@ -1,4 +1,94 @@
+//
+// ####surface_curvature( degree_u, knots_u, degree_v, knots_v, control_points, u, v, options )
+//
+// Compute the gaussian curvature on a non-uniform, non-rational B spline surface
+//
+// **params**
+// + *Number*, integer degree of surface in u direction
+// + *Array*, array of nondecreasing knot values in u direction
+// + *Number*, integer degree of surface in v direction
+// + *Array*, array of nondecreasing knot values in v direction
+// + *Array*, 3d array of control points, where rows are the u dir, and columns run alonsg the positive v direction,
+// and where each control point is an array of length (dim)
+// + *Number*, u parameter at which to evaluate the derivatives
+// + *Number*, v parameter at which to evaluate the derivatives
+//
+// **returns**
+// + *Array*, a point represented by an array of length (dim)
+//
+
+verb.eval.nurbs.rational_surface_curvature = function( degree_u, knots_u, degree_v, knots_v, homo_control_points, u, v ) {
+
+ // compute the first fundamental form
+
+ // symmetric matrix where
+ //
+ // I = [ E F; F G ]
+ //
+ // where:
+ //
+ // E = Xu * Xu
+ // F = Xu * Xv
+ // G = Xv * Xv
+
+ // second fundamental form (shape operator)
+
+ // symmetric matrix where
+ //
+ // II = [ L M; M N ]
+ //
+ // where:
+ //
+ // L = Xuu * n
+ // M = Xuv * n
+ // N = Xvv * n
+
+ // principal curvatures are the eigenvalues of the second fundamental form
+
+ var derivs = verb.eval.nurbs.rational_surface_derivs( degree_u,
+ knots_u,
+ degree_v,
+ knots_v,
+ homo_control_points,
+ 2, u, v );
+
+ // structure of the derivatives
+
+ // pos du vuu
+ // dv duv
+ // dvv
+
+
+ var du = derivs[0][1];
+ var dv = derivs[1][0];
+ var duu = derivs[0][2];
+ var dvv = derivs[2][0];
+ var duv = derivs[1][1];
+
+ var n = numeric.cross( du, dv );
+ var L = numeric.dot( duu, n );
+ var M = numeric.dot( duv, n );
+ var N = numeric.dot( dvv, n );
+
+ var shapeOperator = [ [ L, M ], [ M, N ] ];
+
+ var eigs = numeric.eig( shapeOperator );
+
+ // contains: lambda - x
+ // E - x
+
+ var k1 = eigs.lambda.x[0];
+ var k2 = eigs.lambda.x[1];
+ var mean = 0.5 * ( k1 + k2 );
+ var gaussian = k1 * k2;
+ var p1 = numeric.add( numeric.mul( eigs.E.x[0][0], du ), numeric.mul( eigs.E.x[0][1], dv ) );
+ var p2 = numeric.add( numeric.mul( eigs.E.x[1][0], du ), numeric.mul( eigs.E.x[1][1], dv ) );
+
+ return { point: derivs[0][0], normal: n, mean: mean, gaussian: gaussian, shapeOperator: shapeOperator, k1: k1, k2: k2, p1: p1, p2: p2, p1p : eigs.E.x[0], p2p: eigs.E.x[1] };
+
+};
+
//
// ####curve_knot_insert( degree, knots, control_points, u, s, r )
View
22 src/eval/geom.js
@@ -314,28 +314,28 @@ verb.eval.nurbs.get_cone_surface = function( axis, xaxis, base, height, radius )
verb.eval.nurbs.get_extruded_surface = function( axis, length, prof_knots, prof_degree, prof_control_points, prof_weights){
- var control_points = verb.eval.nurbs.zeros_2d( 2, prof_control_points.length )
- , weights = verb.eval.nurbs.zeros_2d( 2, prof_control_points.length );
+ var control_points = verb.eval.nurbs.zeros_2d( 3, prof_control_points.length )
+ , weights = verb.eval.nurbs.zeros_2d( 3, prof_control_points.length );
+
+ var translation = numeric.mul(axis, length);
+ var halfTranslation = numeric.mul(axis, 0.5 * length);
// original control points
for (var j = 0; j < prof_control_points.length; j++){
control_points[0][j] = prof_control_points[j];
- weights[0][j] = prof_weights[j];
- }
-
- // build translated control points
- var translation = numeric.mul(axis, length);
+ control_points[1][j] = numeric.add( halfTranslation, prof_control_points[j] );
+ control_points[2][j] = numeric.add( translation, prof_control_points[j] );
- for (var j = 0; j < prof_control_points.length; j++){
- control_points[1][j] = numeric.add( translation, prof_control_points[j] );
+ weights[0][j] = prof_weights[j];
weights[1][j] = prof_weights[j];
+ weights[2][j] = prof_weights[j];
}
// return all parameters
- return {"knots_u": [0,0,1,1],
+ return {"knots_u": [0,0,0,1,1,1],
"knots_v": prof_knots,
"control_points": control_points,
- "degree_u": 1,
+ "degree_u": 2,
"degree_v": prof_degree,
"weights": weights };
}
View
140 src/eval/tesselate.js
@@ -346,7 +346,7 @@ verb.eval.nurbs.divide_rational_surface_adaptive = function( degree_u, knots_u,
, v0 = min_v + v_interval * j
, v1 = min_v + v_interval * (j + 1);
- divs.push( new AdaptiveRefinementNode( srf, u0, u1, v0, v1, null, null ) );
+ divs.push( new verb.eval.nurbs.AdaptiveRefinementNode( srf, u0, u1, v0, v1, null, null ) );
}
}
@@ -412,7 +412,46 @@ verb.eval.nurbs.unique_mesh = function( mesh ) {
}
-function AdaptiveRefinementNode( srf, u0, u1, v0, v1, parentNode, neighbors ) {
+
+Array.prototype.where = function( predicate ){
+
+ if (this.length === 0) return this;
+
+ var res = [];
+
+ for (var i = 0; i < this.length; i++){
+ if ( predicate( this[i] ) ) res.push( this[i] );
+ }
+
+ return res;
+
+}
+
+verb.eval.nurbs.AdaptiveRefinementNode = function( srf, u0, u1, v0, v1, parentNode, neighbors ) {
+
+ //
+ // Structure of the child nodes
+ // in the adaptive refinement tree
+ //
+ // +--> u
+ // |
+ // v
+ // v
+ //
+ // neighbors[0]
+ //
+ // (u0,v0)---(u05,v0)---(u1,v0)
+ // | | |
+ // | 0 | 1 |
+ // | | |
+ // neighbors[3] (u0,v05)--(u05,v05)--(u1,v05) neighbors[1]
+ // | | |
+ // | 3 | 2 |
+ // | | |
+ // (u0,v1)---(u05,v1)---(u1,v1)
+ //
+ // neighbors[2]
+ //
this.srf = srf;
this.u0 = u0;
@@ -426,11 +465,12 @@ function AdaptiveRefinementNode( srf, u0, u1, v0, v1, parentNode, neighbors ) {
}
-AdaptiveRefinementNode.prototype.isLeaf = function(){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.isLeaf = function(){
return (this.children === undefined);
};
-AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
+
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
var derivs = verb.eval.nurbs.rational_surface_derivs( this.srf.degree_u,
this.srf.knots_u,
@@ -450,54 +490,43 @@ AdaptiveRefinementNode.prototype.evalSurface = function( uv ){
};
-Array.prototype.where = function( predicate ){
- if (length === 0) return this;
-
- var res = [];
-
- for (var i = 0; i < this.length; i++){
- if ( predicate( this[i] ) ) res.push( res[i] );
- }
-
- return res;
-
-}
-
-AdaptiveRefinementNode.prototype.getEdgeUvs = function( edgeIndex ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.getEdgeUvs = function( edgeIndex ){
// if its a leaf, there are no children to obtain uvs from
- if ( this.isLeaf() ) return this.leafEdgeUvs[ edgeIndex ];
+ if ( this.isLeaf() ) return [ this.leafEdgeUvs[ edgeIndex ] ]
// get the uvs owned by the children along this edge
this.cachedEdgeUvs[edgeIndex] = this.cachedEdgeUvs[edgeIndex] || this.children[ edgeIndex ].getEdgeUvs( edgeIndex )
.concat( this.children[ (edgeIndex + 1) % 4 ].getEdgeUvs( edgeIndex ));
return this.cachedEdgeUvs[edgeIndex];
};
-AdaptiveRefinementNode.prototype.getAllEdgeUvs = function( edgeIndex ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.getAllEdgeUvs = function( edgeIndex ){
- var baseArr = [ leafEdgeUvs[edgeIndex] ];
+ var baseArr = [ this.leafEdgeUvs[edgeIndex] ];
- if (this.neighbors[edgeIndex] === null) return baseArr;
+ if ( this.neighbors[edgeIndex] === null ) return baseArr;
// get opposite edges uvs
var uvs = this.neighbors[edgeIndex].getEdgeUvs( ( edgeIndex + 2 ) % 4 );
var funcIndex = edgeIndex % 2;
+ var that = this;
+
// range clipping functions
var rangeFuncMap = [
- function(x){ return x[0] > u0 + verb.EPSILON && x[0] < u1 - verb.EPSILON; },
- function(x){ return x[1] > v0 + verb.EPSILON && x[1] < v1 - verb.EPSILON; }
+ function(x){ return x[0] > that.u0 + verb.EPSILON && x[0] < that.u1 - verb.EPSILON; },
+ function(x){ return x[1] > that.v0 + verb.EPSILON && x[1] < that.v1 - verb.EPSILON; }
];
// clip the range of uvs to match this one
- return baseArr.concat( uvs.slice(0).reverse().where( rangeFuncMap[ funcIndex ] ) ) ;
+ return baseArr.concat( uvs.where( rangeFuncMap[ funcIndex ] ).reverse() ) ;
};
-AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
var baseIndex = mesh.points.length - 1;
@@ -552,7 +581,7 @@ AdaptiveRefinementNode.prototype.triangulateLeaf = function( mesh ){
};
-AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
if ( this.isLeaf() ) return this.triangulateLeaf( mesh );
@@ -564,44 +593,37 @@ AdaptiveRefinementNode.prototype.triangulate = function( mesh ){
};
-AdaptiveRefinementNode.prototype.divide = function( options ){
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.shouldDivide = function( options, currentDepth ){
- //
- // Structure of the child nodes
- // in the adaptive refinement tree
- //
- // +--> u
- // |
- // v
- // v
- //
- // neighbors[0]
- //
- // (u0,v0)---(u05,v0)---(u1,v0)
- // | | |
- // | 0 | 1 |
- // | | |
- // neighbors[3] (u0,v05)--(u05,v05)--(u1,v05) neighbors[1]
- // | | |
- // | 3 | 2 |
- // | | |
- // (u0,v1)---(u05,v1)---(u1,v1)
- //
- // neighbors[2]
- //
+ if ( ( options.minDepth && currentDepth < options.minDepth ) ){
+ return true;
+ } else if ( this.srf && !verb.eval.nurbs.is_rational_surface_domain_flat( this.srf, this.u0, this.u1, this.v0, this.v1, options ) ){
+ return true;
+ }
- if ( verb.eval.nurbs.is_rational_surface_domain_flat( this.srf, this.u0, this.u1, this.v0, this.v1, options ) )
- return;
+ return false;
- // divide the domain
+}
+verb.eval.nurbs.AdaptiveRefinementNode.prototype.divide = function( options, currentDepth ){
+
+ // initialize currentDepth if it's not present
+ if (currentDepth === undefined) currentDepth = 0;
+
+ if ( !this.shouldDivide( options, currentDepth ) ) return;
+
+ // increment the depth
+ currentDepth++;
+
+ // divide the domain
this.u05 = (this.u0 + this.u1) / 2;
this.v05 = (this.v0 + this.v1) / 2;
- this.children = [ new AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v0, this.v05, this ),
- new AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v0, this.v05, this ),
- new AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v05, this.v1, this ),
- new AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v05, this.v1, this ) ];
+ // create the children
+ this.children = [ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v0, this.v05, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v0, this.v05, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u05, this.u1, this.v05, this.v1, this ),
+ new verb.eval.nurbs.AdaptiveRefinementNode( this.srf, this.u0, this.u05, this.v05, this.v1, this ) ];
// correctly assign neighbors
this.children[0].neighbors = [ this.neighbors[0], this.children[1], this.children[3], this.neighbors[3] ];
@@ -610,7 +632,7 @@ AdaptiveRefinementNode.prototype.divide = function( options ){
this.children[3].neighbors = [ this.children[0], this.children[2], this.neighbors[2], this.neighbors[3] ];
// divide all children recursively
- this.children.forEach(function(x){ x.divide( options ); });
+ this.children.forEach(function(x){ x.divide( options,currentDepth ); })
};
View
195 test/test.js
@@ -1575,7 +1575,7 @@ describe("verb.eval.nurbs.get_cylinder_surface",function(){
var comps = verb.eval.nurbs.get_cylinder_surface(axis, xaxis, base, height, radius);
- comps.degree_u.should.equal(1);
+ comps.degree_u.should.equal(2);
comps.degree_v.should.equal(2);
// sample at the center
@@ -4266,55 +4266,164 @@ describe("verb.eval.nurbs.volume_point",function(){
});
-describe("AdaptiveRefinementNode.constructor",function(){
+describe("verb.eval.nurbs.AdaptiveRefinementNode.constructor",function(){
it('can be instantiated', function(){
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, "a", "b" );
+
+ f.u0.should.be.equal(0);
+ f.u1.should.be.equal(1);
+ f.v0.should.be.equal(0);
+ f.v1.should.be.equal(1);
+ f.parentNode.should.be.equal("a");
+ f.neighbors.should.be.equal("b");
+ f.leafEdgeUvs.length.should.be.equal(4);
+ f.cachedEdgeUvs.length.should.be.equal(0);
});
});
-describe("AdaptiveRefinementNode.getEdgeUvs",function(){
+describe("verb.eval.nurbs.AdaptiveRefinementNode.getEdgeUvs",function(){
+
+ it('returns expected result for node without children', function(){
- it('returns expected result for node with children', function(){
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, null, null );
+ f.getEdgeUvs( 0 ).should.be.eql( [[0,0]] );
+ f.getEdgeUvs( 1 ).should.be.eql( [[1,0]] );
+ f.getEdgeUvs( 2 ).should.be.eql( [[1,1]] );
+ f.getEdgeUvs( 3 ).should.be.eql( [[0,1]] );
});
- it('returns expected result for node with children', function(){
+ it('returns expected result for node with singly children', function(){
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, null, [null, null, null, null] );
+
+ f.divide({ minDepth : 1 });
+ f.children.length.should.be.equal( 4 );
+
+ f.getEdgeUvs(0).should.be.eql( [ [ 0, 0 ], [ 0.5, 0 ] ] );
+ f.getEdgeUvs(1).should.be.eql( [ [ 1, 0 ], [ 1, 0.5 ] ] );
+ f.getEdgeUvs(2).should.be.eql( [ [ 1, 1 ], [ 0.5, 1 ] ] );
+ f.getEdgeUvs(3).should.be.eql( [ [ 0, 1 ], [ 0, 0.5 ] ] );
+
+ });
+
+ it('returns expected result for node with singly children', function(){
+
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, null, [null, null, null, null] );
+
+ f.divide({ minDepth : 2 });
+ f.children.length.should.be.equal( 4 );
+
+ f.getEdgeUvs(0).should.be.eql( [ [ 0, 0 ], [ 0.25, 0 ], [ 0.5, 0 ], [ 0.75, 0 ] ] );
+ f.getEdgeUvs(1).should.be.eql( [ [ 1, 0 ], [ 1, 0.25 ], [ 1, 0.5 ], [ 1, 0.75 ] ] );
+ f.getEdgeUvs(2).should.be.eql( [ [ 1, 1 ], [ 0.75, 1 ], [ 0.5, 1 ], [ 0.25, 1 ] ] );
+ f.getEdgeUvs(3).should.be.eql( [ [ 0, 1 ], [ 0, 0.75 ], [ 0, 0.5 ], [ 0, 0.25 ] ] );
});
});
-describe("AdaptiveRefinementNode.getAllEdgeUvs",function(){
+describe("verb.eval.nurbs.AdaptiveRefinementNode.getAllEdgeUvs",function(){
- it('returns expected result for edge with neighbors that with a large number of vertices on opposite side', function(){
+ it('returns expected result for edge with more vertices on opposite side', function(){
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, null, [null, null, null, null] );
+ f.divide({ minDepth : 1 }); // now f is split in 4
+ f.children[0].divide({ minDepth : 1 }); // f[0] is split in 4
+ f.children[1].divide({ minDepth : 1 }); // f[1] is split in 4
+ f.children[1].children[3].divide({ minDepth : 1 }); // f[1][3] is split in 4
+
+ f.children[0].getAllEdgeUvs(1).should.eql( [ [ 0.5, 0 ], [ 0.5, 0.25 ], [ 0.5, 0.375 ] ] );
+ f.children[0].children[2].getAllEdgeUvs(2).should.eql( [ [ 0.5, 0.5 ] ] );
+
});
it('returns expected result for edge with neighbors that has with lesser number of vertices on opposite side', function(){
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, null, [null, null, null, null] );
+
+ f.divide({ minDepth : 1 }); // now f is split in 4
+ f.children[0].divide({ minDepth : 1 }); // f[0] is split in 4
+ f.children[1].divide({ minDepth : 1 }); // f[1] is split in 4
+ f.children[1].children[3].divide({ minDepth : 1 }); // f[1][3] is split in 4
+
+ f.children[1].children[3].children[3].getAllEdgeUvs(3).should.eql( [ [ 0.5, 0.5 ] ] );
});
});
-describe("AdaptiveRefinementNode.divide",function(){
+describe("verb.eval.nurbs.rational_surface_curvature ",function(){
- it('can be called with no options provided', function(){
+ it('returns expected result for cylinder', function(){
+
+ verb.init();
+
+ var axis = [0,0,1]
+ , xaxis = [1,0,0]
+ , base = [0,0,0]
+ , height = 1
+ , radius = 1;
+
+ var srf = new verb.geom.Cylinder( axis, xaxis, base, height, radius );
+
+ var res = verb.eval.nurbs.rational_surface_curvature( srf.get('degreeU'),
+ srf.get('knotsU'),
+ srf.get('degreeV'),
+ srf.get('knotsV'),
+ srf.homogenize(),
+ 0.5, 0.5 );
+
+ res.point[0].should.be.approximately( -1, verb.TOLERANCE );
+ res.point[1].should.be.approximately( 0, verb.TOLERANCE );
+ res.point[2].should.be.approximately( 0.5, verb.TOLERANCE );
+
+ res.normal[0].should.be.approximately( -5.656854, verb.TOLERANCE );
+ res.normal[1].should.be.approximately( 0, verb.TOLERANCE );
+ res.normal[2].should.be.approximately( 0, verb.TOLERANCE );
+
+ res.mean.should.be.lessThan( 0 );
+ res.gaussian.should.be.approximately( 0, verb.TOLERANCE );
+
+ res.p1[0].should.be.approximately( 0, verb.TOLERANCE );
+ res.p1[1].should.be.approximately( -5.656854249, verb.TOLERANCE );
+ res.p1[2].should.be.approximately( 0, verb.TOLERANCE );
+
+ res.p2[0].should.be.approximately( 0, verb.TOLERANCE );
+ res.p2[1].should.be.approximately( 0, verb.TOLERANCE );
+ res.p2[2].should.be.approximately( 1, verb.TOLERANCE );
+
+ res.k1.should.be.approximately( -181.01933598, verb.TOLERANCE );
+ res.k2.should.be.approximately( 0, verb.TOLERANCE );
});
+});
+
+describe("verb.eval.nurbs.AdaptiveRefinementNode.divide",function(){
+
+ it('can be called with options.minDepth', function(){
+
+ var f = new verb.eval.nurbs.AdaptiveRefinementNode(null, 0, 1, 0, 1, null, [null, null, null, null] );
+
+ f.divide({ minDepth : 2 });
+ f.children.length.should.be.equal( 4 );
+
+ });
+
it('can be called with no options provided', function(){
+
});
it('can produce a non-uniformly nested tree', function(){
@@ -4326,84 +4435,84 @@ describe("AdaptiveRefinementNode.divide",function(){
});
-describe("AdaptiveRefinementNode.triangulate",function(){
+// describe("verb.eval.nurbs.AdaptiveRefinementNode.triangulate",function(){
- it('can triangulate a leaf with no edges', function(){
+// it('can triangulate a leaf with no edges', function(){
- });
+// });
- it('can triangulate a node with children', function(){
+// it('can triangulate a node with children', function(){
- });
+// });
- it('can triangulate a node with children and un-nested neighbors', function(){
+// it('can triangulate a node with children and un-nested neighbors', function(){
- });
+// });
- it('can triangulate a node with children and equally nested neighbors', function(){
+// it('can triangulate a node with children and equally nested neighbors', function(){
- });
+// });
- it('can triangulate a node with children and more nested neighbors', function(){
+// it('can triangulate a node with children and more nested neighbors', function(){
- });
+// });
-});
+// });
-describe("AdaptiveRefinementNode.evalSurface",function(){
+// describe("verb.eval.nurbs.AdaptiveRefinementNode.evalSurface",function(){
- it('works as expected', function(){
+// it('works as expected', function(){
- });
+// });
-});
+// });
-describe("verb.eval.nurbs.divide_rational_surface_adaptive",function(){
+// describe("verb.eval.nurbs.divide_rational_surface_adaptive",function(){
- it('divides the domain according to minDivsU, minDivsV', function(){
+// it('divides the domain according to minDivsU, minDivsV', function(){
- });
+// });
-});
+// });
-describe("verb.eval.nurbs.is_rational_surface_domain_flat",function(){
+// describe("verb.eval.nurbs.is_rational_surface_domain_flat",function(){
- it('evaluates as expected for different tolerances', function(){
+// it('evaluates as expected for different tolerances', function(){
- });
+// });
-});
+// });
-describe("verb.eval.nurbs.triangulate_adaptive_refinement_node_tree",function(){
+// describe("verb.eval.nurbs.triangulate_adaptive_refinement_node_tree",function(){
- it('produces a mesh from a uniform divided surface', function(){
+// it('produces a mesh from a uniform divided surface', function(){
- });
+// });
- it('produces a mesh from a non-uniformly divided surface', function(){
+// it('produces a mesh from a non-uniformly divided surface', function(){
- });
+// });
-});
+// });
-describe("verb.eval.nurbs.tesselate_rational_surface_adaptive",function(){
+// describe("verb.eval.nurbs.tesselate_rational_surface_adaptive",function(){
- it('produces a mesh from a divided surface', function(){
+// it('produces a mesh from a divided surface', function(){
- });
+// });
-});
+// });

0 comments on commit 02e43ac

Please sign in to comment.
Something went wrong with that request. Please try again.