@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 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=[],s=e=>{const s=t.findIndex(t=>vec2.equals(t,e));return s<0?(t.push(e),e):t[s]},o=[];return e.forEach(e=>{o.push([s(e[0]),s(e[1])])}),o},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;
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,i)=>{let[n,o,r]=i,s=Math.sqrt(n*n+o*o+r*r);if(Math.abs(s)<EPSILON)return identity(t);n*=s=1/s,o*=s,r*=s;const a=Math.sin(e),u=Math.cos(e),c=1-u;return t[0]=n*n*c+u,t[1]=o*n*c+r*a,t[2]=r*n*c-o*a,t[3]=0,t[4]=n*o*c-r*a,t[5]=o*o*c+u,t[6]=r*o*c+n*a,t[7]=0,t[8]=n*r*c+o*a,t[9]=o*r*c-n*a,t[10]=r*r*c+u,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t};module.exports=fromRotation;
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,o,r)=>{let[a,s,c]=r,n=Math.sqrt(a*a+s*s+c*c);if(Math.abs(n)<1e-6)return copy(t,e);a*=n=1/n,s*=n,c*=n;const h=Math.sin(o),p=Math.cos(o),u=1-p,M=e[0],i=e[1],y=e[2],l=e[3],q=e[4],b=e[5],d=e[6],f=e[7],m=e[8],x=e[9],g=e[10],j=e[11],k=a*a*u+p,v=s*a*u+c*h,w=c*a*u-s*h,z=a*s*u-c*h,A=s*s*u+p,B=c*s*u+a*h,C=a*c*u+s*h,D=s*c*u-a*h,E=c*c*u+p;return t[0]=M*k+q*v+m*w,t[1]=i*k+b*v+x*w,t[2]=y*k+d*v+g*w,t[3]=l*k+f*v+j*w,t[4]=M*z+q*A+m*B,t[5]=i*z+b*A+x*B,t[6]=y*z+d*A+g*B,t[7]=l*z+f*A+j*B,t[8]=M*C+q*D+m*E,t[9]=i*C+b*D+x*E,t[10]=y*C+d*D+g*E,t[11]=l*C+f*D+j*E,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t};module.exports=rotate;
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,a)=>{const o=t[0],e=t[1],r=t[2],n=a[0],s=a[1],h=a[2],M=Math.sqrt(o*o+e*e+r*r)*Math.sqrt(n*n+s*s+h*h),d=M&&dot(t,a)/M;return Math.acos(Math.min(Math.max(d,-1),1))};module.exports=angle;
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:r,frequency:t}=Object.assign({},{radius:1,frequency:6},e);if(!isGT(r,0))throw new Error("radius must be greater than zero");if(!isGTE(t,6))throw new Error("frequency must be six or more");t=Math.floor(t/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,r,t)=>{const o=e[0],s=e[1],n=e[2];let c=t;const a=[],f=[];for(let e=0;e<r;e++)for(let t=0;t<r-e;t++){const l=e/r,u=(e+1)/r,h=t/(r-e),m=(t+1)/(r-e),p=r-e-1?t/(r-e-1):1,g=[];g[0]=i(i(o,s,h),n,l),g[1]=i(i(o,s,m),n,l),g[2]=i(i(o,s,p),n,u);for(let e=0;e<3;e++){const r=Math.sqrt(g[e][0]*g[e][0]+g[e][1]*g[e][1]+g[e][2]*g[e][2]);for(let t=0;t<3;t++)g[e][t]/=r}if(a.push(g[0],g[1],g[2]),f.push([c,c+1,c+2]),c+=3,t<r-e-1){const h=r-e-1?(t+1)/(r-e-1):1;g[0]=i(i(o,s,m),n,l),g[1]=i(i(o,s,h),n,u),g[2]=i(i(o,s,p),n,u);for(let e=0;e<3;e++){const r=Math.sqrt(g[e][0]*g[e][0]+g[e][1]*g[e][1]+g[e][2]*g[e][2]);for(let t=0;t<3;t++)g[e][t]/=r}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,r,t)=>{const o=1-t,s=[];for(let n=0;n<3;n++)s[n]=e[n]*o+r[n]*t;return s};let c=[],a=[],f=0;for(let e=0;e<s.length;e++){const r=n([o[s[e][0]],o[s[e][1]],o[s[e][2]]],t,f);c=c.concat(r.points),a=a.concat(r.triangles),f=r.offset}let l=polyhedron({points:c,faces:a,orientation:"inward"});return 1!==r&&(l=geom3.transform(mat4.fromScaling(mat4.create(),[r,r,r]),l)),l};module.exports=geodesicSphere;
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.1",
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": "c8ac21281a7acf5a5575b940c18353c598ffa1a4"
63
+ "gitHead": "b6c5675d2d9a292e0ba24896bf22d0e9dc5d4270"
64
64
  }
@@ -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
@@ -3,6 +3,7 @@
3
3
  * @param {Number} p
4
4
  * @param {Number} q
5
5
  * @param {Number} t
6
+ * @return {Number} color component
6
7
  * @alias module:modeling/colors.hueToColorComponent
7
8
  */
8
9
  const hueToColorComponent = (p, q, t) => {
@@ -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
- * @returns {array | number} the tangent at the requested position.
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 uniquevertices = []
10
+ const vertices = {}
11
11
  const getUniqueVertex = (vertex) => {
12
- const i = uniquevertices.findIndex((v) => vec2.equals(v, vertex))
13
- if (i < 0) {
14
- uniquevertices.push(vertex)
15
- return vertex
12
+ const key = vertex.toString()
13
+ if (!vertices[key]) {
14
+ vertices[key] = vertex
16
15
  }
17
- return uniquevertices[i]
16
+ return vertices[key]
18
17
  }
19
18
 
20
- const edges = []
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
- * @params {geom3} geometry - the geometry to invert
9
- * @returns {geom3} a new geometry
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.sqrt(x * x + y * y + z * z)
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))
@@ -12,7 +12,7 @@ const copy = require('./copy')
12
12
  */
13
13
  const rotate = (out, matrix, radians, axis) => {
14
14
  let [x, y, z] = axis
15
- let len = Math.sqrt(x * x + y * y + z * z)
15
+ let len = Math.hypot(x, y, z)
16
16
 
17
17
  if (Math.abs(len) < 0.000001) {
18
18
  // axis is 0,0,0 or almost
@@ -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
  })
@@ -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.sqrt(ax * ax + ay * ay + az * az)
19
- const mag2 = Math.sqrt(bx * bx + by * by + bz * bz)
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 {Array} [options.height=1] the height of the extrusion
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} objects - the geometries to mirror
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.sqrt(q[k][0] * q[k][0] + q[k][1] * q[k][1] + q[k][2] * q[k][2])
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.sqrt(q[k][0] * q[k][0] + q[k][1] * q[k][1] + q[k][2] * q[k][2])
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 {Array} [options.height=2] - height of cylinder
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
- return false
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 + ')')