@jscad/modeling 2.11.1 → 2.12.0
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 +21 -0
- package/dist/jscad-modeling.min.js +25 -25
- package/package.json +2 -2
- package/src/curves/bezier/arcLengthToT.js +6 -6
- package/src/curves/bezier/arcLengthToT.test.js +25 -25
- package/src/curves/bezier/length.js +3 -5
- package/src/curves/bezier/length.test.js +2 -2
- package/src/curves/bezier/lengths.js +10 -10
- package/src/curves/bezier/lengths.test.js +3 -3
- package/src/geometries/poly2/arePointsInside.js +0 -7
- package/src/geometries/poly3/measureBoundingSphere.js +1 -2
- package/src/operations/booleans/trees/PolygonTreeNode.js +1 -1
- package/src/operations/expansions/expand.test.js +1 -1
- package/src/operations/extrusions/extrudeHelical.js +6 -7
- package/src/operations/extrusions/extrudeHelical.test.js +35 -37
- package/src/operations/extrusions/index.d.ts +1 -0
- package/src/operations/hulls/hullPoints2.js +3 -2
- package/src/operations/modifiers/index.js +1 -1
- package/src/operations/modifiers/retessellate.js +66 -27
- package/src/primitives/circle.js +2 -2
- package/src/primitives/circle.test.js +7 -0
- package/src/primitives/cube.js +2 -2
- package/src/primitives/cube.test.js +7 -0
- package/src/primitives/cuboid.js +4 -1
- package/src/primitives/cuboid.test.js +7 -0
- package/src/primitives/cylinder.js +7 -2
- package/src/primitives/cylinder.test.js +14 -0
- package/src/primitives/ellipse.js +4 -1
- package/src/primitives/ellipse.test.js +7 -0
- package/src/primitives/ellipsoid.js +4 -1
- package/src/primitives/ellipsoid.test.js +7 -0
- package/src/primitives/geodesicSphere.js +5 -2
- package/src/primitives/geodesicSphere.test.js +7 -0
- package/src/primitives/rectangle.js +4 -1
- package/src/primitives/rectangle.test.js +7 -0
- package/src/primitives/roundedCuboid.js +10 -3
- package/src/primitives/roundedCuboid.test.js +14 -0
- package/src/primitives/roundedCylinder.js +12 -5
- package/src/primitives/roundedCylinder.test.js +21 -0
- package/src/primitives/roundedRectangle.js +10 -3
- package/src/primitives/roundedRectangle.test.js +14 -0
- package/src/primitives/sphere.js +2 -2
- package/src/primitives/sphere.test.js +7 -0
- package/src/primitives/square.js +2 -2
- package/src/primitives/square.test.js +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
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.12.0](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/modeling@2.11.1...@jscad/modeling@2.12.0) (2023-06-27)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **modeling:** add missing extrudeHelical typing definition ([7f5f8e1](https://github.com/jscad/OpenJSCAD.org/commit/7f5f8e1d777ced7bc4ee5989f895ca06b30bd6d8))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **modeling:** allow zero size in primitives ([76b7369](https://github.com/jscad/OpenJSCAD.org/commit/76b73690ec2ae8000ab00a19f692569fe3595fe3))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Performance Improvements
|
|
20
|
+
|
|
21
|
+
* **modeling:** performance improvements for retessellate as part of booleans ([12157ac](https://github.com/jscad/OpenJSCAD.org/commit/12157ac886b714214223074d2f0a413c99da0a29))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
6
27
|
## [2.11.1](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/modeling@2.11.0...@jscad/modeling@2.11.1) (2023-04-30)
|
|
7
28
|
|
|
8
29
|
|
|
@@ -44,7 +44,7 @@ module.exports={create:require("./create"),valueAt:require("./valueAt"),tangentA
|
|
|
44
44
|
const lengths=require("./lengths"),length=(e,t)=>lengths(e,t)[e];module.exports=length;
|
|
45
45
|
|
|
46
46
|
},{"./lengths":16}],16:[function(require,module,exports){
|
|
47
|
-
const valueAt=require("./valueAt"),lengths=(e,r)=>{let t=0
|
|
47
|
+
const valueAt=require("./valueAt"),lengths=(e,r)=>{let t=0;const n=[0];let s=valueAt(0,r);for(let a=1;a<=e;a++){const i=valueAt(a/e,r);t+=distanceBetween(i,s),n.push(t),s=i}return n},distanceBetween=(e,r)=>{if(Number.isFinite(e)&&Number.isFinite(r))return Math.abs(e-r);if(Array.isArray(e)&&Array.isArray(r)){if(e.length!==r.length)throw new Error("The operands must have the same number of dimensions.");let t=0;for(let n=0;n<e.length;n++)t+=(r[n]-e[n])*(r[n]-e[n]);return Math.sqrt(t)}throw new Error("The operands must be of the same type, either number or array.")};module.exports=lengths;
|
|
48
48
|
|
|
49
49
|
},{"./valueAt":18}],17:[function(require,module,exports){
|
|
50
50
|
const tangentAt=(t,n)=>{if(t<0||t>1)throw new Error("Bezier tangentAt() input must be between 0 and 1");if("float_single"===n.pointType)return bezierTangent(n,n.points,t);{const e=[];for(let o=0;o<n.dimensions;o++){const r=[];for(let t=0;t<n.points.length;t++)r.push(n.points[t][o]);e.push(bezierTangent(n,r,t))}return e}},bezierTangent=function(t,n,e){const o=n.length-1;let r=0;for(let i=0;i<o;i++){const s=o*(n[i+1]-n[i]);r+=t.tangentPermutations[i]*Math.pow(1-e,o-1-i)*Math.pow(e,i)*s}return r};module.exports=tangentAt;
|
|
@@ -203,7 +203,7 @@ const mat4=require("../../maths/mat4"),transform=(t,r)=>{const s=mat4.multiply(m
|
|
|
203
203
|
const vec2=require("../../maths/vec2"),isA=require("./isA"),validate=r=>{if(!isA(r))throw new Error("invalid path2 structure");if(r.points.length>1)for(let i=0;i<r.points.length;i++)if(vec2.equals(r.points[i],r.points[(i+1)%r.points.length]))throw new Error(`path2 duplicate points ${r.points[i]}`);if(r.points.forEach(r=>{if(!r.every(Number.isFinite))throw new Error(`path2 invalid point ${r}`)}),!r.transforms.every(Number.isFinite))throw new Error(`path2 invalid transforms ${r.transforms}`)};module.exports=validate;
|
|
204
204
|
|
|
205
205
|
},{"../../maths/vec2":189,"./isA":62}],69:[function(require,module,exports){
|
|
206
|
-
const measureArea=require("./measureArea"),flip=require("./flip"),arePointsInside=(e,r)=>{if(0===e.length)return 0;const
|
|
206
|
+
const measureArea=require("./measureArea"),flip=require("./flip"),arePointsInside=(e,r)=>{if(0===e.length)return 0;const n=r.vertices;return n.length<3?0:(measureArea(r)<0&&(r=flip(r)),e.reduce((e,r)=>e+isPointInside(r,n),0)===e.length?1:0)},isPointInside=(e,r)=>{const n=r.length,t=e[0],i=e[1];let s=r[n-1],o=r[0],l=s[1]>i,u=0,a=0;for(let e=n+1;--e;){const e=o[1]>i;if(l!==e){const e=s[0]>t,r=o[0]>t;e&&r?u=!u:o[0]-(o[1]-i)*(s[0]-o[0])/(s[1]-o[1])>=t&&(u=!u)}l=e,s=o,o=r[++a]}return u};module.exports=arePointsInside;
|
|
207
207
|
|
|
208
208
|
},{"./flip":71,"./measureArea":73}],70:[function(require,module,exports){
|
|
209
209
|
const create=e=>((void 0===e||e.length<3)&&(e=[]),{vertices:e});module.exports=create;
|
|
@@ -248,9 +248,9 @@ const plane=require("./plane"),measureArea=e=>{const r=e.vertices.length;if(r<3)
|
|
|
248
248
|
const vec3=require("../../maths/vec3"),measureBoundingBox=e=>{const c=e.vertices,n=c.length,o=0===n?vec3.create():vec3.clone(c[0]),r=vec3.clone(o);for(let e=1;e<n;e++)vec3.min(o,o,c[e]),vec3.max(r,r,c[e]);return[o,r]};module.exports=measureBoundingBox;
|
|
249
249
|
|
|
250
250
|
},{"../../maths/vec3":220}],84:[function(require,module,exports){
|
|
251
|
-
const
|
|
251
|
+
const vec4=require("../../maths/vec4"),cache=new WeakMap,measureBoundingSphere=e=>{const r=cache.get(e);if(r)return r;const t=e.vertices,c=vec4.create();if(0===t.length)return c[0]=0,c[1]=0,c[2]=0,c[3]=0,c;let n=t[0],a=n,s=n,h=n,o=n,u=n;t.forEach(e=>{n[0]>e[0]&&(n=e),a[1]>e[1]&&(a=e),s[2]>e[2]&&(s=e),h[0]<e[0]&&(h=e),o[1]<e[1]&&(o=e),u[2]<e[2]&&(u=e)}),c[0]=.5*(n[0]+h[0]),c[1]=.5*(a[1]+o[1]),c[2]=.5*(s[2]+u[2]);const i=c[0]-h[0],g=c[1]-o[1],m=c[2]-u[2];return c[3]=Math.sqrt(i*i+g*g+m*m),cache.set(e,c),c};module.exports=measureBoundingSphere;
|
|
252
252
|
|
|
253
|
-
},{"../../maths/
|
|
253
|
+
},{"../../maths/vec4":246}],85:[function(require,module,exports){
|
|
254
254
|
const vec3=require("../../maths/vec3"),measureSignedVolume=e=>{let r=0;const t=e.vertices,c=vec3.create();for(let e=0;e<t.length-2;e++)vec3.cross(c,t[e+1],t[e+2]),r+=vec3.dot(t[0],c);return r/=6};module.exports=measureSignedVolume;
|
|
255
255
|
|
|
256
256
|
},{"../../maths/vec3":220}],86:[function(require,module,exports){
|
|
@@ -917,7 +917,7 @@ const pointInTriangle=(n,a,e,r,i,o,t,x)=>(i-t)*(a-x)-(n-t)*(o-x)>=0&&(n-t)*(r-x)
|
|
|
917
917
|
const mat4=require("../../maths/mat4"),geom2=require("../../geometries/geom2"),geom3=require("../../geometries/geom3"),poly3=require("../../geometries/poly3"),slice=require("./slice"),repairSlice=require("./slice/repair"),extrudeWalls=require("./extrudeWalls"),defaultCallback=(e,r,l)=>{let t=null;return geom2.isA(l)&&(t=slice.fromSides(geom2.toSides(l))),poly3.isA(l)&&(t=slice.fromPoints(poly3.toPoints(l))),0===e||1===e?slice.transform(mat4.fromTranslation(mat4.create(),[0,0,e]),t):null},extrudeFromSlices=(e,r)=>{const l={numberOfSlices:2,capStart:!0,capEnd:!0,close:!1,repair:!0,callback:defaultCallback},{numberOfSlices:t,capStart:o,capEnd:c,close:s,repair:i,callback:a}=Object.assign({},l,e);if(t<2)throw new Error("numberOfSlices must be 2 or more");i&&(r=repairSlice(r));const n=t-1;let u=null,m=null,f=null,g=[];for(let e=0;e<t;e++){const l=a(e/n,e,r);if(l){if(!slice.isA(l))throw new Error("the callback function must return slice objects");if(0===slice.toEdges(l).length)throw new Error("the callback function must return slices with one or more edges");f&&(g=g.concat(extrudeWalls(f,l))),0===e&&(u=l),e===t-1&&(m=l),f=l}}if(c){const e=slice.toPolygons(m);g=g.concat(e)}if(o){const e=slice.toPolygons(u).map(poly3.invert);g=g.concat(e)}return o||c||s&&!slice.equals(m,u)&&(g=g.concat(extrudeWalls(m,u))),geom3.create(g)};module.exports=extrudeFromSlices;
|
|
918
918
|
|
|
919
919
|
},{"../../geometries/geom2":25,"../../geometries/geom3":40,"../../geometries/poly3":78,"../../maths/mat4":142,"./extrudeWalls":315,"./slice":324,"./slice/repair":326}],307:[function(require,module,exports){
|
|
920
|
-
const{TAU:TAU}=require("../../maths/constants"),slice=require("./slice"),mat4=require("../../maths/mat4"),extrudeFromSlices=require("./extrudeFromSlices"),geom2=require("../../geometries/geom2"),extrudeHelical=(e,t)=>{const r={angle:TAU,startAngle:0,pitch:10,endOffset:0,segmentsPerRotation:32},{angle:a,endOffset:s,segmentsPerRotation:
|
|
920
|
+
const{TAU:TAU}=require("../../maths/constants"),slice=require("./slice"),mat4=require("../../maths/mat4"),extrudeFromSlices=require("./extrudeFromSlices"),geom2=require("../../geometries/geom2"),extrudeHelical=(e,t)=>{const r={angle:TAU,startAngle:0,pitch:10,endOffset:0,segmentsPerRotation:32},{angle:a,endOffset:s,segmentsPerRotation:o,startAngle:i}=Object.assign({},r,e);let n;n=!e.pitch&&e.height?e.height/(a/TAU):e.pitch?e.pitch:r.pitch;if(o<3)throw new Error("The number of segments per rotation needs to be at least 3.");const m=geom2.toSides(t);if(0===m.length)throw new Error("the given geometry cannot be empty");const c=m.filter(e=>e[0][0]>=0);let l=slice.fromSides(m);0===c.length&&(l=slice.reverse(l));const h=Math.round(o/TAU*Math.abs(a)),g=h>=2?h:2,u=mat4.create();let f;return extrudeFromSlices({numberOfSlices:g+1,callback:(e,t,r)=>{const o=i+a/g*t,m=s/g*t,c=(o-i)/TAU*n;return mat4.multiply(u,mat4.fromTranslation(mat4.create(),[m,0,c*Math.sign(a)]),mat4.fromXRotation(mat4.create(),-TAU/4*Math.sign(a))),f=mat4.create(),mat4.multiply(f,mat4.fromZRotation(mat4.create(),o),u),slice.transform(f,r)}},l)};module.exports=extrudeHelical;
|
|
921
921
|
|
|
922
922
|
},{"../../geometries/geom2":25,"../../maths/constants":93,"../../maths/mat4":142,"./extrudeFromSlices":306,"./slice":324}],308:[function(require,module,exports){
|
|
923
923
|
const flatten=require("../../utils/flatten"),geom2=require("../../geometries/geom2"),path2=require("../../geometries/path2"),extrudeLinearGeom2=require("./extrudeLinearGeom2"),extrudeLinearPath2=require("./extrudeLinearPath2"),extrudeLinear=(e,...t)=>{const{height:r,twistAngle:i,twistSteps:n,repair:a}=Object.assign({},{height:1,twistAngle:0,twistSteps:1,repair:!0},e);if(0===(t=flatten(t)).length)throw new Error("wrong number of arguments");e={offset:[0,0,r],twistAngle:i,twistSteps:n,repair:a};const s=t.map(t=>path2.isA(t)?extrudeLinearPath2(e,t):geom2.isA(t)?extrudeLinearGeom2(e,t):t);return 1===s.length?s[0]:s};module.exports=extrudeLinear;
|
|
@@ -1007,7 +1007,7 @@ const flatten=require("../../utils/flatten"),geom3=require("../../geometries/geo
|
|
|
1007
1007
|
const flatten=require("../../utils/flatten"),path2=require("../../geometries/path2"),hullPoints2=require("./hullPoints2"),toUniquePoints=require("./toUniquePoints"),hullPath2=(...t)=>{t=flatten(t);const e=toUniquePoints(t),o=hullPoints2(e);return path2.fromPoints({closed:!0},o)};module.exports=hullPath2;
|
|
1008
1008
|
|
|
1009
1009
|
},{"../../geometries/path2":61,"../../utils/flatten":395,"./hullPoints2":337,"./toUniquePoints":347}],337:[function(require,module,exports){
|
|
1010
|
-
const vec2=require("../../maths/vec2"),hullPoints2=
|
|
1010
|
+
const vec2=require("../../maths/vec2"),hullPoints2=e=>{let t=vec2.fromValues(1/0,1/0);e.forEach(e=>{(e[1]<t[1]||e[1]===t[1]&&e[0]<t[0])&&(t=e)});const n=[];e.forEach(e=>{const o=fakeAtan2(e[1]-t[1],e[0]-t[0]),s=vec2.squaredDistance(e,t);n.push({point:e,angle:o,distSq:s})}),n.sort((e,t)=>e.angle!==t.angle?e.angle-t.angle:e.distSq-t.distSq);const o=[];return n.forEach(e=>{let t=o.length;for(;t>1&&ccw(o[t-2],o[t-1],e.point)<=Number.EPSILON;)o.pop(),t=o.length;o.push(e.point)}),o},ccw=(e,t,n)=>(t[0]-e[0])*(n[1]-e[1])-(t[1]-e[1])*(n[0]-e[0]),fakeAtan2=(e,t)=>0===e&&0===t?-1/0:-t/e;module.exports=hullPoints2;
|
|
1011
1011
|
|
|
1012
1012
|
},{"../../maths/vec2":189}],338:[function(require,module,exports){
|
|
1013
1013
|
module.exports={hull:require("./hull"),hullChain:require("./hullChain")};
|
|
@@ -1055,9 +1055,9 @@ const aboutEqualNormals=require("../../maths/utils/aboutEqualNormals"),vec3=requ
|
|
|
1055
1055
|
const{EPS:EPS}=require("../../maths/constants"),line2=require("../../maths/line2"),vec2=require("../../maths/vec2"),OrthoNormalBasis=require("../../maths/OrthoNormalBasis"),interpolateBetween2DPointsForY=require("../../maths/utils/interpolateBetween2DPointsForY"),{insertSorted:insertSorted,fnNumberSort:fnNumberSort}=require("../../utils"),poly3=require("../../geometries/poly3"),reTesselateCoplanarPolygons=t=>{if(t.length<2)return t;const e=[],o=t.length,n=poly3.plane(t[0]),l=new OrthoNormalBasis(n),i=[],r=[],s=new Map,f=new Map,p=new Map,h=10/EPS;for(let e=0;e<o;e++){const o=t[e];let n=[],g=o.vertices.length,c=-1;if(g>0){let t,i;for(let r=0;r<g;r++){let s=l.to2D(o.vertices[r]);const g=Math.floor(s[1]*h);let a;p.has(g)?a=p.get(g):p.has(g+1)?a=p.get(g+1):p.has(g-1)?a=p.get(g-1):(a=s[1],p.set(g,s[1])),s=vec2.fromValues(s[0],a),n.push(s);const u=s[1];(0===r||u<t)&&(t=u,c=r),(0===r||u>i)&&(i=u);let m=f.get(u);m||(m={},f.set(u,m)),m[e]=!0}if(t>=i)n=[],g=0,c=-1;else{let o=s.get(t);o||(o=[],s.set(t,o)),o.push(e)}}n.reverse(),c=g-c-1,i.push(n),r.push(c)}const g=[];f.forEach((t,e)=>g.push(e)),g.sort(fnNumberSort);let c=[],a=[];for(let t=0;t<g.length;t++){const o=[],p=g[t],h=f.get(p);for(let t=0;t<c.length;++t){const e=c[t],o=e.polygonindex;if(h[o]){const n=i[o],l=n.length;let r=e.leftvertexindex,s=e.rightvertexindex;for(;;){let t=r+1;if(t>=l&&(t=0),n[t][1]!==p)break;r=t}let f=s-1;if(f<0&&(f=l-1),n[f][1]===p&&(s=f),r!==e.leftvertexindex&&r===s)c.splice(t,1),--t;else{e.leftvertexindex=r,e.rightvertexindex=s,e.topleft=n[r],e.topright=n[s];let t=r+1;t>=l&&(t=0),e.bottomleft=n[t];let o=s-1;o<0&&(o=l-1),e.bottomright=n[o]}}}let u;if(t>=g.length-1)c=[],u=null;else{const e=.5*(p+(u=Number(g[t+1]))),o=s.get(p);for(const t in o){const n=o[t],l=i[n],s=l.length,f=r[n];let h=f;for(;;){let t=h+1;if(t>=s&&(t=0),l[t][1]!==p)break;if(t===f)break;h=t}let g=f;for(;;){let t=g-1;if(t<0&&(t=s-1),l[t][1]!==p)break;if(t===h)break;g=t}let a=h+1;a>=s&&(a=0);let u=g-1;u<0&&(u=s-1);const m={polygonindex:n,leftvertexindex:h,rightvertexindex:g,topleft:l[h],topright:l[g],bottomleft:l[a],bottomright:l[u]};insertSorted(c,m,(t,o)=>{const n=interpolateBetween2DPointsForY(t.topleft,t.bottomleft,e),l=interpolateBetween2DPointsForY(o.topleft,o.bottomleft,e);return n>l?1:n<l?-1:0})}}for(const t in c){const e=c[t];let n=interpolateBetween2DPointsForY(e.topleft,e.bottomleft,p);const l=vec2.fromValues(n,p);n=interpolateBetween2DPointsForY(e.topright,e.bottomright,p);const i=vec2.fromValues(n,p);n=interpolateBetween2DPointsForY(e.topleft,e.bottomleft,u);const r=vec2.fromValues(n,u);n=interpolateBetween2DPointsForY(e.topright,e.bottomright,u);const s=vec2.fromValues(n,u),f={topleft:l,topright:i,bottomleft:r,bottomright:s,leftline:line2.fromPoints(line2.create(),l,r),rightline:line2.fromPoints(line2.create(),s,i)};if(o.length>0){const t=o[o.length-1],e=vec2.distance(f.topleft,t.topright),n=vec2.distance(f.bottomleft,t.bottomright);e<EPS&&n<EPS&&(f.topleft=t.topleft,f.leftline=t.leftline,f.bottomleft=t.bottomleft,o.splice(o.length-1,1))}o.push(f)}if(t>0){const t=new Set,i=new Set;for(let e=0;e<o.length;e++){const n=o[e];for(let e=0;e<a.length;e++)if(!i.has(e)){const o=a[e];if(vec2.distance(o.bottomleft,n.topleft)<EPS&&vec2.distance(o.bottomright,n.topright)<EPS){i.add(e);const l=line2.direction(n.leftline),r=line2.direction(o.leftline),s=l[0]-r[0],f=line2.direction(n.rightline),p=line2.direction(o.rightline),h=f[0]-p[0],g=Math.abs(s)<EPS,c=Math.abs(h)<EPS,a=c||h>=0;(g||s>=0)&&a&&(n.outpolygon=o.outpolygon,n.leftlinecontinues=g,n.rightlinecontinues=c,t.add(e));break}}}for(let o=0;o<a.length;o++)if(!t.has(o)){const t=a[o];t.outpolygon.rightpoints.push(t.bottomright),vec2.distance(t.bottomright,t.bottomleft)>EPS&&t.outpolygon.leftpoints.push(t.bottomleft),t.outpolygon.leftpoints.reverse();const i=t.outpolygon.rightpoints.concat(t.outpolygon.leftpoints).map(t=>l.to3D(t)),r=poly3.fromPointsAndPlane(i,n);r.vertices.length&&e.push(r)}}for(let t=0;t<o.length;t++){const e=o[t];e.outpolygon?(e.leftlinecontinues||e.outpolygon.leftpoints.push(e.topleft),e.rightlinecontinues||e.outpolygon.rightpoints.push(e.topright)):(e.outpolygon={leftpoints:[],rightpoints:[]},e.outpolygon.leftpoints.push(e.topleft),vec2.distance(e.topleft,e.topright)>EPS&&e.outpolygon.rightpoints.push(e.topright))}a=o}return e};module.exports=reTesselateCoplanarPolygons;
|
|
1056
1056
|
|
|
1057
1057
|
},{"../../geometries/poly3":78,"../../maths/OrthoNormalBasis":92,"../../maths/constants":93,"../../maths/line2":104,"../../maths/utils/interpolateBetween2DPointsForY":168,"../../maths/vec2":189,"../../utils":397}],353:[function(require,module,exports){
|
|
1058
|
-
const geom3=require("../../geometries/geom3"),poly3=require("../../geometries/poly3"),
|
|
1058
|
+
const geom3=require("../../geometries/geom3"),poly3=require("../../geometries/poly3"),{NEPS:NEPS}=require("../../maths/constants"),reTesselateCoplanarPolygons=require("./reTesselateCoplanarPolygons"),retessellate=e=>{if(e.isRetesselated)return e;const s=geom3.toPolygons(e).map((e,s)=>({vertices:e.vertices,plane:poly3.plane(e),index:s})),o=classifyPolygons(s),l=[];o.forEach(e=>{if(Array.isArray(e)){const s=reTesselateCoplanarPolygons(e);l.push(...s)}else l.push(e)});const n=geom3.create(l);return n.isRetesselated=!0,n},classifyPolygons=e=>{let s=[e];const o=[];for(let e=3;e>=0;e--){const l=[],n=3===e?1.5e-8:NEPS;s.forEach(s=>{s.sort(byPlaneComponent(e,n));let t=0;for(let r=1;r<s.length;r++)s[r].plane[e]-s[t].plane[e]>n&&(r-t==1?o.push(s[t]):l.push(s.slice(t,r)),t=r);s.length-t==1?o.push(s[t]):l.push(s.slice(t))}),s=l}const l=[];return s.forEach(e=>{e[0]&&(l[e[0].index]=e)}),o.forEach(e=>{l[e.index]=e}),l},byPlaneComponent=(e,s)=>(o,l)=>o.plane[e]-l.plane[e]>s?1:l.plane[e]-o.plane[e]>s?-1:0;module.exports=retessellate;
|
|
1059
1059
|
|
|
1060
|
-
},{"../../geometries/geom3":40,"../../geometries/poly3":78,"../../maths/
|
|
1060
|
+
},{"../../geometries/geom3":40,"../../geometries/poly3":78,"../../maths/constants":93,"./reTesselateCoplanarPolygons":352}],354:[function(require,module,exports){
|
|
1061
1061
|
const flatten=require("../../utils/flatten"),vec2=require("../../maths/vec2"),geom2=require("../../geometries/geom2"),geom3=require("../../geometries/geom3"),path2=require("../../geometries/path2"),measureEpsilon=require("../../measurements/measureEpsilon"),snapPolygons=require("./snapPolygons"),snapPath2=e=>{const s=measureEpsilon(e),r=path2.toPoints(e).map(e=>vec2.snap(vec2.create(),e,s));return path2.create(r)},snapGeom2=e=>{const s=measureEpsilon(e);let r=geom2.toSides(e).map(e=>[vec2.snap(vec2.create(),e[0],s),vec2.snap(vec2.create(),e[1],s)]);return r=r.filter(e=>!vec2.equals(e[0],e[1])),geom2.create(r)},snapGeom3=e=>{const s=measureEpsilon(e),r=geom3.toPolygons(e),o=snapPolygons(s,r);return geom3.create(o)},snap=(...e)=>{if(0===(e=flatten(e)).length)throw new Error("wrong number of arguments");const s=e.map(e=>path2.isA(e)?snapPath2(e):geom2.isA(e)?snapGeom2(e):geom3.isA(e)?snapGeom3(e):e);return 1===s.length?s[0]:s};module.exports=snap;
|
|
1062
1062
|
|
|
1063
1063
|
},{"../../geometries/geom2":25,"../../geometries/geom3":40,"../../geometries/path2":61,"../../maths/vec2":189,"../../measurements/measureEpsilon":261,"../../utils/flatten":395,"./snapPolygons":355}],355:[function(require,module,exports){
|
|
@@ -1094,31 +1094,31 @@ const flatten=require("../../utils/flatten"),mat4=require("../../maths/mat4"),ge
|
|
|
1094
1094
|
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),path2=require("../geometries/path2"),{isGT:isGT,isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),arc=e=>{const r={center:[0,0],radius:1,startAngle:0,endAngle:TAU,makeTangent:!1,segments:32};let{center:t,radius:s,startAngle:n,endAngle:a,makeTangent:o,segments:c}=Object.assign({},r,e);if(!isNumberArray(t,2))throw new Error("center must be an array of X and Y values");if(!isGT(s,0))throw new Error("radius must be greater than zero");if(!isGTE(n,0))throw new Error("startAngle must be positive");if(!isGTE(a,0))throw new Error("endAngle must be positive");if(!isGTE(c,4))throw new Error("segments must be four or more");let i=TAU;(n%=TAU)<(a%=TAU)&&(i=a-n),n>a&&(i=a+(TAU-n));const m=Math.acos((s*s+s*s-EPS*EPS)/(2*s*s)),l=vec2.clone(t);let u;const A=[];if(i<m)u=vec2.fromAngleRadians(vec2.create(),n),vec2.scale(u,u,s),vec2.add(u,u,l),A.push(u);else{const e=Math.max(1,Math.floor(c*(i/TAU)))+1;let r=.5*e/i;r>.25&&(r=.25);const t=o?e+2:e;for(let a=0;a<=t;a++){let t=a;o&&((t=(a-1)*(e-2*r)/e+r)<0&&(t=0),t>e&&(t=e));const c=n+t*(i/e);u=vec2.fromAngleRadians(vec2.create(),c),vec2.scale(u,u,s),vec2.add(u,u,l),A.push(u)}}return path2.fromPoints({closed:!1},A)};module.exports=arc;
|
|
1095
1095
|
|
|
1096
1096
|
},{"../geometries/path2":61,"../maths/constants":93,"../maths/vec2":189,"./commonChecks":367}],366:[function(require,module,exports){
|
|
1097
|
-
const{TAU:TAU}=require("../maths/constants"),ellipse=require("./ellipse"),{
|
|
1097
|
+
const{TAU:TAU}=require("../maths/constants"),ellipse=require("./ellipse"),{isGTE:isGTE}=require("./commonChecks"),circle=e=>{const s={center:[0,0],radius:1,startAngle:0,endAngle:TAU,segments:32};let{center:r,radius:t,startAngle:n,endAngle:i,segments:l}=Object.assign({},s,e);if(!isGTE(t,0))throw new Error("radius must be positive");return ellipse({center:r,radius:t=[t,t],startAngle:n,endAngle:i,segments:l})};module.exports=circle;
|
|
1098
1098
|
|
|
1099
1099
|
},{"../maths/constants":93,"./commonChecks":367,"./ellipse":372}],367:[function(require,module,exports){
|
|
1100
1100
|
const isNumberArray=(i,r)=>!!(Array.isArray(i)&&i.length>=r)&&i.every(i=>Number.isFinite(i)),isGT=(i,r)=>Number.isFinite(i)&&i>r,isGTE=(i,r)=>Number.isFinite(i)&&i>=r;module.exports={isNumberArray:isNumberArray,isGT:isGT,isGTE:isGTE};
|
|
1101
1101
|
|
|
1102
1102
|
},{}],368:[function(require,module,exports){
|
|
1103
|
-
const cuboid=require("./cuboid"),{
|
|
1103
|
+
const cuboid=require("./cuboid"),{isGTE:isGTE}=require("./commonChecks"),cube=e=>{let{center:i,size:r}=Object.assign({},{center:[0,0,0],size:2},e);if(!isGTE(r,0))throw new Error("size must be positive");return cuboid({center:i,size:r=[r,r,r]})};module.exports=cube;
|
|
1104
1104
|
|
|
1105
1105
|
},{"./commonChecks":367,"./cuboid":369}],369:[function(require,module,exports){
|
|
1106
|
-
const geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{isNumberArray:isNumberArray}=require("./commonChecks"),cuboid=e=>{const{center:r,size:o}=Object.assign({},{center:[0,0,0],size:[2,2,2]},e);if(!isNumberArray(r,3))throw new Error("center must be an array of X, Y and Z values");if(!isNumberArray(o,3))throw new Error("size must be an array of width, depth and height values");if(!o.every(e=>e
|
|
1106
|
+
const geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{isNumberArray:isNumberArray}=require("./commonChecks"),cuboid=e=>{const{center:r,size:o}=Object.assign({},{center:[0,0,0],size:[2,2,2]},e);if(!isNumberArray(r,3))throw new Error("center must be an array of X, Y and Z values");if(!isNumberArray(o,3))throw new Error("size must be an array of width, depth and height values");if(!o.every(e=>e>=0))throw new Error("size values must be positive");return 0===o[0]||0===o[1]||0===o[2]?geom3.create():geom3.create([[[0,4,6,2],[-1,0,0]],[[1,3,7,5],[1,0,0]],[[0,1,5,4],[0,-1,0]],[[2,6,7,3],[0,1,0]],[[0,2,3,1],[0,0,-1]],[[4,5,7,6],[0,0,1]]].map(e=>{const t=e[0].map(e=>{return[r[0]+o[0]/2*(2*!!(1&e)-1),r[1]+o[1]/2*(2*!!(2&e)-1),r[2]+o[2]/2*(2*!!(4&e)-1)]});return poly3.create(t)}))};module.exports=cuboid;
|
|
1107
1107
|
|
|
1108
1108
|
},{"../geometries/geom3":40,"../geometries/poly3":78,"./commonChecks":367}],370:[function(require,module,exports){
|
|
1109
|
-
const cylinderElliptic=require("./cylinderElliptic"),{
|
|
1109
|
+
const geom3=require("../geometries/geom3"),cylinderElliptic=require("./cylinderElliptic"),{isGTE:isGTE}=require("./commonChecks"),cylinder=e=>{const{center:i,height:r,radius:s,segments:t}=Object.assign({},{center:[0,0,0],height:2,radius:1,segments:32},e);if(!isGTE(s,0))throw new Error("radius must be positive");return 0===r||0===s?geom3.create():cylinderElliptic({center:i,height:r,startRadius:[s,s],endRadius:[s,s],segments:t})};module.exports=cylinder;
|
|
1110
1110
|
|
|
1111
|
-
},{"./commonChecks":367,"./cylinderElliptic":371}],371:[function(require,module,exports){
|
|
1111
|
+
},{"../geometries/geom3":40,"./commonChecks":367,"./cylinderElliptic":371}],371:[function(require,module,exports){
|
|
1112
1112
|
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGT:isGT,isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),cylinderElliptic=e=>{const r={center:[0,0,0],height:2,startRadius:[1,1],startAngle:0,endRadius:[1,1],endAngle:TAU,segments:32};let{center:s,height:t,startRadius:a,startAngle:i,endRadius:o,endAngle:n,segments:u}=Object.assign({},r,e);if(!isNumberArray(s,3))throw new Error("center must be an array of X, Y and Z values");if(!isGT(t,0))throw new Error("height must be greater then zero");if(!isNumberArray(a,2))throw new Error("startRadius must be an array of X and Y values");if(!a.every(e=>e>=0))throw new Error("startRadius values must be positive");if(!isNumberArray(o,2))throw new Error("endRadius must be an array of X and Y values");if(!o.every(e=>e>=0))throw new Error("endRadius values must be positive");if(o.every(e=>0===e)&&a.every(e=>0===e))throw new Error("at least one radius must be positive");if(!isGTE(i,0))throw new Error("startAngle must be positive");if(!isGTE(n,0))throw new Error("endAngle must be positive");if(!isGTE(u,4))throw new Error("segments must be four or more");let c=TAU;(i%=TAU)<(n%=TAU)&&(c=n-i),i>n&&(c=n+(TAU-i));const l=Math.min(a[0],a[1],o[0],o[1]),m=Math.acos((l*l+l*l-EPS*EPS)/(2*l*l));if(c<m)throw new Error("startAngle and endAngle do not define a significant rotation");const h=Math.floor(u*(c/TAU)),d=vec3.fromValues(0,0,-t/2),v=vec3.fromValues(0,0,t/2),f=vec3.subtract(vec3.create(),v,d),g=vec3.fromValues(1,0,0),p=vec3.fromValues(0,1,0),A=vec3.create(),w=vec3.create(),E=vec3.create(),y=(e,r,s)=>{const t=r*c+i;return vec3.scale(A,g,s[0]*cos(t)),vec3.scale(w,p,s[1]*sin(t)),vec3.add(A,A,w),vec3.scale(E,f,e),vec3.add(E,E,d),vec3.add(vec3.create(),A,E)},T=(...e)=>{const r=e.map(e=>vec3.add(vec3.create(),e,s));return poly3.create(r)},b=[];for(let e=0;e<h;e++){const r=e/h;let s=(e+1)/h;c===TAU&&e===h-1&&(s=0),o[0]===a[0]&&o[1]===a[1]?(b.push(T(d,y(0,s,o),y(0,r,o))),b.push(T(y(0,s,o),y(1,s,o),y(1,r,o),y(0,r,o))),b.push(T(v,y(1,r,o),y(1,s,o)))):(a[0]>0&&a[1]>0&&b.push(T(d,y(0,s,a),y(0,r,a))),(a[0]>0||a[1]>0)&&b.push(T(y(0,r,a),y(0,s,a),y(1,r,o))),o[0]>0&&o[1]>0&&b.push(T(v,y(1,r,o),y(1,s,o))),(o[0]>0||o[1]>0)&&b.push(T(y(1,r,o),y(0,s,a),y(1,s,o))))}return c<TAU&&(b.push(T(d,y(0,0,a),v)),b.push(T(y(0,0,a),y(1,0,o),v)),b.push(T(d,v,y(0,1,a))),b.push(T(y(0,1,a),v,y(1,1,o)))),geom3.create(b)};module.exports=cylinderElliptic;
|
|
1113
1113
|
|
|
1114
1114
|
},{"../geometries/geom3":40,"../geometries/poly3":78,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec3":220,"./commonChecks":367}],372:[function(require,module,exports){
|
|
1115
|
-
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),ellipse=e=>{const r={center:[0,0],radius:[1,1],startAngle:0,endAngle:TAU,segments:32};let{center:s,radius:t,startAngle:n,endAngle:o,segments:i}=Object.assign({},r,e);if(!isNumberArray(s,2))throw new Error("center must be an array of X and Y values");if(!isNumberArray(t,2))throw new Error("radius must be an array of X and Y values");if(!t.every(e=>e
|
|
1115
|
+
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),ellipse=e=>{const r={center:[0,0],radius:[1,1],startAngle:0,endAngle:TAU,segments:32};let{center:s,radius:t,startAngle:n,endAngle:o,segments:i}=Object.assign({},r,e);if(!isNumberArray(s,2))throw new Error("center must be an array of X and Y values");if(!isNumberArray(t,2))throw new Error("radius must be an array of X and Y values");if(!t.every(e=>e>=0))throw new Error("radius values must be positive");if(!isGTE(n,0))throw new Error("startAngle must be positive");if(!isGTE(o,0))throw new Error("endAngle must be positive");if(!isGTE(i,3))throw new Error("segments must be three or more");if(0===t[0]||0===t[1])return geom2.create();let a=TAU;(n%=TAU)<(o%=TAU)&&(a=o-n),n>o&&(a=o+(TAU-n));const m=Math.min(t[0],t[1]);if(a<Math.acos((m*m+m*m-EPS*EPS)/(2*m*m)))throw new Error("startAngle and endAngle do not define a significant rotation");i=Math.floor(i*(a/TAU));const u=vec2.clone(s),c=a/i,l=[];i=a<TAU?i+1:i;for(let e=0;e<i;e++){const r=c*e+n,s=vec2.fromValues(t[0]*cos(r),t[1]*sin(r));vec2.add(s,u,s),l.push(s)}return a<TAU&&l.push(u),geom2.fromPoints(l)};module.exports=ellipse;
|
|
1116
1116
|
|
|
1117
1117
|
},{"../geometries/geom2":25,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec2":189,"./commonChecks":367}],373:[function(require,module,exports){
|
|
1118
|
-
const{TAU:TAU}=require("../maths/constants"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),ellipsoid=e=>{const{center:c,radius:r,segments:
|
|
1118
|
+
const{TAU:TAU}=require("../maths/constants"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),ellipsoid=e=>{const{center:c,radius:r,segments:s,axes:a}=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(r,3))throw new Error("radius must be an array of X, Y and Z values");if(!r.every(e=>e>=0))throw new Error("radius values must be positive");if(!isGTE(s,4))throw new Error("segments must be four or more");if(0===r[0]||0===r[1]||0===r[2])return geom3.create();const t=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),a[0]),r[0]),v=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),a[1]),r[1]),o=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),a[2]),r[2]),i=Math.round(s/4);let l;const u=[],d=vec3.create(),n=vec3.create();for(let e=0;e<=s;e++){const r=TAU*e/s,a=vec3.add(vec3.create(),vec3.scale(d,t,cos(r)),vec3.scale(n,v,sin(r)));if(e>0){let e,r;for(let s=0;s<=i;s++){const t=TAU/4*s/i,v=cos(t),m=sin(t);if(s>0){let t,h=[];t=vec3.subtract(vec3.create(),vec3.scale(d,l,e),vec3.scale(n,o,r)),h.push(vec3.add(t,t,c)),t=vec3.subtract(vec3.create(),vec3.scale(d,a,e),vec3.scale(n,o,r)),h.push(vec3.add(t,t,c)),s<i&&(t=vec3.subtract(vec3.create(),vec3.scale(d,a,v),vec3.scale(n,o,m)),h.push(vec3.add(t,t,c))),t=vec3.subtract(vec3.create(),vec3.scale(d,l,v),vec3.scale(n,o,m)),h.push(vec3.add(t,t,c)),u.push(poly3.create(h)),h=[],t=vec3.add(vec3.create(),vec3.scale(d,l,e),vec3.scale(n,o,r)),h.push(vec3.add(vec3.create(),c,t)),t=vec3.add(t,vec3.scale(d,a,e),vec3.scale(n,o,r)),h.push(vec3.add(vec3.create(),c,t)),s<i&&(t=vec3.add(t,vec3.scale(d,a,v),vec3.scale(n,o,m)),h.push(vec3.add(vec3.create(),c,t))),t=vec3.add(t,vec3.scale(d,l,v),vec3.scale(n,o,m)),h.push(vec3.add(vec3.create(),c,t)),h.reverse(),u.push(poly3.create(h))}e=v,r=m}}l=a}return geom3.create(u)};module.exports=ellipsoid;
|
|
1119
1119
|
|
|
1120
1120
|
},{"../geometries/geom3":40,"../geometries/poly3":78,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec3":220,"./commonChecks":367}],374:[function(require,module,exports){
|
|
1121
|
-
const mat4=require("../maths/mat4"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),polyhedron=require("./polyhedron"),{
|
|
1121
|
+
const mat4=require("../maths/mat4"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),polyhedron=require("./polyhedron"),{isGTE:isGTE}=require("./commonChecks"),geodesicSphere=e=>{let{radius:r,frequency:t}=Object.assign({},{radius:1,frequency:6},e);if(!isGTE(r,0))throw new Error("radius must be positive");if(!isGTE(t,6))throw new Error("frequency must be six or more");if(0===r)return geom3.create();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 f=[],l=[];for(let e=0;e<r;e++)for(let t=0;t<r-e;t++){const a=e/r,u=(e+1)/r,m=t/(r-e),h=(t+1)/(r-e),g=r-e-1?t/(r-e-1):1,p=[];p[0]=i(i(o,s,m),n,a),p[1]=i(i(o,s,h),n,a),p[2]=i(i(o,s,g),n,u);for(let e=0;e<3;e++){const r=vec3.length(p[e]);for(let t=0;t<3;t++)p[e][t]/=r}if(f.push(p[0],p[1],p[2]),l.push([c,c+1,c+2]),c+=3,t<r-e-1){const m=r-e-1?(t+1)/(r-e-1):1;p[0]=i(i(o,s,h),n,a),p[1]=i(i(o,s,m),n,u),p[2]=i(i(o,s,g),n,u);for(let e=0;e<3;e++){const r=vec3.length(p[e]);for(let t=0;t<3;t++)p[e][t]/=r}f.push(p[0],p[1],p[2]),l.push([c,c+1,c+2]),c+=3}}return{points:f,triangles:l,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=[],f=[],l=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,l);c=c.concat(r.points),f=f.concat(r.triangles),l=r.offset}let a=polyhedron({points:c,faces:f,orientation:"inward"});return 1!==r&&(a=geom3.transform(mat4.fromScaling(mat4.create(),[r,r,r]),a)),a};module.exports=geodesicSphere;
|
|
1122
1122
|
|
|
1123
1123
|
},{"../geometries/geom3":40,"../maths/mat4":142,"../maths/vec3":220,"./commonChecks":367,"./polyhedron":378}],375:[function(require,module,exports){
|
|
1124
1124
|
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")};
|
|
@@ -1133,22 +1133,22 @@ const geom2=require("../geometries/geom2"),polygon=r=>{const{points:o,paths:t}=O
|
|
|
1133
1133
|
const geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{isNumberArray:isNumberArray}=require("./commonChecks"),polyhedron=r=>{const e={points:[],faces:[],colors:void 0,orientation:"outward"},{points:o,faces:a,colors:t,orientation:n}=Object.assign({},e,r);if(!Array.isArray(o)||!Array.isArray(a))throw new Error("points and faces must be arrays");if(o.length<3)throw new Error("three or more points are required");if(a.length<1)throw new Error("one or more faces are required");if(t){if(!Array.isArray(t))throw new Error("colors must be an array");if(t.length!==a.length)throw new Error("faces and colors must have the same length")}o.forEach((r,e)=>{if(!isNumberArray(r,3))throw new Error(`point ${e} must be an array of X, Y, Z values`)}),a.forEach((r,e)=>{if(r.length<3)throw new Error(`face ${e} must contain 3 or more indexes`);if(!isNumberArray(r,r.length))throw new Error(`face ${e} must be an array of numbers`)}),"outward"!==n&&a.forEach(r=>r.reverse());const s=a.map((r,e)=>{const a=poly3.create(r.map(r=>o[r]));return t&&t[e]&&(a.color=t[e]),a});return geom3.create(s)};module.exports=polyhedron;
|
|
1134
1134
|
|
|
1135
1135
|
},{"../geometries/geom3":40,"../geometries/poly3":78,"./commonChecks":367}],379:[function(require,module,exports){
|
|
1136
|
-
const vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{isNumberArray:isNumberArray}=require("./commonChecks"),rectangle=e=>{const{center:r,size:t}=Object.assign({},{center:[0,0],size:[2,2]},e);if(!isNumberArray(r,2))throw new Error("center must be an array of X and Y values");if(!isNumberArray(t,2))throw new Error("size must be an array of X and Y values");if(!t.every(e=>e
|
|
1136
|
+
const vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{isNumberArray:isNumberArray}=require("./commonChecks"),rectangle=e=>{const{center:r,size:t}=Object.assign({},{center:[0,0],size:[2,2]},e);if(!isNumberArray(r,2))throw new Error("center must be an array of X and Y values");if(!isNumberArray(t,2))throw new Error("size must be an array of X and Y values");if(!t.every(e=>e>=0))throw new Error("size values must be positive");if(0===t[0]||0===t[1])return geom2.create();const a=[t[0]/2,t[1]/2],c=[a[0],-a[1]],s=[vec2.subtract(vec2.create(),r,a),vec2.add(vec2.create(),r,c),vec2.add(vec2.create(),r,a),vec2.subtract(vec2.create(),r,c)];return geom2.fromPoints(s)};module.exports=rectangle;
|
|
1137
1137
|
|
|
1138
1138
|
},{"../geometries/geom2":25,"../maths/vec2":189,"./commonChecks":367}],380:[function(require,module,exports){
|
|
1139
|
-
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{
|
|
1139
|
+
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),cuboid=require("./cuboid"),createCorners=(e,r,t,s,c,o)=>{const a=TAU/4*c/s,n=cos(a),i=sin(a),u=s-c;let l=t*n,h=r[2]-(t-t*i);o||(h=t-t*i-r[2]),l=l>EPS?l:0;const d=vec3.add(vec3.create(),e,[r[0]-t,r[1]-t,h]),v=vec3.add(vec3.create(),e,[t-r[0],r[1]-t,h]),m=vec3.add(vec3.create(),e,[t-r[0],t-r[1],h]),p=vec3.add(vec3.create(),e,[r[0]-t,t-r[1],h]),f=[],g=[],E=[],b=[];for(let e=0;e<=u;e++){const r=u>0?TAU/4*e/u:0,t=vec2.fromAngleRadians(vec2.create(),r);vec2.scale(t,t,l);const s=vec3.fromVec2(vec3.create(),t);f.push(vec3.add(vec3.create(),d,s)),vec3.rotateZ(s,s,[0,0,0],TAU/4),g.push(vec3.add(vec3.create(),v,s)),vec3.rotateZ(s,s,[0,0,0],TAU/4),E.push(vec3.add(vec3.create(),m,s)),vec3.rotateZ(s,s,[0,0,0],TAU/4),b.push(vec3.add(vec3.create(),p,s))}return o?[f,g,E,b]:(f.reverse(),g.reverse(),E.reverse(),b.reverse(),[b,E,g,f])},stitchCorners=(e,r)=>{const t=[];for(let s=0;s<e.length;s++){const c=e[s],o=r[s];for(let e=0;e<c.length-1;e++)t.push(poly3.create([c[e],c[e+1],o[e]])),e<o.length-1&&t.push(poly3.create([o[e],c[e+1],o[e+1]]))}return t},stitchWalls=(e,r)=>{const t=[];for(let s=0;s<e.length;s++){let c=e[s],o=r[s];const a=c[c.length-1],n=o[o.length-1],i=(s+1)%e.length;c=e[i],o=r[i];const u=c[0],l=o[0];t.push(poly3.create([a,u,l,n]))}return t},stitchSides=(e,r)=>{e=(e=[e[3],e[2],e[1],e[0]]).map(e=>e.slice().reverse());const t=[];e.forEach(e=>{e.forEach(e=>t.push(e))});const s=[];r.forEach(e=>{e.forEach(e=>s.push(e))});const c=[];for(let e=0;e<s.length;e++){const r=(e+1)%s.length;c.push(poly3.create([t[e],t[r],s[r],s[e]]))}return c},roundedCuboid=e=>{let{center:r,size:t,roundRadius:s,segments:c}=Object.assign({},{center:[0,0,0],size:[2,2,2],roundRadius:.2,segments:32},e);if(!isNumberArray(r,3))throw new Error("center must be an array of X, Y and Z values");if(!isNumberArray(t,3))throw new Error("size must be an array of X, Y and Z values");if(!t.every(e=>e>=0))throw new Error("size values must be positive");if(!isGTE(s,0))throw new Error("roundRadius must be positive");if(!isGTE(c,4))throw new Error("segments must be four or more");if(0===t[0]||0===t[1]||0===t[2])return geom3.create();if(0===s)return cuboid({center:r,size:t});if(s>(t=t.map(e=>e/2))[0]-EPS||s>t[1]-EPS||s>t[2]-EPS)throw new Error("roundRadius must be smaller then the radius of all dimensions");c=Math.floor(c/4);let o=null,a=null,n=[];for(let e=0;e<=c;e++){const i=createCorners(r,t,s,c,e,!0),u=createCorners(r,t,s,c,e,!1);if(0===e&&(n=n.concat(stitchSides(u,i))),o&&(n=n.concat(stitchCorners(o,i),stitchWalls(o,i))),a&&(n=n.concat(stitchCorners(a,u),stitchWalls(a,u))),e===c){let e=i.map(e=>e[0]);n.push(poly3.create(e)),e=u.map(e=>e[0]),n.push(poly3.create(e))}o=i,a=u}return geom3.create(n)};module.exports=roundedCuboid;
|
|
1140
1140
|
|
|
1141
|
-
},{"../geometries/geom3":40,"../geometries/poly3":78,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec2":189,"../maths/vec3":220,"./commonChecks":367}],381:[function(require,module,exports){
|
|
1142
|
-
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{
|
|
1141
|
+
},{"../geometries/geom3":40,"../geometries/poly3":78,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec2":189,"../maths/vec3":220,"./commonChecks":367,"./cuboid":369}],381:[function(require,module,exports){
|
|
1142
|
+
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec3=require("../maths/vec3"),geom3=require("../geometries/geom3"),poly3=require("../geometries/poly3"),{sin:sin,cos:cos}=require("../maths/utils/trigonometry"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),cylinder=require("./cylinder"),roundedCylinder=e=>{const{center:c,height:r,radius:s,roundRadius:a,segments:t}=Object.assign({},{center:[0,0,0],height:2,radius:1,roundRadius:.2,segments:32},e);if(!isNumberArray(c,3))throw new Error("center must be an array of X, Y and Z values");if(!isGTE(r,0))throw new Error("height must be positive");if(!isGTE(s,0))throw new Error("radius must be positive");if(!isGTE(a,0))throw new Error("roundRadius must be positive");if(a>s)throw new Error("roundRadius must be smaller then the radius");if(!isGTE(t,4))throw new Error("segments must be four or more");if(0===r||0===s)return geom3.create();if(0===a)return cylinder({center:c,height:r,radius:s});const v=[0,0,-r/2],o=[0,0,r/2],i=vec3.subtract(vec3.create(),o,v);if(2*a>vec3.length(i)-EPS)throw new Error("height must be larger than twice roundRadius");let u;u=Math.abs(i[0])>Math.abs(i[1])?vec3.fromValues(0,1,0):vec3.fromValues(1,0,0);const d=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),i),a),n=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),vec3.cross(vec3.create(),d,u)),s),l=vec3.scale(vec3.create(),vec3.normalize(vec3.create(),vec3.cross(vec3.create(),n,d)),s);vec3.add(v,v,d),vec3.subtract(o,o,d);const h=Math.floor(.25*t),m=e=>{const r=e.map(e=>vec3.add(e,e,c));return poly3.create(r)},p=[],b=vec3.create(),f=vec3.create();let g;for(let e=0;e<=t;e++){const c=TAU*e/t,r=vec3.add(vec3.create(),vec3.scale(b,n,cos(c)),vec3.scale(f,l,sin(c)));if(e>0){let e,c,s=[];s.push(vec3.add(vec3.create(),v,r)),s.push(vec3.add(vec3.create(),v,g)),s.push(vec3.add(vec3.create(),o,g)),s.push(vec3.add(vec3.create(),o,r)),p.push(m(s));for(let a=0;a<=h;a++){const t=TAU/4*a/h,i=cos(t),u=sin(t);if(a>0){let t;s=[],t=vec3.add(vec3.create(),v,vec3.subtract(b,vec3.scale(b,g,e),vec3.scale(f,d,c))),s.push(t),t=vec3.add(vec3.create(),v,vec3.subtract(b,vec3.scale(b,r,e),vec3.scale(f,d,c))),s.push(t),a<h&&(t=vec3.add(vec3.create(),v,vec3.subtract(b,vec3.scale(b,r,i),vec3.scale(f,d,u))),s.push(t)),t=vec3.add(vec3.create(),v,vec3.subtract(b,vec3.scale(b,g,i),vec3.scale(f,d,u))),s.push(t),p.push(m(s)),s=[],t=vec3.add(vec3.create(),vec3.scale(b,g,e),vec3.scale(f,d,c)),vec3.add(t,t,o),s.push(t),t=vec3.add(vec3.create(),vec3.scale(b,r,e),vec3.scale(f,d,c)),vec3.add(t,t,o),s.push(t),a<h&&(t=vec3.add(vec3.create(),vec3.scale(b,r,i),vec3.scale(f,d,u)),vec3.add(t,t,o),s.push(t)),t=vec3.add(vec3.create(),vec3.scale(b,g,i),vec3.scale(f,d,u)),vec3.add(t,t,o),s.push(t),s.reverse(),p.push(m(s))}e=i,c=u}}g=r}return geom3.create(p)};module.exports=roundedCylinder;
|
|
1143
1143
|
|
|
1144
|
-
},{"../geometries/geom3":40,"../geometries/poly3":78,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec3":220,"./commonChecks":367}],382:[function(require,module,exports){
|
|
1145
|
-
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{
|
|
1144
|
+
},{"../geometries/geom3":40,"../geometries/poly3":78,"../maths/constants":93,"../maths/utils/trigonometry":171,"../maths/vec3":220,"./commonChecks":367,"./cylinder":370}],382:[function(require,module,exports){
|
|
1145
|
+
const{EPS:EPS,TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),rectangle=require("./rectangle"),roundedRectangle=e=>{let{center:r,size:t,roundRadius:a,segments:c}=Object.assign({},{center:[0,0],size:[2,2],roundRadius:.2,segments:32},e);if(!isNumberArray(r,2))throw new Error("center must be an array of X and Y values");if(!isNumberArray(t,2))throw new Error("size must be an array of X and Y values");if(!t.every(e=>e>=0))throw new Error("size values must be positive");if(!isGTE(a,0))throw new Error("roundRadius must be positive");if(!isGTE(c,4))throw new Error("segments must be four or more");if(0===t[0]||0===t[1])return geom2.create();if(0===a)return rectangle({center:r,size:t});if(a>(t=t.map(e=>e/2))[0]-EPS||a>t[1]-EPS)throw new Error("roundRadius must be smaller then the radius of all dimensions");const s=Math.floor(c/4),o=vec2.add(vec2.create(),r,[t[0]-a,t[1]-a]),n=vec2.add(vec2.create(),r,[a-t[0],t[1]-a]),i=vec2.add(vec2.create(),r,[a-t[0],a-t[1]]),u=vec2.add(vec2.create(),r,[t[0]-a,a-t[1]]),d=[],v=[],m=[],l=[];for(let e=0;e<=s;e++){const r=TAU/4*e/s,t=vec2.fromAngleRadians(vec2.create(),r);vec2.scale(t,t,a),d.push(vec2.add(vec2.create(),o,t)),vec2.rotate(t,t,vec2.create(),TAU/4),v.push(vec2.add(vec2.create(),n,t)),vec2.rotate(t,t,vec2.create(),TAU/4),m.push(vec2.add(vec2.create(),i,t)),vec2.rotate(t,t,vec2.create(),TAU/4),l.push(vec2.add(vec2.create(),u,t))}return geom2.fromPoints(d.concat(v,m,l))};module.exports=roundedRectangle;
|
|
1146
1146
|
|
|
1147
|
-
},{"../geometries/geom2":25,"../maths/constants":93,"../maths/vec2":189,"./commonChecks":367}],383:[function(require,module,exports){
|
|
1148
|
-
const ellipsoid=require("./ellipsoid"),{
|
|
1147
|
+
},{"../geometries/geom2":25,"../maths/constants":93,"../maths/vec2":189,"./commonChecks":367,"./rectangle":379}],383:[function(require,module,exports){
|
|
1148
|
+
const ellipsoid=require("./ellipsoid"),{isGTE:isGTE}=require("./commonChecks"),sphere=e=>{let{center:s,radius:r,segments:i,axes:t}=Object.assign({},{center:[0,0,0],radius:1,segments:32,axes:[[1,0,0],[0,-1,0],[0,0,1]]},e);if(!isGTE(r,0))throw new Error("radius must be positive");return ellipsoid({center:s,radius:r=[r,r,r],segments:i,axes:t})};module.exports=sphere;
|
|
1149
1149
|
|
|
1150
1150
|
},{"./commonChecks":367,"./ellipsoid":373}],384:[function(require,module,exports){
|
|
1151
|
-
const rectangle=require("./rectangle"),{
|
|
1151
|
+
const rectangle=require("./rectangle"),{isGTE:isGTE}=require("./commonChecks"),square=e=>{let{center:r,size:s}=Object.assign({},{center:[0,0],size:2},e);if(!isGTE(s,0))throw new Error("size must be positive");return rectangle({center:r,size:s=[s,s]})};module.exports=square;
|
|
1152
1152
|
|
|
1153
1153
|
},{"./commonChecks":367,"./rectangle":379}],385:[function(require,module,exports){
|
|
1154
1154
|
const{TAU:TAU}=require("../maths/constants"),vec2=require("../maths/vec2"),geom2=require("../geometries/geom2"),{isGT:isGT,isGTE:isGTE,isNumberArray:isNumberArray}=require("./commonChecks"),getRadiusRatio=(e,r)=>e>0&&r>1&&r<e/2?Math.cos(Math.PI*r/e)/Math.cos(Math.PI*(r-1)/e):0,getPoints=(e,r,t,s)=>{const o=TAU/e,i=[];for(let a=0;a<e;a++){const e=vec2.fromAngleRadians(vec2.create(),o*a+t);vec2.scale(e,e,r),vec2.add(e,s,e),i.push(e)}return i},star=e=>{let{center:r,vertices:t,outerRadius:s,innerRadius:o,density:i,startAngle:a}=Object.assign({},{center:[0,0],vertices:5,outerRadius:1,innerRadius:0,density:2,startAngle:0},e);if(!isNumberArray(r,2))throw new Error("center must be an array of X and Y values");if(!isGTE(t,2))throw new Error("vertices must be two or more");if(!isGT(s,0))throw new Error("outerRadius must be greater than zero");if(!isGTE(o,0))throw new Error("innerRadius must be greater than zero");if(!isGTE(a,0))throw new Error("startAngle must be greater than zero");if(t=Math.floor(t),i=Math.floor(i),a%=TAU,0===o){if(!isGTE(i,2))throw new Error("density must be two or more");o=s*getRadiusRatio(t,i)}const n=vec2.clone(r),u=getPoints(t,s,a,n),c=getPoints(t,o,a+Math.PI/t,n),h=[];for(let e=0;e<t;e++)h.push(u[e]),h.push(c[e]);return geom2.fromPoints(h)};module.exports=star;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/modeling",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Constructive Solid Geometry (CSG) Library for JSCAD",
|
|
5
5
|
"homepage": "https://openjscad.xyz/",
|
|
6
6
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"nyc": "15.1.0",
|
|
62
62
|
"uglifyify": "5.0.2"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "e269f212db5a00cda740d2f7ad3e5206d1eb839f"
|
|
65
65
|
}
|
|
@@ -3,7 +3,7 @@ const lengths = require('./lengths')
|
|
|
3
3
|
/**
|
|
4
4
|
* Convert a given arc length along a bezier curve to a t value.
|
|
5
5
|
* Useful for generating equally spaced points along a bezier curve.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @example
|
|
8
8
|
* const points = [];
|
|
9
9
|
* const segments = 9; // this will generate 10 equally spaced points
|
|
@@ -14,7 +14,7 @@ const lengths = require('./lengths')
|
|
|
14
14
|
* points.push(point);
|
|
15
15
|
* }
|
|
16
16
|
* return points;
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* @param {Object} [options] options for construction
|
|
19
19
|
* @param {Number} [options.distance=0] the distance along the bezier curve for which we want to find the corresponding t value.
|
|
20
20
|
* @param {Number} [options.segments=100] the number of segments to use when approximating the curve length.
|
|
@@ -27,8 +27,8 @@ const arcLengthToT = (options, bezier) => {
|
|
|
27
27
|
distance: 0,
|
|
28
28
|
segments: 100
|
|
29
29
|
}
|
|
30
|
-
const {distance, segments} = Object.assign({}, defaults, options)
|
|
31
|
-
|
|
30
|
+
const { distance, segments } = Object.assign({}, defaults, options)
|
|
31
|
+
|
|
32
32
|
const arcLengths = lengths(segments, bezier)
|
|
33
33
|
// binary search for the index with largest value smaller than target arcLength
|
|
34
34
|
let startIndex = 0
|
|
@@ -58,6 +58,6 @@ const arcLengthToT = (options, bezier) => {
|
|
|
58
58
|
const segmentFraction = (distance - lengthBefore) / segmentLength
|
|
59
59
|
// add that fractional amount and return
|
|
60
60
|
return (targetIndex + segmentFraction) / segments
|
|
61
|
-
}
|
|
61
|
+
}
|
|
62
62
|
|
|
63
|
-
module.exports = arcLengthToT
|
|
63
|
+
module.exports = arcLengthToT
|
|
@@ -9,71 +9,71 @@ const { nearlyEqual } = require('../../../test/helpers/index')
|
|
|
9
9
|
test('calculate arcLengthToT for an 1D linear bezier with numeric control points', (t) => {
|
|
10
10
|
const bezierCurve = bezier.create([0, 10])
|
|
11
11
|
const len = length(100, bezierCurve)
|
|
12
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
13
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.5, 0.0001)
|
|
14
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
12
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
13
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.5, 0.0001)
|
|
14
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
15
15
|
t.true(true)
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
test('calculate arcLengthToT for an 1D linear bezier with array control points', (t) => {
|
|
19
19
|
const bezierCurve = bezier.create([[0], [10]])
|
|
20
20
|
const len = length(100, bezierCurve)
|
|
21
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
22
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.5, 0.0001)
|
|
23
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
21
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
22
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.5, 0.0001)
|
|
23
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
24
24
|
t.true(true)
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
test('calculate arcLengthToT for a 2D linear bezier', (t) => {
|
|
28
28
|
const bezierCurve = bezier.create([[0, 0], [10, 10]])
|
|
29
29
|
const len = length(100, bezierCurve)
|
|
30
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
31
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.5, 0.0001)
|
|
32
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
30
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
31
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.5, 0.0001)
|
|
32
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
33
33
|
t.true(true)
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
test('calculate arcLengthToT for a 2D quadratic (3 control points) bezier', (t) => {
|
|
37
37
|
const bezierCurve = bezier.create([[0, 0], [0, 10], [10, 10]])
|
|
38
38
|
const len = length(100, bezierCurve)
|
|
39
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
40
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.50001, 0.0001)
|
|
41
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
39
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
40
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.50001, 0.0001)
|
|
41
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
42
42
|
t.true(true)
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
test('calculate arcLengthToT for a 2D cubic (4 control points) bezier', (t) => {
|
|
46
46
|
const bezierCurve = bezier.create([[0, 0], [0, 10], [10, 10], [10, 0]])
|
|
47
47
|
const len = length(100, bezierCurve)
|
|
48
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
49
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.49999, 0.0001)
|
|
50
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
48
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
49
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.49999, 0.0001)
|
|
50
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
51
51
|
t.true(true)
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
test('calculate arcLengthToT for a 3D linear bezier', (t) => {
|
|
55
55
|
const bezierCurve = bezier.create([[0, 0, 0], [10, 10, 10]])
|
|
56
56
|
const len = length(100, bezierCurve)
|
|
57
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
58
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.49999, 0.0001)
|
|
59
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
57
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
58
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.49999, 0.0001)
|
|
59
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
60
60
|
t.true(true)
|
|
61
61
|
})
|
|
62
62
|
|
|
63
63
|
test('calculate arcLengthToT for a 3D quadratic (3 control points) bezier', (t) => {
|
|
64
64
|
const bezierCurve = bezier.create([[0, 0, 0], [5, 5, 5], [0, 0, 10]])
|
|
65
65
|
const len = length(100, bezierCurve)
|
|
66
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
67
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.49999, 0.0001)
|
|
68
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
66
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
67
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.49999, 0.0001)
|
|
68
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
69
69
|
t.true(true)
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
test('calculate arcLengthToT for a 3D cubic (4 control points) bezier', (t) => {
|
|
73
73
|
const bezierCurve = bezier.create([[0, 0, 0], [5, 5, 5], [0, 0, 10], [-5, -5, 5]])
|
|
74
74
|
const len = length(100, bezierCurve)
|
|
75
|
-
nearlyEqual(t, arcLengthToT({distance: 0}, bezierCurve), 0, 0.0001)
|
|
76
|
-
nearlyEqual(t, arcLengthToT({distance: len / 2}, bezierCurve), 0.5621, 0.0001)
|
|
77
|
-
nearlyEqual(t, arcLengthToT({distance: len}, bezierCurve), 1, 0.0001)
|
|
75
|
+
nearlyEqual(t, arcLengthToT({ distance: 0 }, bezierCurve), 0, 0.0001)
|
|
76
|
+
nearlyEqual(t, arcLengthToT({ distance: len / 2 }, bezierCurve), 0.5621, 0.0001)
|
|
77
|
+
nearlyEqual(t, arcLengthToT({ distance: len }, bezierCurve), 1, 0.0001)
|
|
78
78
|
t.true(true)
|
|
79
|
-
})
|
|
79
|
+
})
|
|
@@ -7,14 +7,12 @@ const lengths = require('./lengths')
|
|
|
7
7
|
* @example
|
|
8
8
|
* const b = bezier.create([[0, 0], [0, 10]]);
|
|
9
9
|
* console.log(length(100, b)) // output 10
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* @param {Number} segments the number of segments to use when approximating the curve length.
|
|
12
12
|
* @param {Object} bezier a bezier curve.
|
|
13
13
|
* @returns an approximation of the curve's length.
|
|
14
14
|
* @alias module:modeling/curves/bezier.length
|
|
15
15
|
*/
|
|
16
|
-
const length = (segments, bezier) =>
|
|
17
|
-
return lengths(segments, bezier)[segments]
|
|
18
|
-
};
|
|
16
|
+
const length = (segments, bezier) => lengths(segments, bezier)[segments]
|
|
19
17
|
|
|
20
|
-
module.exports = length
|
|
18
|
+
module.exports = length
|
|
@@ -7,7 +7,7 @@ const { nearlyEqual } = require('../../../test/helpers/index')
|
|
|
7
7
|
|
|
8
8
|
test('calculate the length of an 1D linear bezier with numeric control points', (t) => {
|
|
9
9
|
const bezierCurve = bezier.create([0, 10])
|
|
10
|
-
nearlyEqual(t, length(100, bezierCurve), 10, 0.0001)
|
|
10
|
+
nearlyEqual(t, length(100, bezierCurve), 10, 0.0001)
|
|
11
11
|
t.true(true)
|
|
12
12
|
})
|
|
13
13
|
|
|
@@ -51,4 +51,4 @@ test('calculate the length of a 3D cubic (4 control points) bezier', (t) => {
|
|
|
51
51
|
const bezierCurve = bezier.create([[0, 0, 0], [5, 5, 5], [0, 0, 10], [-5, -5, 5]])
|
|
52
52
|
nearlyEqual(t, length(100, bezierCurve), 17.2116, 0.0001)
|
|
53
53
|
t.true(true)
|
|
54
|
-
})
|
|
54
|
+
})
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
const valueAt = require(
|
|
1
|
+
const valueAt = require('./valueAt')
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Divides the bezier curve into line segments and returns the cumulative length of those segments as an array.
|
|
5
5
|
* Utility function used to calculate the curve's approximate length and determine the equivalence between arc length and time.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @example
|
|
8
8
|
* const b = bezier.create([[0, 0], [0, 10]]);
|
|
9
9
|
* const totalLength = lengths(100, b).pop(); // the last element of the array is the curve's approximate length
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* @param {Number} segments the number of segments to use when approximating the curve length.
|
|
12
12
|
* @param {Object} bezier a bezier curve.
|
|
13
13
|
* @returns an array containing the cumulative length of the segments.
|
|
14
14
|
*/
|
|
15
15
|
const lengths = (segments, bezier) => {
|
|
16
16
|
let sum = 0
|
|
17
|
-
|
|
17
|
+
const lengths = [0]
|
|
18
18
|
let previous = valueAt(0, bezier)
|
|
19
19
|
for (let index = 1; index <= segments; index++) {
|
|
20
20
|
const current = valueAt(index / segments, bezier)
|
|
@@ -23,7 +23,7 @@ const lengths = (segments, bezier) => {
|
|
|
23
23
|
previous = current
|
|
24
24
|
}
|
|
25
25
|
return lengths
|
|
26
|
-
}
|
|
26
|
+
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Calculates the Euclidean distance between two n-dimensional points.
|
|
@@ -31,7 +31,7 @@ const lengths = (segments, bezier) => {
|
|
|
31
31
|
* @example
|
|
32
32
|
* const distance = distanceBetween([0, 0], [0, 10]); // calculate distance between 2D points
|
|
33
33
|
* console.log(distance); // output 10
|
|
34
|
-
*
|
|
34
|
+
*
|
|
35
35
|
* @param {Array} a - first operand.
|
|
36
36
|
* @param {Array} b - second operand.
|
|
37
37
|
* @returns {Number} - distance.
|
|
@@ -41,7 +41,7 @@ const distanceBetween = (a, b) => {
|
|
|
41
41
|
return Math.abs(a - b)
|
|
42
42
|
} else if (Array.isArray(a) && Array.isArray(b)) {
|
|
43
43
|
if (a.length !== b.length) {
|
|
44
|
-
throw new Error(
|
|
44
|
+
throw new Error('The operands must have the same number of dimensions.')
|
|
45
45
|
}
|
|
46
46
|
let sum = 0
|
|
47
47
|
for (let i = 0; i < a.length; i++) {
|
|
@@ -49,8 +49,8 @@ const distanceBetween = (a, b) => {
|
|
|
49
49
|
}
|
|
50
50
|
return Math.sqrt(sum)
|
|
51
51
|
} else {
|
|
52
|
-
throw new Error(
|
|
52
|
+
throw new Error('The operands must be of the same type, either number or array.')
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
module.exports = lengths
|
|
56
|
+
module.exports = lengths
|
|
@@ -17,7 +17,7 @@ test('calculate lengths for a 1D linear bezier with numeric control points', (t)
|
|
|
17
17
|
test('calculate lengths for a 1D linear bezier with array control points', (t) => {
|
|
18
18
|
const bezierCurve = bezier.create([[0], [10]])
|
|
19
19
|
const result = lengths(100, bezierCurve)
|
|
20
|
-
t.is(result.length, 101)
|
|
20
|
+
t.is(result.length, 101)
|
|
21
21
|
nearlyEqual(t, result[0], 0, 0.0001)
|
|
22
22
|
nearlyEqual(t, result[50], 5, 0.0001)
|
|
23
23
|
nearlyEqual(t, result[100], 10, 0.0001)
|
|
@@ -26,7 +26,7 @@ test('calculate lengths for a 1D linear bezier with array control points', (t) =
|
|
|
26
26
|
test('calculate lengths for a 2D linear bezier', (t) => {
|
|
27
27
|
const bezierCurve = bezier.create([[0, 0], [10, 10]])
|
|
28
28
|
const result = lengths(100, bezierCurve)
|
|
29
|
-
t.is(result.length, 101)
|
|
29
|
+
t.is(result.length, 101)
|
|
30
30
|
nearlyEqual(t, result[0], 0, 0.0001)
|
|
31
31
|
nearlyEqual(t, result[50], 7.0710, 0.0001)
|
|
32
32
|
nearlyEqual(t, result[100], 14.1421, 0.0001)
|
|
@@ -53,7 +53,7 @@ test('calculate lengths for a 2D cubic (4 control points) bezier', (t) => {
|
|
|
53
53
|
test('calculate lengths for a 3D linear bezier', (t) => {
|
|
54
54
|
const bezierCurve = bezier.create([[0, 0, 0], [10, 10, 10]])
|
|
55
55
|
const result = lengths(100, bezierCurve)
|
|
56
|
-
t.is(result.length, 101)
|
|
56
|
+
t.is(result.length, 101)
|
|
57
57
|
nearlyEqual(t, result[0], 0, 0.0001)
|
|
58
58
|
nearlyEqual(t, result[50], 8.6602, 0.0001)
|
|
59
59
|
nearlyEqual(t, result[100], 17.3205, 0.0001)
|
|
@@ -80,11 +80,4 @@ const isPointInside = (point, polygon) => {
|
|
|
80
80
|
return insideFlag
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
/*
|
|
84
|
-
* > 0 : p2 is left of the line p0 -> p1
|
|
85
|
-
* = 0 : p2 is on the line p0 -> p1
|
|
86
|
-
* < 0 : p2 is right of the line p0 -> p1
|
|
87
|
-
*/
|
|
88
|
-
const isLeft = (p0, p1, p2) => (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1])
|
|
89
|
-
|
|
90
83
|
module.exports = arePointsInside
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const vec3 = require('../../maths/vec3')
|
|
2
1
|
const vec4 = require('../../maths/vec4')
|
|
3
2
|
|
|
4
3
|
const cache = new WeakMap()
|
|
@@ -10,7 +9,7 @@ const cache = new WeakMap()
|
|
|
10
9
|
* @alias module:modeling/geometries/poly3.measureBoundingSphere
|
|
11
10
|
*/
|
|
12
11
|
const measureBoundingSphere = (polygon) => {
|
|
13
|
-
|
|
12
|
+
const boundingSphere = cache.get(polygon)
|
|
14
13
|
if (boundingSphere) return boundingSphere
|
|
15
14
|
|
|
16
15
|
const vertices = polygon.vertices
|