@jscad/modeling 2.7.1 → 2.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/jscad-modeling.min.js +5 -5
- package/package.json +2 -2
- package/src/colors/hslToRgb.js +1 -1
- package/src/colors/hueToColorComponent.js +1 -0
- package/src/curves/bezier/tangentAt.js +2 -2
- package/src/geometries/geom2/toOutlines.js +6 -11
- package/src/geometries/geom3/invert.js +2 -2
- package/src/geometries/geom3/toPoints.js +1 -0
- package/src/maths/mat4/fromRotation.js +1 -1
- package/src/maths/mat4/isIdentity.test.js +0 -2
- package/src/maths/mat4/rotate.js +1 -1
- package/src/maths/vec2/length.test.js +10 -0
- package/src/maths/vec3/angle.js +2 -2
- package/src/maths/vec3/angle.test.js +17 -0
- package/src/maths/vec3/length.test.js +10 -0
- package/src/operations/booleans/retessellate.js +1 -3
- package/src/operations/extrusions/extrudeLinear.js +1 -1
- package/src/operations/hulls/quickhull/QuickHull.js +2 -2
- package/src/operations/modifiers/edges.js +1 -3
- package/src/operations/modifiers/generalize.js +3 -6
- package/src/operations/transforms/mirror.js +1 -1
- package/src/primitives/geodesicSphere.js +2 -2
- package/src/primitives/roundedCylinder.js +1 -1
- package/test/helpers/comparePolygons.js +1 -3
- package/test/helpers/nearlyEqual.js +2 -6
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.7.2](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/modeling@2.7.1...@jscad/modeling@2.7.2) (2022-02-19)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* **modeling:** changed geom2.toOutlines to use a map when creating unique edges ([#997](https://github.com/jscad/OpenJSCAD.org/issues/997)) ([338065f](https://github.com/jscad/OpenJSCAD.org/commit/338065fa37041a41e66cbe648ba2080239f3db97))
|
|
12
|
+
* **modeling:** Use hypot instead of sqrt when possible ([#996](https://github.com/jscad/OpenJSCAD.org/issues/996)) ([113c636](https://github.com/jscad/OpenJSCAD.org/commit/113c636b1ac33e351c97789eb6ce0a546365141e))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
## [2.7.1](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/modeling@2.7.0...@jscad/modeling@2.7.1) (2021-12-26)
|
|
7
19
|
|
|
8
20
|
|
|
@@ -74,7 +74,7 @@ const create=require("./create"),toSides=require("./toSides"),reverse=e=>{const
|
|
|
74
74
|
const toCompactBinary=o=>{const t=o.sides,r=o.transforms;let n=[-1,-1,-1,-1];o.color&&(n=o.color);const e=new Float32Array(21+4*t.length);e[0]=0,e[1]=r[0],e[2]=r[1],e[3]=r[2],e[4]=r[3],e[5]=r[4],e[6]=r[5],e[7]=r[6],e[8]=r[7],e[9]=r[8],e[10]=r[9],e[11]=r[10],e[12]=r[11],e[13]=r[12],e[14]=r[13],e[15]=r[14],e[16]=r[15],e[17]=n[0],e[18]=n[1],e[19]=n[2],e[20]=n[3];for(let o=0;o<t.length;o++){const r=4*o+21,n=t[o][0],s=t[o][1];e[r+0]=n[0],e[r+1]=n[1],e[r+2]=s[0],e[r+3]=s[1]}return e};module.exports=toCompactBinary;
|
|
75
75
|
|
|
76
76
|
},{}],26:[function(require,module,exports){
|
|
77
|
-
const vec2=require("../../maths/vec2"),toSides=require("./toSides"),toEdges=e=>{const t=
|
|
77
|
+
const vec2=require("../../maths/vec2"),toSides=require("./toSides"),toEdges=e=>{const t={},s=e=>{const s=e.toString();return t[s]||(t[s]=e),t[s]};return e.map(e=>e.map(s))},toOutlines=e=>{const t=new Map;toEdges(toSides(e)).forEach(e=>{t.has(e[0])||t.set(e[0],[]),t.get(e[0]).push(e)});const s=[];for(;;){let e;for(const[s,o]of t){if(e=o.shift())break;t.delete(s)}if(void 0===e)break;const o=[],r=e[0],n=vec2.create();for(;;){o.push(e[0]);const s=e[1];if(s===r)break;const c=t.get(s);if(!c)throw new Error("the given geometry is not closed. verify proper construction");let i=-1;if(1===c.length)i=0;else{let t;const s=vec2.angleDegrees(vec2.subtract(n,e[1],e[0]));for(let e=0;e<c.length;e++){const o=c[e];let r=vec2.angleDegrees(vec2.subtract(n,o[1],o[0]))-s;r<-180&&(r+=360),r>=180&&(r-=360),(i<0||r>t)&&(i=e,t=r)}}const l=c[i];c.splice(i,1),0===c.length&&t.delete(s),e=l}o.length>0&&o.push(o.shift()),s.push(o)}return t.clear(),s};module.exports=toOutlines;
|
|
78
78
|
|
|
79
79
|
},{"../../maths/vec2":183,"./toSides":28}],27:[function(require,module,exports){
|
|
80
80
|
const toSides=require("./toSides"),toPoints=t=>{const o=toSides(t).map(t=>t[0]);return o.length>0&&o.push(o.shift()),o};module.exports=toPoints;
|
|
@@ -377,7 +377,7 @@ const create=()=>[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];module.exports=create;
|
|
|
377
377
|
const equals=(e,s)=>e[0]===s[0]&&e[1]===s[1]&&e[2]===s[2]&&e[3]===s[3]&&e[4]===s[4]&&e[5]===s[5]&&e[6]===s[6]&&e[7]===s[7]&&e[8]===s[8]&&e[9]===s[9]&&e[10]===s[10]&&e[11]===s[11]&&e[12]===s[12]&&e[13]===s[13]&&e[14]===s[14]&&e[15]===s[15];module.exports=equals;
|
|
378
378
|
|
|
379
379
|
},{}],127:[function(require,module,exports){
|
|
380
|
-
const identity=require("./identity"),{EPSILON:EPSILON}=require("./constants"),fromRotation=(t,e
|
|
380
|
+
const identity=require("./identity"),{EPSILON:EPSILON}=require("./constants"),fromRotation=(t,o,e)=>{let[i,n,r]=e,a=Math.hypot(i,n,r);if(Math.abs(a)<EPSILON)return identity(t);i*=a=1/a,n*=a,r*=a;const s=Math.sin(o),h=Math.cos(o),u=1-h;return t[0]=i*i*u+h,t[1]=n*i*u+r*s,t[2]=r*i*u-n*s,t[3]=0,t[4]=i*n*u-r*s,t[5]=n*n*u+h,t[6]=r*n*u+i*s,t[7]=0,t[8]=i*r*u+n*s,t[9]=n*r*u-i*s,t[10]=r*r*u+h,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t};module.exports=fromRotation;
|
|
381
381
|
|
|
382
382
|
},{"./constants":123,"./identity":136}],128:[function(require,module,exports){
|
|
383
383
|
const fromScaling=(o,c)=>(o[0]=c[0],o[1]=0,o[2]=0,o[3]=0,o[4]=0,o[5]=c[1],o[6]=0,o[7]=0,o[8]=0,o[9]=0,o[10]=c[2],o[11]=0,o[12]=0,o[13]=0,o[14]=0,o[15]=1,o);module.exports=fromScaling;
|
|
@@ -428,7 +428,7 @@ const mirrorByPlane=(r,o)=>{const[e,n,t,l]=o;return r[0]=1-2*e*e,r[1]=-2*n*e,r[2
|
|
|
428
428
|
const multiply=(t,l,e)=>{const o=l[0],u=l[1],m=l[2],n=l[3],p=l[4],r=l[5],s=l[6],c=l[7],i=l[8],y=l[9],d=l[10],x=l[11],a=l[12],b=l[13],f=l[14],g=l[15];let h=e[0],j=e[1],k=e[2],q=e[3];return t[0]=h*o+j*p+k*i+q*a,t[1]=h*u+j*r+k*y+q*b,t[2]=h*m+j*s+k*d+q*f,t[3]=h*n+j*c+k*x+q*g,h=e[4],j=e[5],k=e[6],q=e[7],t[4]=h*o+j*p+k*i+q*a,t[5]=h*u+j*r+k*y+q*b,t[6]=h*m+j*s+k*d+q*f,t[7]=h*n+j*c+k*x+q*g,h=e[8],j=e[9],k=e[10],q=e[11],t[8]=h*o+j*p+k*i+q*a,t[9]=h*u+j*r+k*y+q*b,t[10]=h*m+j*s+k*d+q*f,t[11]=h*n+j*c+k*x+q*g,h=e[12],j=e[13],k=e[14],q=e[15],t[12]=h*o+j*p+k*i+q*a,t[13]=h*u+j*r+k*y+q*b,t[14]=h*m+j*s+k*d+q*f,t[15]=h*n+j*c+k*x+q*g,t};module.exports=multiply;
|
|
429
429
|
|
|
430
430
|
},{}],144:[function(require,module,exports){
|
|
431
|
-
const copy=require("./copy"),rotate=(t,e,
|
|
431
|
+
const copy=require("./copy"),rotate=(t,o,e,r)=>{let[a,c,s]=r,h=Math.hypot(a,c,s);if(Math.abs(h)<1e-6)return copy(t,o);a*=h=1/h,c*=h,s*=h;const n=Math.sin(e),p=Math.cos(e),u=1-p,y=o[0],M=o[1],i=o[2],l=o[3],b=o[4],d=o[5],f=o[6],m=o[7],q=o[8],x=o[9],g=o[10],j=o[11],k=a*a*u+p,v=c*a*u+s*n,w=s*a*u-c*n,z=a*c*u-s*n,A=c*c*u+p,B=s*c*u+a*n,C=a*s*u+c*n,D=c*s*u-a*n,E=s*s*u+p;return t[0]=y*k+b*v+q*w,t[1]=M*k+d*v+x*w,t[2]=i*k+f*v+g*w,t[3]=l*k+m*v+j*w,t[4]=y*z+b*A+q*B,t[5]=M*z+d*A+x*B,t[6]=i*z+f*A+g*B,t[7]=l*z+m*A+j*B,t[8]=y*C+b*D+q*E,t[9]=M*C+d*D+x*E,t[10]=i*C+f*D+g*E,t[11]=l*C+m*D+j*E,o!==t&&(t[12]=o[12],t[13]=o[13],t[14]=o[14],t[15]=o[15]),t};module.exports=rotate;
|
|
432
432
|
|
|
433
433
|
},{"./copy":124}],145:[function(require,module,exports){
|
|
434
434
|
const rotateX=(t,o,e)=>{const r=Math.sin(e),s=Math.cos(e),a=o[4],n=o[5],c=o[6],h=o[7],u=o[8],M=o[9],X=o[10],d=o[11];return o!==t&&(t[0]=o[0],t[1]=o[1],t[2]=o[2],t[3]=o[3],t[12]=o[12],t[13]=o[13],t[14]=o[14],t[15]=o[15]),t[4]=a*s+u*r,t[5]=n*s+M*r,t[6]=c*s+X*r,t[7]=h*s+d*r,t[8]=u*s-a*r,t[9]=M*s-n*r,t[10]=X*s-c*r,t[11]=d*s-h*r,t};module.exports=rotateX;
|
|
@@ -602,7 +602,7 @@ const abs=(a,s)=>(a[0]=Math.abs(s[0]),a[1]=Math.abs(s[1]),a[2]=Math.abs(s[2]),a)
|
|
|
602
602
|
const add=(d,o,a)=>(d[0]=o[0]+a[0],d[1]=o[1]+a[1],d[2]=o[2]+a[2],d);module.exports=add;
|
|
603
603
|
|
|
604
604
|
},{}],202:[function(require,module,exports){
|
|
605
|
-
const dot=require("./dot"),angle=(t,
|
|
605
|
+
const dot=require("./dot"),angle=(t,o)=>{const a=t[0],e=t[1],h=t[2],n=o[0],r=o[1],M=o[2],d=Math.hypot(a,e,h)*Math.hypot(n,r,M),s=d&&dot(t,o)/d;return Math.acos(Math.min(Math.max(s,-1),1))};module.exports=angle;
|
|
606
606
|
|
|
607
607
|
},{"./dot":209}],203:[function(require,module,exports){
|
|
608
608
|
const create=require("./create"),clone=e=>{const r=create();return r[0]=e[0],r[1]=e[1],r[2]=e[2],r};module.exports=clone;
|
|
@@ -1070,7 +1070,7 @@ const{EPS:EPS}=require("../maths/constants"),vec2=require("../maths/vec2"),geom2
|
|
|
1070
1070
|
const vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),ellipsoid=e=>{const{center:c,radius:a,segments:r,axes:s}=Object.assign({},{center:[0,0,0],radius:[1,1,1],segments:32,axes:[[1,0,0],[0,-1,0],[0,0,1]]},e);if(!isNumberArray(c,3))throw new Error("center must be an array of X, Y and Z values");if(!isNumberArray(a,3))throw new Error("radius must be an array of X, Y and Z values");if(!a.every(e=>e>0))throw new Error("radius values must be greater than zero");if(!isGTE(r,4))throw new Error("segments must be four or more");const t=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),s[0]),a[0]),v=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),s[1]),a[1]),o=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),s[2]),a[2]),l=Math.round(r/4);let u;const d=[],i=vec3.create(),n=vec3.create();for(let e=0;e<=r;e++){const a=2*Math.PI*e/r,s=vec3.add(vec3.create(),vec3.scale(i,t,Math.cos(a)),vec3.scale(n,v,Math.sin(a)));if(e>0){let e,a;for(let r=0;r<=l;r++){const t=.5*Math.PI*r/l,v=Math.cos(t),m=Math.sin(t);if(r>0){let t,h=[];t=vec3.subtract(vec3.create(),vec3.scale(i,u,e),vec3.scale(n,o,a)),h.push(vec3.add(t,t,c)),t=vec3.subtract(vec3.create(),vec3.scale(i,s,e),vec3.scale(n,o,a)),h.push(vec3.add(t,t,c)),r<l&&(t=vec3.subtract(vec3.create(),vec3.scale(i,s,v),vec3.scale(n,o,m)),h.push(vec3.add(t,t,c))),t=vec3.subtract(vec3.create(),vec3.scale(i,u,v),vec3.scale(n,o,m)),h.push(vec3.add(t,t,c)),d.push(poly3.fromPoints(h)),h=[],t=vec3.add(vec3.create(),vec3.scale(i,u,e),vec3.scale(n,o,a)),h.push(vec3.add(vec3.create(),c,t)),t=vec3.add(t,vec3.scale(i,s,e),vec3.scale(n,o,a)),h.push(vec3.add(vec3.create(),c,t)),r<l&&(t=vec3.add(t,vec3.scale(i,s,v),vec3.scale(n,o,m)),h.push(vec3.add(vec3.create(),c,t))),t=vec3.add(t,vec3.scale(i,u,v),vec3.scale(n,o,m)),h.push(vec3.add(vec3.create(),c,t)),h.reverse(),d.push(poly3.fromPoints(h))}e=v,a=m}}u=s}return geom3.create(d)};module.exports=ellipsoid;
|
|
1071
1071
|
|
|
1072
1072
|
},{"../geometries/geom3":36,"../geometries/poly3":73,"../maths/vec3":214,"./commonChecks":351}],358:[function(require,module,exports){
|
|
1073
|
-
const mat4=require("../maths/mat4"),geom3=require("../geometries/geom3"),polyhedron=require("./polyhedron"),{isGT:isGT,isGTE:isGTE}=require("./commonChecks"),geodesicSphere=e=>{let{radius:
|
|
1073
|
+
const mat4=require("../maths/mat4"),geom3=require("../geometries/geom3"),polyhedron=require("./polyhedron"),{isGT:isGT,isGTE:isGTE}=require("./commonChecks"),geodesicSphere=e=>{let{radius:t,frequency:r}=Object.assign({},{radius:1,frequency:6},e);if(!isGT(t,0))throw new Error("radius must be greater than zero");if(!isGTE(r,6))throw new Error("frequency must be six or more");r=Math.floor(r/6);const o=[[.850651,0,-.525731],[.850651,-0,.525731],[-.850651,-0,.525731],[-.850651,0,-.525731],[0,-.525731,.850651],[0,.525731,.850651],[0,.525731,-.850651],[0,-.525731,-.850651],[-.525731,-.850651,-0],[.525731,-.850651,-0],[.525731,.850651,0],[-.525731,.850651,0]],s=[[0,9,1],[1,10,0],[6,7,0],[10,6,0],[7,9,0],[5,1,4],[4,1,9],[5,10,1],[2,8,3],[3,11,2],[2,5,4],[4,8,2],[2,11,5],[3,7,6],[6,11,3],[8,7,3],[9,8,4],[11,10,5],[10,11,6],[8,9,7]],n=(e,t,r)=>{const o=e[0],s=e[1],n=e[2];let c=r;const a=[],f=[];for(let e=0;e<t;e++)for(let r=0;r<t-e;r++){const l=e/t,h=(e+1)/t,u=r/(t-e),m=(r+1)/(t-e),p=t-e-1?r/(t-e-1):1,g=[];g[0]=i(i(o,s,u),n,l),g[1]=i(i(o,s,m),n,l),g[2]=i(i(o,s,p),n,h);for(let e=0;e<3;e++){const t=Math.hypot(g[e][0],g[e][1],g[e][2]);for(let r=0;r<3;r++)g[e][r]/=t}if(a.push(g[0],g[1],g[2]),f.push([c,c+1,c+2]),c+=3,r<t-e-1){const u=t-e-1?(r+1)/(t-e-1):1;g[0]=i(i(o,s,m),n,l),g[1]=i(i(o,s,u),n,h),g[2]=i(i(o,s,p),n,h);for(let e=0;e<3;e++){const t=Math.hypot(g[e][0],g[e][1],g[e][2]);for(let r=0;r<3;r++)g[e][r]/=t}a.push(g[0],g[1],g[2]),f.push([c,c+1,c+2]),c+=3}}return{points:a,triangles:f,offset:c}},i=(e,t,r)=>{const o=1-r,s=[];for(let n=0;n<3;n++)s[n]=e[n]*o+t[n]*r;return s};let c=[],a=[],f=0;for(let e=0;e<s.length;e++){const t=n([o[s[e][0]],o[s[e][1]],o[s[e][2]]],r,f);c=c.concat(t.points),a=a.concat(t.triangles),f=t.offset}let l=polyhedron({points:c,faces:a,orientation:"inward"});return 1!==t&&(l=geom3.transform(mat4.fromScaling(mat4.create(),[t,t,t]),l)),l};module.exports=geodesicSphere;
|
|
1074
1074
|
|
|
1075
1075
|
},{"../geometries/geom3":36,"../maths/mat4":137,"./commonChecks":351,"./polyhedron":362}],359:[function(require,module,exports){
|
|
1076
1076
|
module.exports={arc:require("./arc"),circle:require("./circle"),cube:require("./cube"),cuboid:require("./cuboid"),cylinder:require("./cylinder"),cylinderElliptic:require("./cylinderElliptic"),ellipse:require("./ellipse"),ellipsoid:require("./ellipsoid"),geodesicSphere:require("./geodesicSphere"),line:require("./line"),polygon:require("./polygon"),polyhedron:require("./polyhedron"),rectangle:require("./rectangle"),roundedCuboid:require("./roundedCuboid"),roundedCylinder:require("./roundedCylinder"),roundedRectangle:require("./roundedRectangle"),sphere:require("./sphere"),square:require("./square"),star:require("./star"),torus:require("./torus"),triangle:require("./triangle")};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/modeling",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.2",
|
|
4
4
|
"description": "Constructive Solid Geometry (CSG) Library for JSCAD",
|
|
5
5
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"nyc": "15.1.0",
|
|
61
61
|
"uglifyify": "5.0.2"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "b6c5675d2d9a292e0ba24896bf22d0e9dc5d4270"
|
|
64
64
|
}
|
package/src/colors/hslToRgb.js
CHANGED
|
@@ -5,7 +5,7 @@ const hueToColorComponent = require('./hueToColorComponent')
|
|
|
5
5
|
/**
|
|
6
6
|
* Converts HSL color values to RGB color values.
|
|
7
7
|
*
|
|
8
|
-
* @see http://en.wikipedia.org/wiki/HSL_color_space
|
|
8
|
+
* @see http://en.wikipedia.org/wiki/HSL_color_space
|
|
9
9
|
* @param {...Number|Array} values - HSL or HSLA color values
|
|
10
10
|
* @return {Array} RGB or RGBA color values
|
|
11
11
|
* @alias module:modeling/colors.hslToRgb
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* See the example called extrudeAlongPath.js
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
|
-
* const b = bezier.create([0,0,0], [0,5,10], [10,0,-5], [10,10,10]]) // a cubic 3 dimensional easing curve that can generate position arrays for modelling
|
|
7
|
+
* const b = bezier.create([[0,0,0], [0,5,10], [10,0,-5], [10,10,10]]) // a cubic 3 dimensional easing curve that can generate position arrays for modelling
|
|
8
8
|
* let tangent = bezier.tangentAt(t, b)
|
|
9
9
|
*
|
|
10
10
|
* @param {number} t : the position of which to calculate the bezier's tangent value; 0 < t < 1
|
|
11
11
|
* @param {Object} bezier : an array with at least 2 elements of either all numbers, or all arrays of numbers that are the same size.
|
|
12
|
-
* @
|
|
12
|
+
* @return {array | number} the tangent at the requested position.
|
|
13
13
|
* @alias module:modeling/curves/bezier.tangentAt
|
|
14
14
|
*/
|
|
15
15
|
const tangentAt = (t, bezier) => {
|
|
@@ -7,21 +7,16 @@ const toSides = require('./toSides')
|
|
|
7
7
|
* This allows the edges to be traversed in order.
|
|
8
8
|
*/
|
|
9
9
|
const toEdges = (sides) => {
|
|
10
|
-
const
|
|
10
|
+
const vertices = {}
|
|
11
11
|
const getUniqueVertex = (vertex) => {
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
return vertex
|
|
12
|
+
const key = vertex.toString()
|
|
13
|
+
if (!vertices[key]) {
|
|
14
|
+
vertices[key] = vertex
|
|
16
15
|
}
|
|
17
|
-
return
|
|
16
|
+
return vertices[key]
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
sides.forEach((side) => {
|
|
22
|
-
edges.push([getUniqueVertex(side[0]), getUniqueVertex(side[1])])
|
|
23
|
-
})
|
|
24
|
-
return edges
|
|
19
|
+
return sides.map((side) => side.map(getUniqueVertex))
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
/**
|
|
@@ -5,8 +5,8 @@ const toPolygons = require('./toPolygons')
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Invert the given geometry, transposing solid and empty space.
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
8
|
+
* @param {geom3} geometry - the geometry to invert
|
|
9
|
+
* @return {geom3} a new geometry
|
|
10
10
|
* @alias module:modeling/geometries/geom3.invert
|
|
11
11
|
*/
|
|
12
12
|
const invert = (geometry) => {
|
|
@@ -5,6 +5,7 @@ const toPolygons = require('./toPolygons')
|
|
|
5
5
|
/**
|
|
6
6
|
* Return the given geometry as a list of points, after applying transforms.
|
|
7
7
|
* The returned array should not be modified as the points are shared with the geometry.
|
|
8
|
+
* @param {geom3} geometry - the geometry
|
|
8
9
|
* @return {Array} list of points, where each sub-array represents a polygon
|
|
9
10
|
* @alias module:modeling/geometries/geom3.toPoints
|
|
10
11
|
*/
|
|
@@ -19,7 +19,7 @@ const { EPSILON } = require('./constants')
|
|
|
19
19
|
*/
|
|
20
20
|
const fromRotation = (out, rad, axis) => {
|
|
21
21
|
let [x, y, z] = axis
|
|
22
|
-
let len = Math.
|
|
22
|
+
let len = Math.hypot(x, y, z)
|
|
23
23
|
|
|
24
24
|
if (Math.abs(len) < EPSILON) {
|
|
25
25
|
// axis is 0,0,0 or almost
|
|
@@ -2,8 +2,6 @@ const test = require('ava')
|
|
|
2
2
|
|
|
3
3
|
const { isIdentity, create, fromTranslation } = require('./index')
|
|
4
4
|
|
|
5
|
-
const { compareVectors } = require('../../../test/helpers/index')
|
|
6
|
-
|
|
7
5
|
test('mat4: isIdentity() should return correct values', (t) => {
|
|
8
6
|
const identity = create() // identity matrix
|
|
9
7
|
t.true(isIdentity(identity))
|
package/src/maths/mat4/rotate.js
CHANGED
|
@@ -25,5 +25,15 @@ test('vec2: length() should return correct values', (t) => {
|
|
|
25
25
|
const length5 = length(vec5)
|
|
26
26
|
nearlyEqual(t, length5, 2.23606, EPS)
|
|
27
27
|
|
|
28
|
+
// huge vector
|
|
29
|
+
const vec6 = fromValues(1e200, 1e200)
|
|
30
|
+
const length6 = length(vec6)
|
|
31
|
+
nearlyEqual(t, length6, Math.SQRT2 * 1e200, EPS)
|
|
32
|
+
|
|
33
|
+
// tiny vector
|
|
34
|
+
const vec7 = fromValues(1e-200, 1e-200)
|
|
35
|
+
const length7 = length(vec7)
|
|
36
|
+
nearlyEqual(t, length7, Math.SQRT2 * 1e-200, EPS)
|
|
37
|
+
|
|
28
38
|
t.true(true)
|
|
29
39
|
})
|
package/src/maths/vec3/angle.js
CHANGED
|
@@ -15,8 +15,8 @@ const angle = (a, b) => {
|
|
|
15
15
|
const bx = b[0]
|
|
16
16
|
const by = b[1]
|
|
17
17
|
const bz = b[2]
|
|
18
|
-
const mag1 = Math.
|
|
19
|
-
const mag2 = Math.
|
|
18
|
+
const mag1 = Math.hypot(ax, ay, az)
|
|
19
|
+
const mag2 = Math.hypot(bx, by, bz)
|
|
20
20
|
const mag = mag1 * mag2
|
|
21
21
|
const cosine = mag && dot(a, b) / mag
|
|
22
22
|
return Math.acos(Math.min(Math.max(cosine, -1), 1))
|
|
@@ -25,5 +25,22 @@ test('vec3: angle() should return correct values', (t) => {
|
|
|
25
25
|
const angle4 = angle(veca4, vec4)
|
|
26
26
|
nearlyEqual(t, angle4, 3.14159, EPS)
|
|
27
27
|
|
|
28
|
+
const vec5a = fromValues(1, 0, 0)
|
|
29
|
+
const vec5b = fromValues(1, 1, 0)
|
|
30
|
+
const angle5 = angle(vec5a, vec5b)
|
|
31
|
+
nearlyEqual(t, angle5, 0.785398, EPS)
|
|
32
|
+
|
|
33
|
+
// tiny values
|
|
34
|
+
const vec6a = fromValues(1, 0, 0)
|
|
35
|
+
const vec6b = fromValues(1e-200, 1e-200, 0)
|
|
36
|
+
const angle6 = angle(vec6a, vec6b)
|
|
37
|
+
nearlyEqual(t, angle6, 0.785398, EPS)
|
|
38
|
+
|
|
39
|
+
// huge values
|
|
40
|
+
const vec7a = fromValues(1, 0, 0)
|
|
41
|
+
const vec7b = fromValues(1e200, 1e200, 0)
|
|
42
|
+
const angle7 = angle(vec7a, vec7b)
|
|
43
|
+
nearlyEqual(t, angle7, 0.785398, EPS)
|
|
44
|
+
|
|
28
45
|
t.true(true)
|
|
29
46
|
})
|
|
@@ -41,5 +41,15 @@ test('vec3: length() should return correct values', (t) => {
|
|
|
41
41
|
const length9 = length(vec9)
|
|
42
42
|
nearlyEqual(t, length9, 3.74165, EPS)
|
|
43
43
|
|
|
44
|
+
// huge vector
|
|
45
|
+
const vec10 = fromValues(1e200, 0, 1e200)
|
|
46
|
+
const length10 = length(vec10)
|
|
47
|
+
nearlyEqual(t, length10, Math.SQRT2 * 1e200, EPS)
|
|
48
|
+
|
|
49
|
+
// tiny vector
|
|
50
|
+
const vec11 = fromValues(1e-200, 0, 1e-200)
|
|
51
|
+
const length11 = length(vec11)
|
|
52
|
+
nearlyEqual(t, length11, Math.SQRT2 * 1e-200, EPS)
|
|
53
|
+
|
|
44
54
|
t.true(true)
|
|
45
55
|
})
|
|
@@ -10,9 +10,7 @@ const reTesselateCoplanarPolygons = require('./reTesselateCoplanarPolygons')
|
|
|
10
10
|
const NEPS = 1e-13
|
|
11
11
|
|
|
12
12
|
// Compare two normals (unit vectors) for equality.
|
|
13
|
-
const aboutEqualNormals = (a, b) =>
|
|
14
|
-
return (Math.abs(a[0] - b[0]) <= NEPS && Math.abs(a[1] - b[1]) <= NEPS && Math.abs(a[2] - b[2]) <= NEPS)
|
|
15
|
-
}
|
|
13
|
+
const aboutEqualNormals = (a, b) => (Math.abs(a[0] - b[0]) <= NEPS && Math.abs(a[1] - b[1]) <= NEPS && Math.abs(a[2] - b[2]) <= NEPS)
|
|
16
14
|
|
|
17
15
|
const coplanar = (plane1, plane2) => {
|
|
18
16
|
// expect the same distance from the origin, within tolerance
|
|
@@ -7,7 +7,7 @@ const extrudeLinearGeom2 = require('./extrudeLinearGeom2')
|
|
|
7
7
|
/**
|
|
8
8
|
* Extrude the given geometry in an upward linear direction using the given options.
|
|
9
9
|
* @param {Object} options - options for extrude
|
|
10
|
-
* @param {
|
|
10
|
+
* @param {Number} [options.height=1] the height of the extrusion
|
|
11
11
|
* @param {Number} [options.twistAngle=0] the final rotation (RADIANS) about the origin of the shape (if any)
|
|
12
12
|
* @param {Integer} [options.twistSteps=1] the resolution of the twist about the axis (if any)
|
|
13
13
|
* @param {...Object} geometry - the list of geometry to extrude
|
|
@@ -722,7 +722,7 @@ class QuickHull {
|
|
|
722
722
|
for (let i = 0; i < this.newFaces.length; i += 1) {
|
|
723
723
|
const face = this.newFaces[i]
|
|
724
724
|
if (face.mark === VISIBLE) {
|
|
725
|
-
while (this.doAdjacentMerge(face, MERGE_NON_CONVEX_WRT_LARGER_FACE)) {}
|
|
725
|
+
while (this.doAdjacentMerge(face, MERGE_NON_CONVEX_WRT_LARGER_FACE)) {} // eslint-disable-line no-empty
|
|
726
726
|
}
|
|
727
727
|
}
|
|
728
728
|
|
|
@@ -733,7 +733,7 @@ class QuickHull {
|
|
|
733
733
|
const face = this.newFaces[i]
|
|
734
734
|
if (face.mark === NON_CONVEX) {
|
|
735
735
|
face.mark = VISIBLE
|
|
736
|
-
while (this.doAdjacentMerge(face, MERGE_NON_CONVEX)) {}
|
|
736
|
+
while (this.doAdjacentMerge(face, MERGE_NON_CONVEX)) {} // eslint-disable-line no-empty
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
|
|
@@ -99,9 +99,7 @@ const splitPolygon = (openedge, polygon, eps) => {
|
|
|
99
99
|
/*
|
|
100
100
|
* TBD This should be part of vec3.
|
|
101
101
|
*/
|
|
102
|
-
const almostEquals = (eps, v1, v2) =>
|
|
103
|
-
return (Math.abs(v1[0] - v2[0]) <= eps && Math.abs(v1[1] - v2[1]) <= eps && Math.abs(v1[2] - v2[2]) <= eps)
|
|
104
|
-
}
|
|
102
|
+
const almostEquals = (eps, v1, v2) => (Math.abs(v1[0] - v2[0]) <= eps && Math.abs(v1[1] - v2[1]) <= eps && Math.abs(v1[2] - v2[2]) <= eps)
|
|
105
103
|
|
|
106
104
|
const enclosedEdge = (openedge, edge, eps) => {
|
|
107
105
|
if (openedge.distance < edge.distance) {
|
|
@@ -15,15 +15,11 @@ const repairTjunctions = require('./repairTjunctions')
|
|
|
15
15
|
|
|
16
16
|
/*
|
|
17
17
|
*/
|
|
18
|
-
const generalizePath2 = (options, geometry) =>
|
|
19
|
-
return geometry
|
|
20
|
-
}
|
|
18
|
+
const generalizePath2 = (options, geometry) => geometry
|
|
21
19
|
|
|
22
20
|
/*
|
|
23
21
|
*/
|
|
24
|
-
const generalizeGeom2 = (options, geometry) =>
|
|
25
|
-
return geometry
|
|
26
|
-
}
|
|
22
|
+
const generalizeGeom2 = (options, geometry) => geometry
|
|
27
23
|
|
|
28
24
|
/*
|
|
29
25
|
*/
|
|
@@ -77,6 +73,7 @@ const generalizeGeom3 = (options, geometry) => {
|
|
|
77
73
|
* @param {Boolean} [options.simplify=false] the geometries should be simplified
|
|
78
74
|
* @param {Boolean} [options.triangulate=false] the geometries should be triangulated
|
|
79
75
|
* @param {Boolean} [options.repair=false] the geometries should be repaired
|
|
76
|
+
* @param {...Object} geometries - the geometries to generalize
|
|
80
77
|
* @return {Object|Array} the modified geometry, or a list of modified geometries
|
|
81
78
|
* @alias module:modeling/modifiers.generalize
|
|
82
79
|
*/
|
|
@@ -64,7 +64,7 @@ const mirrorY = (...objects) => mirror({ normal: [0, 1, 0] }, objects)
|
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Mirror the given object(s) about the Z axis.
|
|
67
|
-
* @param {...Object}
|
|
67
|
+
* @param {...Object} geometries - the geometries to mirror
|
|
68
68
|
* @return {Object|Array} the mirrored geometry, or a list of mirrored geometry
|
|
69
69
|
* @alias module:modeling/transforms.mirrorZ
|
|
70
70
|
*/
|
|
@@ -79,7 +79,7 @@ const geodesicSphere = (options) => {
|
|
|
79
79
|
|
|
80
80
|
// -- normalize
|
|
81
81
|
for (let k = 0; k < 3; k++) {
|
|
82
|
-
const r = Math.
|
|
82
|
+
const r = Math.hypot(q[k][0], q[k][1], q[k][2])
|
|
83
83
|
for (let l = 0; l < 3; l++) {
|
|
84
84
|
q[k][l] /= r
|
|
85
85
|
}
|
|
@@ -95,7 +95,7 @@ const geodesicSphere = (options) => {
|
|
|
95
95
|
|
|
96
96
|
// -- normalize
|
|
97
97
|
for (let k = 0; k < 3; k++) {
|
|
98
|
-
const r = Math.
|
|
98
|
+
const r = Math.hypot(q[k][0], q[k][1], q[k][2])
|
|
99
99
|
for (let l = 0; l < 3; l++) {
|
|
100
100
|
q[k][l] /= r
|
|
101
101
|
}
|
|
@@ -11,7 +11,7 @@ const { isGT, isGTE, isNumberArray } = require('./commonChecks')
|
|
|
11
11
|
* Construct a Z axis-aligned solid cylinder in three dimensional space with rounded ends.
|
|
12
12
|
* @param {Object} [options] - options for construction
|
|
13
13
|
* @param {Array} [options.center=[0,0,0]] - center of cylinder
|
|
14
|
-
* @param {
|
|
14
|
+
* @param {Number} [options.height=2] - height of cylinder
|
|
15
15
|
* @param {Number} [options.radius=1] - radius of cylinder
|
|
16
16
|
* @param {Number} [options.roundRadius=0.2] - radius of rounded edges
|
|
17
17
|
* @param {Number} [options.segments=32] - number of segments to create per full rotation
|
|
@@ -8,9 +8,7 @@ const compareVectors = require('./compareVectors')
|
|
|
8
8
|
*/
|
|
9
9
|
const comparePolygons = (poly1, poly2) => {
|
|
10
10
|
if (poly1.vertices.length === poly2.vertices.length) {
|
|
11
|
-
return poly1.vertices.reduce((valid, vertex, index) =>
|
|
12
|
-
return valid && compareVectors(poly1.vertices[index], poly2.vertices[index])
|
|
13
|
-
}, true)
|
|
11
|
+
return poly1.vertices.reduce((valid, vertex, index) => valid && compareVectors(poly1.vertices[index], poly2.vertices[index]), true)
|
|
14
12
|
}
|
|
15
13
|
return false
|
|
16
14
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Compare two numeric values for near equality.
|
|
2
2
|
// the given test is fails if the numeric values are outside the given epsilon
|
|
3
3
|
const nearlyEqual = (t, a, b, epsilon, failMessage) => {
|
|
4
|
-
// console.log('nearEqual(t,'+a+','+b+','+epsilon+')')
|
|
5
4
|
if (a === b) { // shortcut, also handles infinities and NaNs
|
|
6
5
|
return true
|
|
7
6
|
}
|
|
@@ -10,11 +9,9 @@ const nearlyEqual = (t, a, b, epsilon, failMessage) => {
|
|
|
10
9
|
const absB = Math.abs(b)
|
|
11
10
|
const diff = Math.abs(a - b)
|
|
12
11
|
if (Number.isNaN(diff)) {
|
|
13
|
-
|
|
12
|
+
failMessage = failMessage === undefined ? 'difference is not a number' : failMessage
|
|
13
|
+
t.fail(failMessage + '(' + a + ',' + b + ')')
|
|
14
14
|
}
|
|
15
|
-
// console.log(absA)
|
|
16
|
-
// console.log(absB)
|
|
17
|
-
// console.log(diff)
|
|
18
15
|
if (a === 0 || b === 0 || diff < Number.EPSILON) {
|
|
19
16
|
// a or b is zero or both are extremely close to it
|
|
20
17
|
// relative error is less meaningful here
|
|
@@ -25,7 +22,6 @@ const nearlyEqual = (t, a, b, epsilon, failMessage) => {
|
|
|
25
22
|
}
|
|
26
23
|
// use relative error
|
|
27
24
|
const relative = (diff / Math.min((absA + absB), Number.MAX_VALUE))
|
|
28
|
-
// console.log(relative)
|
|
29
25
|
if (relative > epsilon) {
|
|
30
26
|
failMessage = failMessage === undefined ? 'Numbers outside of epsilon' : failMessage
|
|
31
27
|
t.fail(failMessage + '(' + a + ',' + b + ')')
|