fluidcad 0.0.13 → 0.0.15
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/lib/dist/common/scene-object.d.ts +3 -0
- package/lib/dist/common/scene-object.js +7 -0
- package/lib/dist/core/2d/arc.d.ts +14 -56
- package/lib/dist/core/2d/arc.js +8 -23
- package/lib/dist/core/2d/center.d.ts +9 -0
- package/lib/dist/core/2d/center.js +10 -0
- package/lib/dist/core/2d/index.d.ts +2 -0
- package/lib/dist/core/2d/index.js +2 -0
- package/lib/dist/core/2d/intersect.d.ts +17 -0
- package/lib/dist/core/2d/intersect.js +20 -0
- package/lib/dist/core/interfaces.d.ts +50 -2
- package/lib/dist/core/repeat.js +10 -3
- package/lib/dist/features/2d/arc.d.ts +27 -14
- package/lib/dist/features/2d/arc.js +269 -38
- package/lib/dist/features/2d/intersect.d.ts +15 -0
- package/lib/dist/features/2d/intersect.js +83 -0
- package/lib/dist/features/2d/plane-center.d.ts +13 -0
- package/lib/dist/features/2d/plane-center.js +40 -0
- package/lib/dist/features/2d/projection.js +3 -4
- package/lib/dist/features/2d/rect.d.ts +2 -2
- package/lib/dist/features/2d/rect.js +3 -3
- package/lib/dist/features/2d/sketch.d.ts +2 -2
- package/lib/dist/features/2d/sketch.js +13 -1
- package/lib/dist/features/2d/slot.d.ts +2 -2
- package/lib/dist/features/2d/slot.js +3 -3
- package/lib/dist/features/extrude-base.d.ts +4 -0
- package/lib/dist/features/extrude-base.js +27 -0
- package/lib/dist/features/extrude-to-face.d.ts +1 -0
- package/lib/dist/features/extrude-to-face.js +5 -1
- package/lib/dist/features/extrude-two-distances.d.ts +1 -0
- package/lib/dist/features/extrude-two-distances.js +5 -2
- package/lib/dist/features/extrude.d.ts +1 -0
- package/lib/dist/features/extrude.js +5 -1
- package/lib/dist/features/plane-renderable-base.d.ts +2 -1
- package/lib/dist/features/plane-renderable-base.js +1 -1
- package/lib/dist/features/plane.d.ts +1 -1
- package/lib/dist/filters/face/face-filter.d.ts +10 -0
- package/lib/dist/filters/face/face-filter.js +39 -0
- package/lib/dist/filters/face/intersects-with.d.ts +18 -0
- package/lib/dist/filters/face/intersects-with.js +41 -0
- package/lib/dist/helpers/clone-transform.js +1 -0
- package/lib/dist/oc/boolean-ops.js +0 -2
- package/lib/dist/oc/face-query.d.ts +1 -0
- package/lib/dist/oc/face-query.js +15 -0
- package/lib/dist/oc/index.d.ts +1 -0
- package/lib/dist/oc/index.js +1 -0
- package/lib/dist/oc/section-ops.d.ts +6 -0
- package/lib/dist/oc/section-ops.js +26 -0
- package/lib/dist/oc/thin-face-maker.d.ts +29 -0
- package/lib/dist/oc/thin-face-maker.js +163 -0
- package/lib/dist/rendering/render.js +16 -0
- package/lib/dist/tests/features/2d/arc.test.js +2 -2
- package/lib/dist/tests/features/2d/intersect.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/intersect.test.js +22 -0
- package/lib/dist/tests/features/2d/rect.test.js +1 -1
- package/lib/dist/tests/features/loft.test.js +1 -1
- package/lib/dist/tests/features/select.test.js +49 -1
- package/lib/dist/tests/features/thin-extrude.test.d.ts +1 -0
- package/lib/dist/tests/features/thin-extrude.test.js +137 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/server/dist/index.js +23 -15
- package/ui/dist/assets/{index-mLcpjEcV.js → index-BJG141m7.js} +2 -2
- package/ui/dist/index.html +1 -1
- package/lib/dist/features/2d/arc-three-points.d.ts +0 -19
- package/lib/dist/features/2d/arc-three-points.js +0 -75
- package/lib/dist/features/2d/arc-to-point.d.ts +0 -17
- package/lib/dist/features/2d/arc-to-point.js +0 -95
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluidcad",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Parametric CAD modeling library using javascript",
|
|
5
5
|
"author": "Marwan Aouida <contact@marwan.dev>",
|
|
6
6
|
"homepage": "https://fluidcad.io",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"chokidar": "^5.0.0",
|
|
59
59
|
"color-name": "^2.1.0",
|
|
60
60
|
"express": "^5.2.1",
|
|
61
|
-
"occjs-fluidcad": "^
|
|
62
|
-
"occjs-wrapper": "npm:occjs-fluidcad
|
|
61
|
+
"occjs-fluidcad": "^2.0.0",
|
|
62
|
+
"occjs-wrapper": "npm:occjs-fluidcad@2.0.0",
|
|
63
63
|
"tsx": "^4.21.0",
|
|
64
64
|
"vite": "^8.0.8",
|
|
65
65
|
"ws": "^8.18.0"
|
package/server/dist/index.js
CHANGED
|
@@ -174,22 +174,30 @@ async function handleExtensionMessage(msg) {
|
|
|
174
174
|
broadcastToUI({ type: 'processing-file' });
|
|
175
175
|
currentFile = msg.fileName;
|
|
176
176
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
try {
|
|
178
|
+
const data = await fluidCadServer.updateLiveCode(msg.fileName, msg.code);
|
|
179
|
+
if (myVersion !== renderVersion) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (data) {
|
|
183
|
+
sendToExtension({
|
|
184
|
+
type: 'scene-rendered',
|
|
185
|
+
absPath: data.absPath,
|
|
186
|
+
result: data.result,
|
|
187
|
+
rollbackStop: data.rollbackStop,
|
|
188
|
+
});
|
|
189
|
+
broadcastToUI({
|
|
190
|
+
type: 'scene-rendered',
|
|
191
|
+
result: data.result,
|
|
192
|
+
absPath: data.absPath,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
180
195
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
rollbackStop: data.rollbackStop,
|
|
187
|
-
});
|
|
188
|
-
broadcastToUI({
|
|
189
|
-
type: 'scene-rendered',
|
|
190
|
-
result: data.result,
|
|
191
|
-
absPath: data.absPath,
|
|
192
|
-
});
|
|
196
|
+
catch {
|
|
197
|
+
// Silently ignore errors during live-update (syntax errors, incomplete
|
|
198
|
+
// expressions, etc. while the user is typing). The last successful
|
|
199
|
+
// render remains visible. Model-building errors are delivered separately
|
|
200
|
+
// via scene-rendered object properties and are not affected.
|
|
193
201
|
}
|
|
194
202
|
break;
|
|
195
203
|
}
|
|
@@ -4305,7 +4305,7 @@ void main() {
|
|
|
4305
4305
|
|
|
4306
4306
|
gl_FragColor = vec4(color, 1.0);
|
|
4307
4307
|
}
|
|
4308
|
-
`,af=class extends ii{constructor(e){super(),this.userData.isMetaShape=!0;for(let t of e.meshes){let e=t.vertices,n=t.indices,r=[];for(let t=0;t<n.length;t+=2){let i=n[t]*3;r.push(e[i],e[i+1],e[i+2])}if(n.length>=2){let t=n[n.length-1]*3;r.push(e[t],e[t+1],e[t+2])}let i=new Tr;i.setAttribute(`position`,new W(new Float32Array(r),3));let a=new Ui(i,new qr({uniforms:{color:{value:Nd.metaEdgeColor},dashLength:{value:Qd},gapLength:{value:$d},dotLength:{value:ef},patternLength:{value:tf}},vertexShader:nf,fragmentShader:rf,side:2,transparent:!0,polygonOffset:!0,polygonOffsetFactor:2,polygonOffsetUnits:1}));a.computeLineDistances(),this.add(a)}}},of=`#2297ff`,sf=2,cf=class extends ii{constructor(e){super(),this.userData.isMetaShape=!0;for(let t of e.meshes){let e=new Tr;e.setAttribute(`position`,new W(new Float32Array(t.vertices),3)),e.setAttribute(`normal`,new W(new Float32Array(t.normals),3));let n=t.vertices.length/3>65535?Uint32Array:Uint16Array;e.setIndex(new W(new n(t.indices),1));let r=new qi(e,new Fi({color:of,linewidth:sf,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1,side:2,depthWrite:!0,depthTest:!0}));this.add(r)}}},lf=`#2297ff`,uf=`#2297ff`,df=.15,ff=.4,pf=class extends ii{constructor(e,t){super(),this.userData.isMetaShape=!0,this.userData.isPickRegion=!0,this.userData.isPickRegionSelected=t,e.metaData&&(this.userData.metaData=e.metaData);let n=t?uf:lf,r=t?ff:df;for(let t of e.meshes){let e=new Tr;e.setAttribute(`position`,new W(new Float32Array(t.vertices),3)),e.setAttribute(`normal`,new W(new Float32Array(t.normals),3));let i=t.vertices.length/3>65535?Uint32Array:Uint16Array;e.setIndex(new W(new i(t.indices),1)),e.computeBoundingBox();let a=new G(e,new dr({color:n,transparent:!0,opacity:r,side:2,depthWrite:!1,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1}));this.add(a)}}},mf=`#2297ff`,hf=2,gf=2,_f=16,vf=.003,yf=1.5,bf=1e-8;function xf(e,t,n){if(e instanceof Pa)return(e.top-e.bottom)/e.zoom*n;if(e instanceof Qr){let r=e.position.distanceTo(t),i=e.fov*Math.PI/180;return 2*r*Math.tan(i/2)*n}return 1}var Sf=class extends ii{constructor(e){super(),this.userData.isMetaShape=!0;let t=new Zi(gf,_f),n=new dr({color:mf,side:2,depthTest:!0}),r=[];for(let t of e.meshes){let e=new Tr;e.setAttribute(`position`,new W(new Float32Array(t.vertices),3)),e.setAttribute(`normal`,new W(new Float32Array(t.normals),3));let n=t.vertices.length/3>65535?Uint32Array:Uint16Array;e.setIndex(new W(new n(t.indices),1));let i=new Fi({color:mf,linewidth:hf,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1,side:2,depthWrite:!0,depthTest:!0});this.add(new qi(e,i));let a=t.vertices,o=t.indices,s=new Map;for(let e of o)s.set(e,(s.get(e)||0)+1);for(let[e,t]of s)if(t===1){let t=new B(a[e*3],a[e*3+1],a[e*3+2]);r.some(e=>e.distanceToSquared(t)<bf)||r.push(t)}}for(let e of r){let r=new G(t,n);r.renderOrder=2;let i=new ii;i.renderOrder=2,i.userData.isVertexDot=!0,i.add(r),i.position.copy(e),r.onBeforeRender=(t,n,r)=>{i.scale.setScalar(Math.min(xf(r,e,vf),yf)),i.updateMatrixWorld(!0)},this.add(i)}}},Cf={color:`#2297ff`,lineWidth:2},wf={trim:e=>new cf(e),"pick-edge":e=>new Sf(e)};function Tf(e){let t=e.metaType?wf[e.metaType]:void 0;return t?t(e):new af(e)}var Ef={"pick-region":e=>new pf(e,!1),"pick-region-selected":e=>new pf(e,!0)};function Df(e){let t=e.metaType?Ef[e.metaType]:void 0;return t?t(e):new Xd(e)}var Of=class extends ii{constructor(e,t,n){if(super(),!e.sceneShapes)return;let r=e.sceneShapes.every(e=>e.isMetaShape||e.shapeType===`wire`||e.shapeType===`edge`),i=[`pick-region`,`pick-region-selected`,`pick-edge`];for(let a of e.sceneShapes){if(!t&&a.isMetaShape&&a.metaType&&i.includes(a.metaType))continue;let e;if(a.isMetaShape)switch(a.shapeType){case`wire`:case`edge`:e=Tf(a);break;case`face`:e=Df(a);break}else switch(a.shapeType){case`wire`:case`edge`:e=new Jd(a,n?.edge??(r?Cf:void 0));break;case`face`:e=new Xd(a,n?.face);break;case`solid`:e=new Zd(a,n);break}e&&(a.shapeId&&(e.userData.shapeId=a.shapeId),this.add(e))}}};function kf(e,t,n){if(e instanceof Pa)return(e.top-e.bottom)/e.zoom*n;if(e instanceof Qr){let r=e.position.distanceTo(t),i=e.fov*Math.PI/180;return 2*r*Math.tan(i/2)*n}return 1}var Af=`#2297ff`,jf=2,Mf=16,Nf=.003,Pf=1.5,Ff=15954511,If=64,Lf=3,Rf=15954511,zf=.35,Bf=.6,Vf=18,Hf=5,Uf=2.5,Wf=class extends ii{constructor(e,t,n,r){super(),this.buildEdges(e,t),this.buildVertices(e,t,r),n&&(this.buildCursor(e,r),this.buildTangentArrow(e,r))}buildEdges(e,t){for(let n of t)if(!(n.parentId!==e.id||!n.sceneShapes.length))for(let e of n.sceneShapes){if(e.isMetaShape||e.isGuide){if(e.shapeType===`wire`||e.shapeType===`edge`){let t=Tf(e);e.shapeId&&(t.userData.shapeId=e.shapeId),this.add(t)}continue}let t=new Jd(e,{color:Af,lineWidth:2});e.shapeId&&(t.userData.shapeId=e.shapeId),this.add(t)}}buildVertices(e,t,n){let r=e.object?.plane?.normal,i=[];for(let n of t)if(!(n.parentId!==e.id||!n.sceneShapes.length)){for(let e of n.sceneShapes)if(!(e.isMetaShape||e.isGuide))for(let t of e.meshes){if(!t.indices.length)continue;let e=new Map;for(let n of t.indices)e.set(n,(e.get(n)||0)+1);for(let[n,r]of e)r===1&&i.push(new B(t.vertices[n*3],t.vertices[n*3+1],t.vertices[n*3+2]))}}let a=[];for(let e of i)a.some(t=>t.distanceToSquared(e)<1e-12)||a.push(e);let o=new Zi(jf,Mf),s=new dr({color:Af,side:2,depthTest:!1});for(let e of a){let t=new G(o,s);t.renderOrder=2;let i=new ii;i.renderOrder=2,i.userData.isVertexDot=!0,i.add(t),i.position.copy(e),r&&i.lookAt(new B(e.x+r.x,e.y+r.y,e.z+r.z)),i.scale.setScalar(Math.min(kf(n,e,Nf),Pf)),t.onBeforeRender=(t,n,r)=>{i.scale.setScalar(Math.min(kf(r,e,Nf),Pf)),i.updateMatrixWorld(!0)},this.add(i)}}buildCursor(e,t){let n=e.object?.currentPosition;if(!n)return;let r=new Zi(Lf,If),i=new dr({color:Ff,side:2,depthTest:!1});i.transparent=!0,i.opacity=.8;let a=new G(r,i);a.renderOrder=1;let o=new ii;o.renderOrder=1,o.add(a),o.position.set(n.x,n.y,n.z);let s=e.object?.plane?.normal;if(s){let e=new B(n.x+s.x,n.y+s.y,n.z+s.z);o.lookAt(e)}o.scale.setScalar(kf(t,o.position,.003)),a.onBeforeRender=(e,t,n)=>{o.scale.setScalar(kf(n,o.position,.003)),o.updateMatrixWorld(!0)},this.add(o)}buildTangentArrow(e,t){let n=e.object?.currentPosition,r=e.object?.currentTangent,i=e.object?.plane?.origin;if(!n||!r||!i)return;let a=new B(r.x-i.x,r.y-i.y,r.z-i.z).normalize(),o=new dr({color:Rf,transparent:!0,opacity:zf,depthTest:!1}),s=new Qi(Bf,Bf,Vf,8);s.translate(0,Vf/2,0);let c=new G(s,o),l=new $i(Uf,Hf,8);l.translate(0,Vf+Hf/2,0);let u=new G(l,o),d=new ii;d.renderOrder=1,d.add(c),d.add(u);let f=new B(0,1,0),p=new mt().setFromUnitVectors(f,a);d.quaternion.copy(p),d.position.set(n.x,n.y,n.z),d.scale.setScalar(kf(t,d.position,.003)),c.onBeforeRender=(e,t,n)=>{d.scale.setScalar(kf(n,d.position,.003)),d.updateMatrixWorld(!0)},this.add(d)}};function Gf(e,t,n){if(e instanceof Pa)return(e.top-e.bottom)/e.zoom*n;if(e instanceof Qr){let r=e.position.distanceTo(t),i=e.fov*Math.PI/180;return 2*r*Math.tan(i/2)*n}return 1}var Kf=`#ffc26c`,qf=`#c88f40`,Jf=`#c88f40`,Yf=.1,Xf=20,Zf=3,Qf=1.5,$f=.4,ep=class extends ii{constructor(e,t){super();let n=e.sceneShapes[0]?.meshes[0];if(!n)return;this.userData.isMetaShape=!0,this.userData.isConstructionPlane=!0;let r=e.object.normal,i=e.object.center,a=new Tr;a.setAttribute(`position`,new W(new Float32Array(n.vertices),3)),a.setAttribute(`normal`,new W(new Float32Array(n.normals),3)),a.setIndex(new W(new Uint16Array(n.indices),1)),a.computeBoundingBox();let o=new G(a,new dr({color:Kf,transparent:!0,opacity:Yf,side:2,polygonOffset:!0,polygonOffsetFactor:1,polygonOffsetUnits:1}));this.add(o);let s=new qi(new ia(a,18),new Fi({color:qf,linewidth:1}));this.add(s);let c=new B(r.x,r.y,r.z).normalize(),l=new B(i.x,i.y,i.z),u=new dr({color:Jf}),d=Xf-Zf,f=new Qi($f,$f,d,8);f.translate(0,d/2,0);let p=new G(f,u),m=new $i(Qf,Zf,8);m.translate(0,d+Zf/2,0);let h=new G(m,u),g=new ii;g.add(p),g.add(h);let _=new B(0,1,0),v=new mt().setFromUnitVectors(_,c);g.quaternion.copy(v),g.position.copy(l),g.scale.setScalar(Gf(t,g.position,.006)),p.onBeforeRender=(e,t,n)=>{g.scale.setScalar(Gf(n,g.position,.006)),g.updateMatrixWorld(!0)},this.add(g),this.position.z=.01}},tp=`#c88f40`,np=class extends ii{constructor(e){super();let t=e.sceneShapes[0]?.meshes[0];if(!t)return;let n=new Tr;n.setAttribute(`position`,new W(new Float32Array(t.vertices),3));let r=new qi(n,new fa({color:tp,dashSize:5,gapSize:5}));r.computeLineDistances(),this.add(r)}},rp={edge:{color:`#11a4ed`,lineWidth:3,depthWrite:!1},face:{color:`#5c9fcc`,opacity:1}},ip={edge:{opacity:.3},face:{opacity:.3}};function ap(e,t,n,r){if(r)return r;if(e===`select`)return rp;if(t&&n!==`sketch`)return ip}function op(e,t,n,r,i,a){switch(e.type){case`sketch`:return new Wf(e,t,n,r);case`plane`:return new ep(e,r);case`axis`:return new np(e)}let o=e.uniqueType===`select`,s=ap(e.uniqueType,n,e.type,a),c=t.filter(t=>t.parentId===e.id),l;if(c.length>0){let e=new ii;for(let a of c)e.add(op(a,t,n,r,i,s));l=e}else l=new Of(e,i,s);return o&&l.traverse(e=>{e.renderOrder=999}),l}function sp(e,t,n,r=!1){let i=new ii;i.name=`compiledMesh`;for(let a of e)a.parentId||!a.visible&&!(t&&a.type===`sketch`)||i.add(op(a,e,t,n,r));return i}var cp=`<svg
|
|
4308
|
+
`,af=class extends ii{constructor(e){super(),this.userData.isMetaShape=!0;for(let t of e.meshes){let e=t.vertices,n=t.indices,r=[];for(let t=0;t<n.length;t+=2){let i=n[t]*3;r.push(e[i],e[i+1],e[i+2])}if(n.length>=2){let t=n[n.length-1]*3;r.push(e[t],e[t+1],e[t+2])}let i=new Tr;i.setAttribute(`position`,new W(new Float32Array(r),3));let a=new Ui(i,new qr({uniforms:{color:{value:Nd.metaEdgeColor},dashLength:{value:Qd},gapLength:{value:$d},dotLength:{value:ef},patternLength:{value:tf}},vertexShader:nf,fragmentShader:rf,side:2,transparent:!0,polygonOffset:!0,polygonOffsetFactor:2,polygonOffsetUnits:1}));a.computeLineDistances(),this.add(a)}}},of=`#2297ff`,sf=2,cf=class extends ii{constructor(e){super(),this.userData.isMetaShape=!0;for(let t of e.meshes){let e=new Tr;e.setAttribute(`position`,new W(new Float32Array(t.vertices),3)),e.setAttribute(`normal`,new W(new Float32Array(t.normals),3));let n=t.vertices.length/3>65535?Uint32Array:Uint16Array;e.setIndex(new W(new n(t.indices),1));let r=new qi(e,new Fi({color:of,linewidth:sf,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1,side:2,depthWrite:!0,depthTest:!0}));this.add(r)}}},lf=`#2297ff`,uf=`#2297ff`,df=.15,ff=.4,pf=class extends ii{constructor(e,t){super(),this.userData.isMetaShape=!0,this.userData.isPickRegion=!0,this.userData.isPickRegionSelected=t,e.metaData&&(this.userData.metaData=e.metaData);let n=t?uf:lf,r=t?ff:df;for(let t of e.meshes){let e=new Tr;e.setAttribute(`position`,new W(new Float32Array(t.vertices),3)),e.setAttribute(`normal`,new W(new Float32Array(t.normals),3));let i=t.vertices.length/3>65535?Uint32Array:Uint16Array;e.setIndex(new W(new i(t.indices),1)),e.computeBoundingBox();let a=new G(e,new dr({color:n,transparent:!0,opacity:r,side:2,depthWrite:!1,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1}));this.add(a)}}},mf=`#2297ff`,hf=2,gf=2,_f=16,vf=.003,yf=1.5,bf=1e-8;function xf(e,t,n){if(e instanceof Pa)return(e.top-e.bottom)/e.zoom*n;if(e instanceof Qr){let r=e.position.distanceTo(t),i=e.fov*Math.PI/180;return 2*r*Math.tan(i/2)*n}return 1}var Sf=class extends ii{constructor(e){super(),this.userData.isMetaShape=!0;let t=new Zi(gf,_f),n=new dr({color:mf,side:2,depthTest:!0}),r=[];for(let t of e.meshes){let e=new Tr;e.setAttribute(`position`,new W(new Float32Array(t.vertices),3)),e.setAttribute(`normal`,new W(new Float32Array(t.normals),3));let n=t.vertices.length/3>65535?Uint32Array:Uint16Array;e.setIndex(new W(new n(t.indices),1));let i=new Fi({color:mf,linewidth:hf,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1,side:2,depthWrite:!0,depthTest:!0});this.add(new qi(e,i));let a=t.vertices,o=t.indices,s=new Map;for(let e of o)s.set(e,(s.get(e)||0)+1);for(let[e,t]of s)if(t===1){let t=new B(a[e*3],a[e*3+1],a[e*3+2]);r.some(e=>e.distanceToSquared(t)<bf)||r.push(t)}}for(let e of r){let r=new G(t,n);r.renderOrder=2;let i=new ii;i.renderOrder=2,i.userData.isVertexDot=!0,i.add(r),i.position.copy(e),r.onBeforeRender=(t,n,r)=>{i.scale.setScalar(Math.min(xf(r,e,vf),yf)),i.updateMatrixWorld(!0)},this.add(i)}}},Cf={color:`#2297ff`,lineWidth:2},wf={trim:e=>new cf(e),"pick-edge":e=>new Sf(e)};function Tf(e){let t=e.metaType?wf[e.metaType]:void 0;return t?t(e):new af(e)}var Ef={"pick-region":e=>new pf(e,!1),"pick-region-selected":e=>new pf(e,!0)};function Df(e){let t=e.metaType?Ef[e.metaType]:void 0;return t?t(e):new Xd(e)}var Of=class extends ii{constructor(e,t,n){if(super(),!e.sceneShapes)return;let r=e.sceneShapes.every(e=>e.isMetaShape||e.shapeType===`wire`||e.shapeType===`edge`),i=[`pick-region`,`pick-region-selected`,`pick-edge`];for(let a of e.sceneShapes){if(!t&&a.isMetaShape&&a.metaType&&i.includes(a.metaType))continue;let e;if(a.isMetaShape)switch(a.shapeType){case`wire`:case`edge`:e=Tf(a);break;case`face`:e=Df(a);break}else switch(a.shapeType){case`wire`:case`edge`:e=new Jd(a,n?.edge??(r?Cf:void 0));break;case`face`:e=new Xd(a,n?.face);break;case`solid`:e=new Zd(a,n);break}e&&(a.shapeId&&(e.userData.shapeId=a.shapeId),this.add(e))}}};function kf(e,t,n){if(e instanceof Pa)return(e.top-e.bottom)/e.zoom*n;if(e instanceof Qr){let r=e.position.distanceTo(t),i=e.fov*Math.PI/180;return 2*r*Math.tan(i/2)*n}return 1}var Af=`#2297ff`,jf=2,Mf=16,Nf=.003,Pf=1.5,Ff=15954511,If=64,Lf=3,Rf=15954511,zf=.35,Bf=.6,Vf=18,Hf=5,Uf=2.5,Wf=class extends ii{constructor(e,t,n,r){super(),this.buildEdges(e,t),this.buildVertices(e,t,r),n&&e.id===n&&(this.buildCursor(e,r),this.buildTangentArrow(e,r))}buildEdges(e,t){for(let n of t)if(!(n.parentId!==e.id||!n.sceneShapes.length))for(let e of n.sceneShapes){if(e.isMetaShape||e.isGuide){if(e.shapeType===`wire`||e.shapeType===`edge`){let t=Tf(e);e.shapeId&&(t.userData.shapeId=e.shapeId),this.add(t)}continue}let t=new Jd(e,{color:Af,lineWidth:2});e.shapeId&&(t.userData.shapeId=e.shapeId),this.add(t)}}buildVertices(e,t,n){let r=e.object?.plane?.normal,i=[];for(let n of t)if(!(n.parentId!==e.id||!n.sceneShapes.length)){for(let e of n.sceneShapes)if(!(e.isMetaShape||e.isGuide))for(let t of e.meshes){if(!t.indices.length)continue;let e=new Map;for(let n of t.indices)e.set(n,(e.get(n)||0)+1);for(let[n,r]of e)r===1&&i.push(new B(t.vertices[n*3],t.vertices[n*3+1],t.vertices[n*3+2]))}}let a=[];for(let e of i)a.some(t=>t.distanceToSquared(e)<1e-12)||a.push(e);let o=new Zi(jf,Mf),s=new dr({color:Af,side:2,depthTest:!1});for(let e of a){let t=new G(o,s);t.renderOrder=2;let i=new ii;i.renderOrder=2,i.userData.isVertexDot=!0,i.add(t),i.position.copy(e),r&&i.lookAt(new B(e.x+r.x,e.y+r.y,e.z+r.z)),i.scale.setScalar(Math.min(kf(n,e,Nf),Pf)),t.onBeforeRender=(t,n,r)=>{i.scale.setScalar(Math.min(kf(r,e,Nf),Pf)),i.updateMatrixWorld(!0)},this.add(i)}}buildCursor(e,t){let n=e.object?.currentPosition;if(!n)return;let r=new Zi(Lf,If),i=new dr({color:Ff,side:2,depthTest:!1});i.transparent=!0,i.opacity=.8;let a=new G(r,i);a.renderOrder=1;let o=new ii;o.renderOrder=1,o.add(a),o.position.set(n.x,n.y,n.z);let s=e.object?.plane?.normal;if(s){let e=new B(n.x+s.x,n.y+s.y,n.z+s.z);o.lookAt(e)}o.scale.setScalar(kf(t,o.position,.003)),a.onBeforeRender=(e,t,n)=>{o.scale.setScalar(kf(n,o.position,.003)),o.updateMatrixWorld(!0)},this.add(o)}buildTangentArrow(e,t){let n=e.object?.currentPosition,r=e.object?.currentTangent,i=e.object?.plane?.origin;if(!n||!r||!i)return;let a=new B(r.x-i.x,r.y-i.y,r.z-i.z).normalize(),o=new dr({color:Rf,transparent:!0,opacity:zf,depthTest:!1}),s=new Qi(Bf,Bf,Vf,8);s.translate(0,Vf/2,0);let c=new G(s,o),l=new $i(Uf,Hf,8);l.translate(0,Vf+Hf/2,0);let u=new G(l,o),d=new ii;d.renderOrder=1,d.add(c),d.add(u);let f=new B(0,1,0),p=new mt().setFromUnitVectors(f,a);d.quaternion.copy(p),d.position.set(n.x,n.y,n.z),d.scale.setScalar(kf(t,d.position,.003)),c.onBeforeRender=(e,t,n)=>{d.scale.setScalar(kf(n,d.position,.003)),d.updateMatrixWorld(!0)},this.add(d)}};function Gf(e,t,n){if(e instanceof Pa)return(e.top-e.bottom)/e.zoom*n;if(e instanceof Qr){let r=e.position.distanceTo(t),i=e.fov*Math.PI/180;return 2*r*Math.tan(i/2)*n}return 1}var Kf=`#ffc26c`,qf=`#c88f40`,Jf=`#c88f40`,Yf=.1,Xf=20,Zf=3,Qf=1.5,$f=.4,ep=class extends ii{constructor(e,t){super();let n=e.sceneShapes[0]?.meshes[0];if(!n)return;this.userData.isMetaShape=!0,this.userData.isConstructionPlane=!0;let r=e.object.normal,i=e.object.center,a=new Tr;a.setAttribute(`position`,new W(new Float32Array(n.vertices),3)),a.setAttribute(`normal`,new W(new Float32Array(n.normals),3)),a.setIndex(new W(new Uint16Array(n.indices),1)),a.computeBoundingBox();let o=new G(a,new dr({color:Kf,transparent:!0,opacity:Yf,side:2,polygonOffset:!0,polygonOffsetFactor:1,polygonOffsetUnits:1}));this.add(o);let s=new qi(new ia(a,18),new Fi({color:qf,linewidth:1}));this.add(s);let c=new B(r.x,r.y,r.z).normalize(),l=new B(i.x,i.y,i.z),u=new dr({color:Jf}),d=Xf-Zf,f=new Qi($f,$f,d,8);f.translate(0,d/2,0);let p=new G(f,u),m=new $i(Qf,Zf,8);m.translate(0,d+Zf/2,0);let h=new G(m,u),g=new ii;g.add(p),g.add(h);let _=new B(0,1,0),v=new mt().setFromUnitVectors(_,c);g.quaternion.copy(v),g.position.copy(l),g.scale.setScalar(Gf(t,g.position,.006)),p.onBeforeRender=(e,t,n)=>{g.scale.setScalar(Gf(n,g.position,.006)),g.updateMatrixWorld(!0)},this.add(g),this.position.z=.01}},tp=`#c88f40`,np=class extends ii{constructor(e){super();let t=e.sceneShapes[0]?.meshes[0];if(!t)return;let n=new Tr;n.setAttribute(`position`,new W(new Float32Array(t.vertices),3));let r=new qi(n,new fa({color:tp,dashSize:5,gapSize:5}));r.computeLineDistances(),this.add(r)}},rp={edge:{color:`#11a4ed`,lineWidth:3,depthWrite:!1},face:{color:`#5c9fcc`,opacity:1}},ip={edge:{opacity:.3},face:{opacity:.3}};function ap(e,t,n,r){if(r)return r;if(e===`select`)return rp;if(t&&n!==`sketch`)return ip}function op(e,t,n,r,i,a){switch(e.type){case`sketch`:return new Wf(e,t,n,r);case`plane`:return new ep(e,r);case`axis`:return new np(e)}let o=e.uniqueType===`select`,s=ap(e.uniqueType,n,e.type,a),c=t.filter(t=>t.parentId===e.id),l;if(c.length>0){let e=new ii;for(let a of c)e.add(op(a,t,n,r,i,s));l=e}else l=new Of(e,i,s);return o&&l.traverse(e=>{e.renderOrder=999}),l}function sp(e,t,n,r=!1){let i=new ii;i.name=`compiledMesh`;for(let a of e)a.parentId||!a.visible&&!(t&&a.type===`sketch`)||i.add(op(a,e,t,n,r));return i}var cp=`<svg
|
|
4309
4309
|
xmlns="http://www.w3.org/2000/svg"
|
|
4310
4310
|
width="24"
|
|
4311
4311
|
height="24"
|
|
@@ -4521,7 +4521,7 @@ void main() {
|
|
|
4521
4521
|
<button class="${Pp} ${e.showGrid?Fp:``}" data-action="grid" title="Toggle grid">${wp}</button>
|
|
4522
4522
|
<div class="h-px bg-base-content/[0.08] my-0.5"></div>
|
|
4523
4523
|
<button class="${Pp}" data-action="theme" title="${n}">${t}</button>
|
|
4524
|
-
`}bindEvents(){this.el.querySelector(`[data-action="fit"]`)?.addEventListener(`click`,()=>{this.onFitView?.()}),this.el.querySelectorAll(`[data-mode]`).forEach(e=>{e.addEventListener(`click`,()=>{let t=e.dataset.mode;Vd.update({cameraMode:t}),this.onCameraSwitch(t)})}),this.el.querySelector(`[data-action="grid"]`)?.addEventListener(`click`,()=>{Vd.update({showGrid:!Vd.current.showGrid})}),this.el.querySelector(`[data-action="theme"]`)?.addEventListener(`click`,()=>{let e=Lp()?`fluidcad-light`:`fluidcad-dark`;document.documentElement.setAttribute(`data-theme`,e),this.syncThemeButton(),fetch(`/api/preferences`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({theme:e})})})}setFitHandler(e){this.onFitView=e}setFitButtonVisible(e){let t=this.el.querySelector(`[data-action="fit"]`);t&&(t.style.display=e?``:`none`);let n=this.el.querySelector(`.h-px`);n&&(n.style.display=e?``:`none`)}setProjectionLocked(e){this.el.querySelectorAll(`[data-mode]`).forEach(t=>{t.disabled=e})}syncThemeButton(){let e=this.el.querySelector(`[data-action="theme"]`);e&&(e.innerHTML=Lp()?Mp:Np,e.title=Lp()?`Switch to light theme`:`Switch to dark theme`)}sync(){let e=Vd.current;this.el.querySelectorAll(`[data-mode]`).forEach(t=>{t.className=t.dataset.mode===e.cameraMode?Fp:Pp});let t=this.el.querySelector(`[data-action="grid"]`);t&&(t.className=e.showGrid?Fp:Pp)}},zp=class{mesh=null;show(e,t,n){this.clear(e);let r=new G(new oa(n,16,16),new dr({color:16729088,depthTest:!1}));r.position.set(t.x,t.y,t.z),r.renderOrder=999,r.userData.isMetaShape=!0,e.add(r),this.mesh=r}clear(e){this.mesh&&=(this.mesh.geometry.dispose(),this.mesh.material.dispose(),e.remove(this.mesh),null)}};function Bp(e,t){if(t.userData.isMetaShape)return;let n=t;(n.isMesh||n.isLine||n.isPoints)&&n.geometry&&(n.geometry.computeBoundingBox(),n.geometry.boundingBox&&e.union(n.geometry.boundingBox.clone().applyMatrix4(n.matrixWorld)));for(let n of t.children)Bp(e,n)}var Vp=`#ffc578`,Hp=`#ffc578`,Up=`#64B5F6`,Wp=`#64B5F6`,Gp=.3,Kp=class{ctx;modeManager;settingsPanel;sceneObjects=[];highlightedShapeId=null;faceHighlightMeshes=[];hasRendered=!1;lastFitBox=null;isTrimming=!1;isRegionPicking=!1;isBezierDrawing=!1;selectionHandler=null;centroidIndicator=new zp;hoverState=null;hoverFaceOverlayMeshes=[];hoverRafId=null;isMouseDown=!1;highlightedSub=null;constructor(e){let t=document.getElementById(e);this.ctx=new Rd(t),this.modeManager=new Kd(this.ctx),this.settingsPanel=new Rp(t,e=>this.ctx.switchCamera(e)),this.settingsPanel.setFitHandler(()=>this.fitViewToScene()),this.initClickDetection(),this.initHoverDetection()}get sceneContext(){return this.ctx}get currentSceneObjects(){return this.sceneObjects}setSelectionHandler(e){this.selectionHandler=e}initClickDetection(){let e=this.ctx.renderer.domElement,t=0,n=0;e.addEventListener(`mousedown`,e=>{t=e.clientX,n=e.clientY}),e.addEventListener(`mouseup`,e=>{if(!this.selectionHandler||this.isTrimming||this.isRegionPicking||this.isBezierDrawing)return;let r=e.clientX-t,i=e.clientY-n;if(r*r+i*i>64)return;this.clearHover();let a=this.pickAt(e.clientX,e.clientY);a?this.selectionHandler(a.shapeId,a.sub):this.selectionHandler(null,null)})}pickAt(e,t){let n=this.ctx.camera,r=this.ctx.renderer.domElement.getBoundingClientRect(),i=(e-r.left)/r.width*2-1,a=-((t-r.top)/r.height)*2+1,o=new to;o.setFromCamera(new z(i,a),n),o.params.Line={threshold:this.computeEdgePickThreshold()};let s=[],c=[];this.ctx.scene.traverse(e=>{e.userData.isMetaShape||(e.isMesh&&e.userData.faceMapping?s.push(e):e.isLine&&e.userData.edgeIndex!==void 0&&c.push(e))});let l=s.length>0?o.intersectObjects(s,!1):[],u=c.length>0?o.intersectObjects(c,!1):[];if(l.length===0&&u.length===0)return null;let d=new B;n.getWorldDirection(d);let f;for(let e of l){if(!e.face){f=e;break}if(e.face.normal.clone().transformDirection(e.object.matrixWorld).dot(d)<0){f=e;break}}let p=f==null?1/0:f.distance,m=o.ray.origin,h=o.ray.direction,g=new B,_=new B;for(let e of u){let t=e.object.geometry,n=t.getAttribute(`position`),r=t.getIndex();if(r!==null&&e.faceIndex!=null){let t=r.getX(e.faceIndex*2),i=r.getX(e.faceIndex*2+1),a=new B().fromBufferAttribute(n,t).applyMatrix4(e.object.matrixWorld),s=new B().fromBufferAttribute(n,i).applyMatrix4(e.object.matrixWorld);o.ray.distanceSqToSegment(a,s,void 0,g)}else g.copy(e.point);if(h.dot(_.copy(g).sub(m))<=p+.001){let t=e.object.userData.edgeIndex,n=this.findShapeIdForObject(e.object);if(n)return{shapeId:n,sub:{type:`edge`,index:t}}}}if(f){let e=f.object.userData.faceMapping;if(!e||f.faceIndex==null)return null;let t=e[f.faceIndex];if(t==null)return null;let n=this.findShapeIdForObject(f.object);if(n)return{shapeId:n,sub:{type:`face`,index:t}}}return null}findShapeIdForObject(e){let t=e;for(;t;){if(t.userData.shapeId&&!t.userData.isMetaShape)return t.userData.shapeId;t=t.parent}return null}toggleSketchMode(e){this.modeManager.sketchEnabled=e}setFileName(e){}updateView(e,t=!1){if(this.sceneObjects=e,this.highlightedShapeId=null,this.highlightedSub=null,this.hoverState=null,this.hoverFaceOverlayMeshes=[],this.ctx.renderer.domElement.style.cursor=``,this.removeCompiledMesh(),!t){let t=this.findActiveObject(e);t?.type===`sketch`&&t.object?.plane?(this.modeManager.isSketchMode?this.modeManager.enforceSketchNormal(t.object.plane):this.modeManager.enterSketchMode(t.object.plane),this.settingsPanel.setProjectionLocked(!0),this.settingsPanel.setFitButtonVisible(!1)):(this.modeManager.enterDefaultMode(),this.settingsPanel.setProjectionLocked(!1),this.settingsPanel.setFitButtonVisible(!0),this.lastFitBox=null)}let n=sp(e,this.modeManager.isSketchMode,this.ctx.camera,this.isRegionPicking);if(this.ctx.scene.add(n),!this.hasRendered||this.modeManager.isSketchMode&&!t&&!this.isTrimming&&!this.isRegionPicking&&!this.isBezierDrawing){let e=new Ht;Bp(e,n),!e.isEmpty()&&!this.isBoxContained(e)&&(this.ctx.fitToBox(e,!0),this.lastFitBox=e.clone(),this.hasRendered=!0)}this.ctx.requestRender()}highlightShape(e){this.clearHighlight();let t=this.findShapeById(e);if(!t)return;let n=this.findMeshByShapeId(e);if(!n)return;let r=t.shapeType===`solid`||t.shapeType===`face`;n.traverse(e=>{e.material&&(r&&e instanceof G?(e.userData.originalColor=e.material.color.getHex(),e.material.color.set(Vp)):!r&&e instanceof qi&&(e.userData.originalColor=e.material.color.getHex(),e.material.color.set(Hp),e.material.opacity<1&&(e.userData.originalOpacity=e.material.opacity,e.material.opacity=1)))}),this.highlightedShapeId=e,this.highlightedSub=null,this.ctx.render()}clearHighlight(){if(!(!this.highlightedShapeId&&this.faceHighlightMeshes.length===0)){this.ctx.scene.traverse(e=>{e.userData.originalColor!==void 0&&(e.material.color.setHex(e.userData.originalColor),delete e.userData.originalColor),e.userData.originalOpacity!==void 0&&(e.material.opacity=e.userData.originalOpacity,delete e.userData.originalOpacity)});for(let e of this.faceHighlightMeshes)e.parent?.remove(e),e.geometry.dispose(),e.material.dispose();this.faceHighlightMeshes=[],this.highlightedShapeId=null,this.highlightedSub=null,this.ctx.render()}}highlightFace(e,t){this.clearHighlight(),this.ctx.scene.traverse(n=>{if(!n.isMesh)return;let r=n.userData.faceMapping;if(!r)return;let i=!1,a=n;for(;a;){if(a.userData.shapeId===e&&!a.userData.isMetaShape){i=!0;break}a=a.parent}if(!i)return;let o=n,s=o.geometry,c=s.index;if(!c)return;let l=c.array,u=s.getAttribute(`position`).array,d=[];for(let e=0;e<r.length;e++)if(r[e]===t){let t=l[e*3]*3,n=l[e*3+1]*3,r=l[e*3+2]*3;d.push(u[t],u[t+1],u[t+2]),d.push(u[n],u[n+1],u[n+2]),d.push(u[r],u[r+1],u[r+2])}if(d.length===0)return;let f=new Tr;f.setAttribute(`position`,new W(new Float32Array(d),3));let p=new G(f,new la({color:Vp,polygonOffset:!0,polygonOffsetFactor:-2,polygonOffsetUnits:-1}));(o.parent??this.ctx.scene).add(p),this.faceHighlightMeshes.push(p)}),this.highlightedShapeId=e,this.highlightedSub={type:`face`,index:t},this.ctx.render()}highlightEdge(e,t){this.clearHighlight(),this.ctx.scene.traverse(n=>{if(!n.isLine||n.userData.edgeIndex!==t)return;let r=!1,i=n;for(;i;){if(i.userData.shapeId===e&&!i.userData.isMetaShape){r=!0;break}i=i.parent}r&&(n.userData.originalColor=n.material.color.getHex(),n.material.color.set(Hp))}),this.highlightedShapeId=e,this.highlightedSub={type:`edge`,index:t},this.ctx.render()}initHoverDetection(){let e=this.ctx.renderer.domElement;e.addEventListener(`mousedown`,()=>{this.isMouseDown=!0,this.clearHover()}),e.addEventListener(`mouseup`,()=>{this.isMouseDown=!1}),e.addEventListener(`mousemove`,e=>{this.isMouseDown||this.isTrimming||this.isRegionPicking||this.isBezierDrawing||this.hoverRafId===null&&(this.hoverRafId=requestAnimationFrame(()=>{this.hoverRafId=null,this.updateHover(e.clientX,e.clientY)}))}),e.addEventListener(`mouseleave`,()=>{this.clearHover()})}updateHover(e,t){if(!this.selectionHandler)return;let n=this.pickAt(e,t);if(!(this.hoverState&&n&&this.hoverState.shapeId===n.shapeId&&this.hoverState.sub?.type===n.sub?.type&&this.hoverState.sub?.index===n.sub?.index)){if(!n){this.hoverState&&this.clearHover();return}if(this.highlightedShapeId===n.shapeId&&this.highlightedSub?.type===n.sub?.type&&this.highlightedSub?.index===n.sub?.index){this.hoverState&&this.clearHover();return}this.clearHover(),this.hoverState=n,this.ctx.renderer.domElement.style.cursor=`pointer`,n.sub?.type===`face`?this.applyHoverFace(n.shapeId,n.sub.index):n.sub?.type===`edge`&&this.applyHoverEdge(n.shapeId,n.sub.index)}}clearHover(){for(let e of this.hoverFaceOverlayMeshes)e.parent?.remove(e),e.geometry.dispose(),e.material.dispose();this.hoverFaceOverlayMeshes=[],this.ctx.scene.traverse(e=>{e.userData.hoverOriginalColor!==void 0&&(e.material.color.setHex(e.userData.hoverOriginalColor),delete e.userData.hoverOriginalColor)}),this.hoverState=null,this.ctx.renderer.domElement.style.cursor=``,this.ctx.requestRender()}applyHoverFace(e,t){this.ctx.scene.traverse(n=>{if(!n.isMesh)return;let r=n.userData.faceMapping;if(!r)return;let i=!1,a=n;for(;a;){if(a.userData.shapeId===e&&!a.userData.isMetaShape){i=!0;break}a=a.parent}if(!i)return;let o=n,s=o.geometry,c=s.index;if(!c)return;let l=c.array,u=s.getAttribute(`position`).array,d=[];for(let e=0;e<r.length;e++)if(r[e]===t){let t=l[e*3]*3,n=l[e*3+1]*3,r=l[e*3+2]*3;d.push(u[t],u[t+1],u[t+2]),d.push(u[n],u[n+1],u[n+2]),d.push(u[r],u[r+1],u[r+2])}if(d.length===0)return;let f=new Tr;f.setAttribute(`position`,new W(new Float32Array(d),3));let p=new G(f,new la({color:Up,transparent:!0,opacity:Gp,depthWrite:!1,polygonOffset:!0,polygonOffsetFactor:-2,polygonOffsetUnits:-1}));(o.parent??this.ctx.scene).add(p),this.hoverFaceOverlayMeshes.push(p)}),this.ctx.requestRender()}applyHoverEdge(e,t){this.ctx.scene.traverse(n=>{if(!n.isLine||n.userData.edgeIndex!==t)return;let r=!1,i=n;for(;i;){if(i.userData.shapeId===e&&!i.userData.isMetaShape){r=!0;break}i=i.parent}r&&(n.userData.hoverOriginalColor=n.material.color.getHex(),n.material.color.set(Wp))}),this.ctx.requestRender()}showCentroid(e){let t=this.computeCentroidRadius();this.centroidIndicator.show(this.ctx.scene,e,t),this.ctx.requestRender()}clearCentroid(){this.centroidIndicator.clear(this.ctx.scene),this.ctx.requestRender()}dispose(){this.ctx.dispose()}computeEdgePickThreshold(){let e=this.ctx.camera,t=this.ctx.renderer.domElement.getBoundingClientRect().height||1,n,r=e;if(r.isOrthographicCamera)n=(r.top-r.bottom)/(r.zoom||1);else{let t=new B;this.ctx.cameraControls.getTarget(t);let i=e.position.distanceTo(t),a=r.fov*Math.PI/180;n=2*i*Math.tan(a/2)}return n/t*8}computeCentroidRadius(){let e=this.ctx.scene.getObjectByName(`compiledMesh`);if(e){let t=new Ht;if(Bp(t,e),!t.isEmpty())return t.getSize(new B).length()*.015}return 2}fitViewToScene(){let e=this.ctx.scene.getObjectByName(`compiledMesh`);if(!e)return;let t=new Ht;Bp(t,e),t.isEmpty()||this.ctx.fitToBox(t,!0)}findShapeById(e){for(let t of this.sceneObjects)for(let n of t.sceneShapes)if(n.shapeId===e)return n}findMeshByShapeId(e){let t;return this.ctx.scene.traverse(n=>{n.userData.shapeId===e&&(t=n)}),t}findActiveObject(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(!n.parentId&&(n.visible||n.type===`sketch`)||n.parentId&&(n.visible||n.type===`sketch`)&&e.find(e=>e.id===n.parentId)?.type===`part`)return n}}isBoxContained(e){if(!this.lastFitBox)return!1;let t=this.lastFitBox.getCenter(new B),n=this.lastFitBox.getSize(new B).length()/2*Ld;if(n===0)return!1;let r=e.getCenter(new B),i=e.getSize(new B).length()/2;return t.distanceTo(r)+i<=n}rebuildSceneMesh(){if(!this.sceneObjects)return;this.removeCompiledMesh();let e=sp(this.sceneObjects,this.modeManager.isSketchMode,this.ctx.camera,this.isRegionPicking);this.ctx.scene.add(e),this.ctx.requestRender()}removeCompiledMesh(){let e=this.ctx.scene.getObjectByName(`compiledMesh`);e&&(e.traverse(e=>{e.geometry?.dispose(),Array.isArray(e.material)?e.material.forEach(e=>e.dispose()):e.material?.dispose()}),this.ctx.scene.remove(e))}};function qp(e){switch(e){case`inch`:return 16.387064;case`foot`:return 28316.846592;case`yard`:return 764554.857984;case`meter`:return 1e6;default:return .001}}function Jp(e){switch(e){case`inch`:return`in`;case`foot`:return`ft`;case`yard`:return`yd`;case`meter`:return`m`;default:return`mm`}}function Yp(e,t,n){let r=t===`kg`?1e3:t===`lbs`?453.592:1;return e*qp(n)/r}function Xp(e,t){switch(t){case`kg/m³`:return e*.001;case`g/mm³`:return e*1e3;case`lbs/in³`:return e*27.6799;default:return e}}function Zp(e,t){switch(t){case`kg/m³`:return e/.001;case`g/mm³`:return e/1e3;case`lbs/in³`:return e/27.6799;default:return e}}function Qp(e){return e===0?`0`:parseFloat(e.toPrecision(6)).toString()}var $p=class{btn;panel;placeholderEl;formEl;selectEl;densityEl;densityUnitSelectEl;lengthUnitEl;massUnitEl;calcBtn;resultsEl;errorEl;volVal;areaVal;massVal;centroidVal;selectedShapeId=null;rawProps=null;canonicalDensityGcm3=null;currentDensityUnit=`g/cm³`;centroidHandler=null;openHandler=null;constructor(e){this.btn=document.createElement(`button`),this.btn.className=`btn btn-ghost btn-square btn-sm rounded-md absolute bottom-6 right-8 z-[100] panel-bg border border-base-content/10 text-base-content/60`,this.btn.title=`Shape Properties`,this.btn.innerHTML=Tp,e.appendChild(this.btn),this.panel=document.createElement(`div`),this.panel.className=`absolute bottom-[68px] right-6 w-[300px] bg-base-100/95 backdrop-blur-xl border border-base-content/10 rounded-lg p-4 z-[200] shadow-[0_4px_24px_rgba(0,0,0,0.5)] text-base-content text-[13px] hidden`,this.panel.innerHTML=this.buildHTML(),e.appendChild(this.panel),this.bindRefs(),this.bindEvents(),this.loadMaterials()}buildHTML(){return`
|
|
4524
|
+
`}bindEvents(){this.el.querySelector(`[data-action="fit"]`)?.addEventListener(`click`,()=>{this.onFitView?.()}),this.el.querySelectorAll(`[data-mode]`).forEach(e=>{e.addEventListener(`click`,()=>{let t=e.dataset.mode;Vd.update({cameraMode:t}),this.onCameraSwitch(t)})}),this.el.querySelector(`[data-action="grid"]`)?.addEventListener(`click`,()=>{Vd.update({showGrid:!Vd.current.showGrid})}),this.el.querySelector(`[data-action="theme"]`)?.addEventListener(`click`,()=>{let e=Lp()?`fluidcad-light`:`fluidcad-dark`;document.documentElement.setAttribute(`data-theme`,e),this.syncThemeButton(),fetch(`/api/preferences`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({theme:e})})})}setFitHandler(e){this.onFitView=e}setFitButtonVisible(e){let t=this.el.querySelector(`[data-action="fit"]`);t&&(t.style.display=e?``:`none`);let n=this.el.querySelector(`.h-px`);n&&(n.style.display=e?``:`none`)}setProjectionLocked(e){this.el.querySelectorAll(`[data-mode]`).forEach(t=>{t.disabled=e})}syncThemeButton(){let e=this.el.querySelector(`[data-action="theme"]`);e&&(e.innerHTML=Lp()?Mp:Np,e.title=Lp()?`Switch to light theme`:`Switch to dark theme`)}sync(){let e=Vd.current;this.el.querySelectorAll(`[data-mode]`).forEach(t=>{t.className=t.dataset.mode===e.cameraMode?Fp:Pp});let t=this.el.querySelector(`[data-action="grid"]`);t&&(t.className=e.showGrid?Fp:Pp)}},zp=class{mesh=null;show(e,t,n){this.clear(e);let r=new G(new oa(n,16,16),new dr({color:16729088,depthTest:!1}));r.position.set(t.x,t.y,t.z),r.renderOrder=999,r.userData.isMetaShape=!0,e.add(r),this.mesh=r}clear(e){this.mesh&&=(this.mesh.geometry.dispose(),this.mesh.material.dispose(),e.remove(this.mesh),null)}};function Bp(e,t){if(t.userData.isMetaShape)return;let n=t;(n.isMesh||n.isLine||n.isPoints)&&n.geometry&&(n.geometry.computeBoundingBox(),n.geometry.boundingBox&&e.union(n.geometry.boundingBox.clone().applyMatrix4(n.matrixWorld)));for(let n of t.children)Bp(e,n)}var Vp=`#ffc578`,Hp=`#ffc578`,Up=`#64B5F6`,Wp=`#64B5F6`,Gp=.3,Kp=class{ctx;modeManager;settingsPanel;sceneObjects=[];highlightedShapeId=null;faceHighlightMeshes=[];hasRendered=!1;lastFitBox=null;isTrimming=!1;isRegionPicking=!1;isBezierDrawing=!1;selectionHandler=null;centroidIndicator=new zp;hoverState=null;hoverFaceOverlayMeshes=[];hoverRafId=null;isMouseDown=!1;highlightedSub=null;activeSketchId=null;constructor(e){let t=document.getElementById(e);this.ctx=new Rd(t),this.modeManager=new Kd(this.ctx),this.settingsPanel=new Rp(t,e=>this.ctx.switchCamera(e)),this.settingsPanel.setFitHandler(()=>this.fitViewToScene()),this.initClickDetection(),this.initHoverDetection()}get sceneContext(){return this.ctx}get currentSceneObjects(){return this.sceneObjects}setSelectionHandler(e){this.selectionHandler=e}initClickDetection(){let e=this.ctx.renderer.domElement,t=0,n=0;e.addEventListener(`mousedown`,e=>{t=e.clientX,n=e.clientY}),e.addEventListener(`mouseup`,e=>{if(!this.selectionHandler||this.isTrimming||this.isRegionPicking||this.isBezierDrawing)return;let r=e.clientX-t,i=e.clientY-n;if(r*r+i*i>64)return;this.clearHover();let a=this.pickAt(e.clientX,e.clientY);a?this.selectionHandler(a.shapeId,a.sub):this.selectionHandler(null,null)})}pickAt(e,t){let n=this.ctx.camera,r=this.ctx.renderer.domElement.getBoundingClientRect(),i=(e-r.left)/r.width*2-1,a=-((t-r.top)/r.height)*2+1,o=new to;o.setFromCamera(new z(i,a),n),o.params.Line={threshold:this.computeEdgePickThreshold()};let s=[],c=[];this.ctx.scene.traverse(e=>{e.userData.isMetaShape||(e.isMesh&&e.userData.faceMapping?s.push(e):e.isLine&&e.userData.edgeIndex!==void 0&&c.push(e))});let l=s.length>0?o.intersectObjects(s,!1):[],u=c.length>0?o.intersectObjects(c,!1):[];if(l.length===0&&u.length===0)return null;let d=new B;n.getWorldDirection(d);let f;for(let e of l){if(!e.face){f=e;break}if(e.face.normal.clone().transformDirection(e.object.matrixWorld).dot(d)<0){f=e;break}}let p=f==null?1/0:f.distance,m=o.ray.origin,h=o.ray.direction,g=new B,_=new B;for(let e of u){let t=e.object.geometry,n=t.getAttribute(`position`),r=t.getIndex();if(r!==null&&e.faceIndex!=null){let t=r.getX(e.faceIndex*2),i=r.getX(e.faceIndex*2+1),a=new B().fromBufferAttribute(n,t).applyMatrix4(e.object.matrixWorld),s=new B().fromBufferAttribute(n,i).applyMatrix4(e.object.matrixWorld);o.ray.distanceSqToSegment(a,s,void 0,g)}else g.copy(e.point);if(h.dot(_.copy(g).sub(m))<=p+.001){let t=e.object.userData.edgeIndex,n=this.findShapeIdForObject(e.object);if(n)return{shapeId:n,sub:{type:`edge`,index:t}}}}if(f){let e=f.object.userData.faceMapping;if(!e||f.faceIndex==null)return null;let t=e[f.faceIndex];if(t==null)return null;let n=this.findShapeIdForObject(f.object);if(n)return{shapeId:n,sub:{type:`face`,index:t}}}return null}findShapeIdForObject(e){let t=e;for(;t;){if(t.userData.shapeId&&!t.userData.isMetaShape)return t.userData.shapeId;t=t.parent}return null}toggleSketchMode(e){this.modeManager.sketchEnabled=e}setFileName(e){}updateView(e,t=!1){if(this.sceneObjects=e,this.highlightedShapeId=null,this.highlightedSub=null,this.hoverState=null,this.hoverFaceOverlayMeshes=[],this.ctx.renderer.domElement.style.cursor=``,this.removeCompiledMesh(),!t){let t=this.findActiveObject(e);t?.type===`sketch`&&t.object?.plane?(this.modeManager.isSketchMode?this.modeManager.enforceSketchNormal(t.object.plane):this.modeManager.enterSketchMode(t.object.plane),this.activeSketchId=t.id,this.settingsPanel.setProjectionLocked(!0),this.settingsPanel.setFitButtonVisible(!1)):(this.activeSketchId=null,this.modeManager.enterDefaultMode(),this.settingsPanel.setProjectionLocked(!1),this.settingsPanel.setFitButtonVisible(!0),this.lastFitBox=null)}let n=sp(e,this.activeSketchId,this.ctx.camera,this.isRegionPicking);if(this.ctx.scene.add(n),!this.hasRendered||this.modeManager.isSketchMode&&!t&&!this.isTrimming&&!this.isRegionPicking&&!this.isBezierDrawing){let e=new Ht;Bp(e,n),!e.isEmpty()&&!this.isBoxContained(e)&&(this.ctx.fitToBox(e,!0),this.lastFitBox=e.clone(),this.hasRendered=!0)}this.ctx.requestRender()}highlightShape(e){this.clearHighlight();let t=this.findShapeById(e);if(!t)return;let n=this.findMeshByShapeId(e);if(!n)return;let r=t.shapeType===`solid`||t.shapeType===`face`;n.traverse(e=>{e.material&&(r&&e instanceof G?(e.userData.originalColor=e.material.color.getHex(),e.material.color.set(Vp)):!r&&e instanceof qi&&(e.userData.originalColor=e.material.color.getHex(),e.material.color.set(Hp),e.material.opacity<1&&(e.userData.originalOpacity=e.material.opacity,e.material.opacity=1)))}),this.highlightedShapeId=e,this.highlightedSub=null,this.ctx.render()}clearHighlight(){if(!(!this.highlightedShapeId&&this.faceHighlightMeshes.length===0)){this.ctx.scene.traverse(e=>{e.userData.originalColor!==void 0&&(e.material.color.setHex(e.userData.originalColor),delete e.userData.originalColor),e.userData.originalOpacity!==void 0&&(e.material.opacity=e.userData.originalOpacity,delete e.userData.originalOpacity)});for(let e of this.faceHighlightMeshes)e.parent?.remove(e),e.geometry.dispose(),e.material.dispose();this.faceHighlightMeshes=[],this.highlightedShapeId=null,this.highlightedSub=null,this.ctx.render()}}highlightFace(e,t){this.clearHighlight(),this.ctx.scene.traverse(n=>{if(!n.isMesh)return;let r=n.userData.faceMapping;if(!r)return;let i=!1,a=n;for(;a;){if(a.userData.shapeId===e&&!a.userData.isMetaShape){i=!0;break}a=a.parent}if(!i)return;let o=n,s=o.geometry,c=s.index;if(!c)return;let l=c.array,u=s.getAttribute(`position`).array,d=[];for(let e=0;e<r.length;e++)if(r[e]===t){let t=l[e*3]*3,n=l[e*3+1]*3,r=l[e*3+2]*3;d.push(u[t],u[t+1],u[t+2]),d.push(u[n],u[n+1],u[n+2]),d.push(u[r],u[r+1],u[r+2])}if(d.length===0)return;let f=new Tr;f.setAttribute(`position`,new W(new Float32Array(d),3));let p=new G(f,new la({color:Vp,polygonOffset:!0,polygonOffsetFactor:-2,polygonOffsetUnits:-1}));(o.parent??this.ctx.scene).add(p),this.faceHighlightMeshes.push(p)}),this.highlightedShapeId=e,this.highlightedSub={type:`face`,index:t},this.ctx.render()}highlightEdge(e,t){this.clearHighlight(),this.ctx.scene.traverse(n=>{if(!n.isLine||n.userData.edgeIndex!==t)return;let r=!1,i=n;for(;i;){if(i.userData.shapeId===e&&!i.userData.isMetaShape){r=!0;break}i=i.parent}r&&(n.userData.originalColor=n.material.color.getHex(),n.material.color.set(Hp))}),this.highlightedShapeId=e,this.highlightedSub={type:`edge`,index:t},this.ctx.render()}initHoverDetection(){let e=this.ctx.renderer.domElement;e.addEventListener(`mousedown`,()=>{this.isMouseDown=!0,this.clearHover()}),e.addEventListener(`mouseup`,()=>{this.isMouseDown=!1}),e.addEventListener(`mousemove`,e=>{this.isMouseDown||this.isTrimming||this.isRegionPicking||this.isBezierDrawing||this.hoverRafId===null&&(this.hoverRafId=requestAnimationFrame(()=>{this.hoverRafId=null,this.updateHover(e.clientX,e.clientY)}))}),e.addEventListener(`mouseleave`,()=>{this.clearHover()})}updateHover(e,t){if(!this.selectionHandler)return;let n=this.pickAt(e,t);if(!(this.hoverState&&n&&this.hoverState.shapeId===n.shapeId&&this.hoverState.sub?.type===n.sub?.type&&this.hoverState.sub?.index===n.sub?.index)){if(!n){this.hoverState&&this.clearHover();return}if(this.highlightedShapeId===n.shapeId&&this.highlightedSub?.type===n.sub?.type&&this.highlightedSub?.index===n.sub?.index){this.hoverState&&this.clearHover();return}this.clearHover(),this.hoverState=n,this.ctx.renderer.domElement.style.cursor=`pointer`,n.sub?.type===`face`?this.applyHoverFace(n.shapeId,n.sub.index):n.sub?.type===`edge`&&this.applyHoverEdge(n.shapeId,n.sub.index)}}clearHover(){for(let e of this.hoverFaceOverlayMeshes)e.parent?.remove(e),e.geometry.dispose(),e.material.dispose();this.hoverFaceOverlayMeshes=[],this.ctx.scene.traverse(e=>{e.userData.hoverOriginalColor!==void 0&&(e.material.color.setHex(e.userData.hoverOriginalColor),delete e.userData.hoverOriginalColor)}),this.hoverState=null,this.ctx.renderer.domElement.style.cursor=``,this.ctx.requestRender()}applyHoverFace(e,t){this.ctx.scene.traverse(n=>{if(!n.isMesh)return;let r=n.userData.faceMapping;if(!r)return;let i=!1,a=n;for(;a;){if(a.userData.shapeId===e&&!a.userData.isMetaShape){i=!0;break}a=a.parent}if(!i)return;let o=n,s=o.geometry,c=s.index;if(!c)return;let l=c.array,u=s.getAttribute(`position`).array,d=[];for(let e=0;e<r.length;e++)if(r[e]===t){let t=l[e*3]*3,n=l[e*3+1]*3,r=l[e*3+2]*3;d.push(u[t],u[t+1],u[t+2]),d.push(u[n],u[n+1],u[n+2]),d.push(u[r],u[r+1],u[r+2])}if(d.length===0)return;let f=new Tr;f.setAttribute(`position`,new W(new Float32Array(d),3));let p=new G(f,new la({color:Up,transparent:!0,opacity:Gp,depthWrite:!1,polygonOffset:!0,polygonOffsetFactor:-2,polygonOffsetUnits:-1}));(o.parent??this.ctx.scene).add(p),this.hoverFaceOverlayMeshes.push(p)}),this.ctx.requestRender()}applyHoverEdge(e,t){this.ctx.scene.traverse(n=>{if(!n.isLine||n.userData.edgeIndex!==t)return;let r=!1,i=n;for(;i;){if(i.userData.shapeId===e&&!i.userData.isMetaShape){r=!0;break}i=i.parent}r&&(n.userData.hoverOriginalColor=n.material.color.getHex(),n.material.color.set(Wp))}),this.ctx.requestRender()}showCentroid(e){let t=this.computeCentroidRadius();this.centroidIndicator.show(this.ctx.scene,e,t),this.ctx.requestRender()}clearCentroid(){this.centroidIndicator.clear(this.ctx.scene),this.ctx.requestRender()}dispose(){this.ctx.dispose()}computeEdgePickThreshold(){let e=this.ctx.camera,t=this.ctx.renderer.domElement.getBoundingClientRect().height||1,n,r=e;if(r.isOrthographicCamera)n=(r.top-r.bottom)/(r.zoom||1);else{let t=new B;this.ctx.cameraControls.getTarget(t);let i=e.position.distanceTo(t),a=r.fov*Math.PI/180;n=2*i*Math.tan(a/2)}return n/t*8}computeCentroidRadius(){let e=this.ctx.scene.getObjectByName(`compiledMesh`);if(e){let t=new Ht;if(Bp(t,e),!t.isEmpty())return t.getSize(new B).length()*.015}return 2}fitViewToScene(){let e=this.ctx.scene.getObjectByName(`compiledMesh`);if(!e)return;let t=new Ht;Bp(t,e),t.isEmpty()||this.ctx.fitToBox(t,!0)}findShapeById(e){for(let t of this.sceneObjects)for(let n of t.sceneShapes)if(n.shapeId===e)return n}findMeshByShapeId(e){let t;return this.ctx.scene.traverse(n=>{n.userData.shapeId===e&&(t=n)}),t}findActiveObject(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(!n.parentId&&(n.visible||n.type===`sketch`)||n.parentId&&(n.visible||n.type===`sketch`)&&e.find(e=>e.id===n.parentId)?.type===`part`)return n}}isBoxContained(e){if(!this.lastFitBox)return!1;let t=this.lastFitBox.getCenter(new B),n=this.lastFitBox.getSize(new B).length()/2*Ld;if(n===0)return!1;let r=e.getCenter(new B),i=e.getSize(new B).length()/2;return t.distanceTo(r)+i<=n}rebuildSceneMesh(){if(!this.sceneObjects)return;this.removeCompiledMesh();let e=sp(this.sceneObjects,this.activeSketchId,this.ctx.camera,this.isRegionPicking);this.ctx.scene.add(e),this.ctx.requestRender()}removeCompiledMesh(){let e=this.ctx.scene.getObjectByName(`compiledMesh`);e&&(e.traverse(e=>{e.geometry?.dispose(),Array.isArray(e.material)?e.material.forEach(e=>e.dispose()):e.material?.dispose()}),this.ctx.scene.remove(e))}};function qp(e){switch(e){case`inch`:return 16.387064;case`foot`:return 28316.846592;case`yard`:return 764554.857984;case`meter`:return 1e6;default:return .001}}function Jp(e){switch(e){case`inch`:return`in`;case`foot`:return`ft`;case`yard`:return`yd`;case`meter`:return`m`;default:return`mm`}}function Yp(e,t,n){let r=t===`kg`?1e3:t===`lbs`?453.592:1;return e*qp(n)/r}function Xp(e,t){switch(t){case`kg/m³`:return e*.001;case`g/mm³`:return e*1e3;case`lbs/in³`:return e*27.6799;default:return e}}function Zp(e,t){switch(t){case`kg/m³`:return e/.001;case`g/mm³`:return e/1e3;case`lbs/in³`:return e/27.6799;default:return e}}function Qp(e){return e===0?`0`:parseFloat(e.toPrecision(6)).toString()}var $p=class{btn;panel;placeholderEl;formEl;selectEl;densityEl;densityUnitSelectEl;lengthUnitEl;massUnitEl;calcBtn;resultsEl;errorEl;volVal;areaVal;massVal;centroidVal;selectedShapeId=null;rawProps=null;canonicalDensityGcm3=null;currentDensityUnit=`g/cm³`;centroidHandler=null;openHandler=null;constructor(e){this.btn=document.createElement(`button`),this.btn.className=`btn btn-ghost btn-square btn-sm rounded-md absolute bottom-6 right-8 z-[100] panel-bg border border-base-content/10 text-base-content/60`,this.btn.title=`Shape Properties`,this.btn.innerHTML=Tp,e.appendChild(this.btn),this.panel=document.createElement(`div`),this.panel.className=`absolute bottom-[68px] right-6 w-[300px] bg-base-100/95 backdrop-blur-xl border border-base-content/10 rounded-lg p-4 z-[200] shadow-[0_4px_24px_rgba(0,0,0,0.5)] text-base-content text-[13px] hidden`,this.panel.innerHTML=this.buildHTML(),e.appendChild(this.panel),this.bindRefs(),this.bindEvents(),this.loadMaterials()}buildHTML(){return`
|
|
4525
4525
|
<div class="flex items-center justify-between mb-3">
|
|
4526
4526
|
<span class="text-xs font-semibold text-base-content/70 uppercase tracking-wider">Shape Properties</span>
|
|
4527
4527
|
<button class="btn btn-ghost btn-xs btn-square" data-action="panel-close">×</button>
|
package/ui/dist/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>FluidCAD Viewer</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-BJG141m7.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-BpvgjPLm.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body class="m-0 p-0 overflow-hidden w-full h-full bg-base-100 text-base-content">
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { GeometrySceneObject } from "./geometry.js";
|
|
2
|
-
import { LazyVertex } from "../lazy-vertex.js";
|
|
3
|
-
import { PlaneObjectBase } from "../plane-renderable-base.js";
|
|
4
|
-
export declare class ArcThreePoints extends GeometrySceneObject {
|
|
5
|
-
startPoint: LazyVertex;
|
|
6
|
-
endPoint: LazyVertex;
|
|
7
|
-
center: LazyVertex;
|
|
8
|
-
private targetPlane;
|
|
9
|
-
constructor(startPoint: LazyVertex, endPoint: LazyVertex, center: LazyVertex, targetPlane?: PlaneObjectBase);
|
|
10
|
-
build(): void;
|
|
11
|
-
compareTo(other: ArcThreePoints): boolean;
|
|
12
|
-
getType(): string;
|
|
13
|
-
getUniqueType(): string;
|
|
14
|
-
serialize(): {
|
|
15
|
-
startPoint: {};
|
|
16
|
-
endPoint: {};
|
|
17
|
-
center: {};
|
|
18
|
-
};
|
|
19
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { Vertex } from "../../common/vertex.js";
|
|
2
|
-
import { Geometry } from "../../oc/geometry.js";
|
|
3
|
-
import { Point2D } from "../../math/point.js";
|
|
4
|
-
import { GeometrySceneObject } from "./geometry.js";
|
|
5
|
-
export class ArcThreePoints extends GeometrySceneObject {
|
|
6
|
-
startPoint;
|
|
7
|
-
endPoint;
|
|
8
|
-
center;
|
|
9
|
-
targetPlane;
|
|
10
|
-
constructor(startPoint, endPoint, center, targetPlane = null) {
|
|
11
|
-
super();
|
|
12
|
-
this.startPoint = startPoint;
|
|
13
|
-
this.endPoint = endPoint;
|
|
14
|
-
this.center = center;
|
|
15
|
-
this.targetPlane = targetPlane;
|
|
16
|
-
}
|
|
17
|
-
build() {
|
|
18
|
-
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
19
|
-
const startPt = this.startPoint.asPoint2D();
|
|
20
|
-
const endPt = this.endPoint.asPoint2D();
|
|
21
|
-
const centerPt = this.center.asPoint2D();
|
|
22
|
-
const dx = startPt.x - centerPt.x;
|
|
23
|
-
const dy = startPt.y - centerPt.y;
|
|
24
|
-
const radius = Math.sqrt(dx * dx + dy * dy);
|
|
25
|
-
const endAngle = Math.atan2(endPt.y - centerPt.y, endPt.x - centerPt.x);
|
|
26
|
-
const center = plane.localToWorld(centerPt);
|
|
27
|
-
const start = plane.localToWorld(startPt);
|
|
28
|
-
const end = plane.localToWorld(endPt);
|
|
29
|
-
const arc = Geometry.makeArc(center, radius, plane.normal, start, end);
|
|
30
|
-
const edge = Geometry.makeEdgeFromCurve(arc);
|
|
31
|
-
// Tangent at end: perpendicular to radius direction at end point (CCW)
|
|
32
|
-
const tx = -Math.sin(endAngle);
|
|
33
|
-
const ty = Math.cos(endAngle);
|
|
34
|
-
this.setTangent(new Point2D(tx, ty));
|
|
35
|
-
this.setState('start', Vertex.fromPoint2D(startPt));
|
|
36
|
-
this.setState('end', Vertex.fromPoint2D(endPt));
|
|
37
|
-
this.addShape(edge);
|
|
38
|
-
if (this.sketch) {
|
|
39
|
-
this.setCurrentPosition(endPt);
|
|
40
|
-
}
|
|
41
|
-
if (this.targetPlane) {
|
|
42
|
-
this.targetPlane.removeShapes(this);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
compareTo(other) {
|
|
46
|
-
if (!(other instanceof ArcThreePoints)) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
if (!super.compareTo(other)) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
if (this.targetPlane?.constructor !== other.targetPlane?.constructor) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
return this.startPoint.compareTo(other.startPoint) &&
|
|
59
|
-
this.endPoint.compareTo(other.endPoint) &&
|
|
60
|
-
this.center.compareTo(other.center);
|
|
61
|
-
}
|
|
62
|
-
getType() {
|
|
63
|
-
return 'arc';
|
|
64
|
-
}
|
|
65
|
-
getUniqueType() {
|
|
66
|
-
return 'arc-three-points';
|
|
67
|
-
}
|
|
68
|
-
serialize() {
|
|
69
|
-
return {
|
|
70
|
-
startPoint: this.startPoint.serialize(),
|
|
71
|
-
endPoint: this.endPoint.serialize(),
|
|
72
|
-
center: this.center.serialize()
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { GeometrySceneObject } from "./geometry.js";
|
|
2
|
-
import { LazyVertex } from "../lazy-vertex.js";
|
|
3
|
-
import { PlaneObjectBase } from "../plane-renderable-base.js";
|
|
4
|
-
export declare class ArcToPoint extends GeometrySceneObject {
|
|
5
|
-
endPoint: LazyVertex;
|
|
6
|
-
radius: number;
|
|
7
|
-
private targetPlane;
|
|
8
|
-
constructor(endPoint: LazyVertex, radius?: number, targetPlane?: PlaneObjectBase);
|
|
9
|
-
build(): void;
|
|
10
|
-
compareTo(other: ArcToPoint): boolean;
|
|
11
|
-
getType(): string;
|
|
12
|
-
getUniqueType(): string;
|
|
13
|
-
serialize(): {
|
|
14
|
-
endPoint: {};
|
|
15
|
-
radius: number;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { Vertex } from "../../common/vertex.js";
|
|
2
|
-
import { Geometry } from "../../oc/geometry.js";
|
|
3
|
-
import { Point2D } from "../../math/point.js";
|
|
4
|
-
import { GeometrySceneObject } from "./geometry.js";
|
|
5
|
-
export class ArcToPoint extends GeometrySceneObject {
|
|
6
|
-
endPoint;
|
|
7
|
-
radius;
|
|
8
|
-
targetPlane;
|
|
9
|
-
constructor(endPoint, radius = 0, targetPlane = null) {
|
|
10
|
-
super();
|
|
11
|
-
this.endPoint = endPoint;
|
|
12
|
-
this.radius = radius;
|
|
13
|
-
this.targetPlane = targetPlane;
|
|
14
|
-
}
|
|
15
|
-
build() {
|
|
16
|
-
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
17
|
-
const targetPoint = this.endPoint.asPoint2D();
|
|
18
|
-
const startPoint = this.targetPlane
|
|
19
|
-
? plane.worldToLocal(this.targetPlane.getPlaneCenter())
|
|
20
|
-
: this.getCurrentPosition();
|
|
21
|
-
const dx = targetPoint.x - startPoint.x;
|
|
22
|
-
const dy = targetPoint.y - startPoint.y;
|
|
23
|
-
const chordLen = Math.sqrt(dx * dx + dy * dy);
|
|
24
|
-
// Default radius: semicircle (half the chord length)
|
|
25
|
-
let r = this.radius || (chordLen / 2);
|
|
26
|
-
const cw = r < 0;
|
|
27
|
-
r = Math.abs(r);
|
|
28
|
-
// Ensure radius is at least half chord length
|
|
29
|
-
if (r < chordLen / 2) {
|
|
30
|
-
r = chordLen / 2;
|
|
31
|
-
}
|
|
32
|
-
// Find center using perpendicular bisector + radius constraint
|
|
33
|
-
const mx = (startPoint.x + targetPoint.x) / 2;
|
|
34
|
-
const my = (startPoint.y + targetPoint.y) / 2;
|
|
35
|
-
// Perpendicular direction to chord (normalized)
|
|
36
|
-
const px = -dy / chordLen;
|
|
37
|
-
const py = dx / chordLen;
|
|
38
|
-
// Distance from midpoint to center along perpendicular
|
|
39
|
-
const d = Math.sqrt(r * r - (chordLen / 2) * (chordLen / 2));
|
|
40
|
-
// Choose side based on CW/CCW
|
|
41
|
-
const sign = cw ? -1 : 1;
|
|
42
|
-
const centerPoint = new Point2D(mx + sign * d * px, my + sign * d * py);
|
|
43
|
-
const startAngle = Math.atan2(startPoint.y - centerPoint.y, startPoint.x - centerPoint.x);
|
|
44
|
-
const endAngle = Math.atan2(targetPoint.y - centerPoint.y, targetPoint.x - centerPoint.x);
|
|
45
|
-
const normal = cw ? plane.normal.negate() : plane.normal;
|
|
46
|
-
const center = plane.localToWorld(centerPoint);
|
|
47
|
-
const start = plane.localToWorld(startPoint);
|
|
48
|
-
const end = plane.localToWorld(targetPoint);
|
|
49
|
-
const arc = Geometry.makeArc(center, r, normal, start, end);
|
|
50
|
-
const edge = Geometry.makeEdgeFromCurve(arc);
|
|
51
|
-
// Tangent at end: perpendicular to radius direction at end point
|
|
52
|
-
// CCW: (-sin θ, cos θ), CW: (sin θ, -cos θ)
|
|
53
|
-
const signT = cw ? -1 : 1;
|
|
54
|
-
const endTx = signT * (-Math.sin(endAngle));
|
|
55
|
-
const endTy = signT * Math.cos(endAngle);
|
|
56
|
-
this.setTangent(new Point2D(endTx, endTy));
|
|
57
|
-
this.setState('start', Vertex.fromPoint2D(startPoint));
|
|
58
|
-
this.setState('end', Vertex.fromPoint2D(targetPoint));
|
|
59
|
-
this.addShape(edge);
|
|
60
|
-
if (this.sketch) {
|
|
61
|
-
this.setCurrentPosition(targetPoint);
|
|
62
|
-
}
|
|
63
|
-
if (this.targetPlane) {
|
|
64
|
-
this.targetPlane.removeShapes(this);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
compareTo(other) {
|
|
68
|
-
if (!(other instanceof ArcToPoint)) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
if (!super.compareTo(other)) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
if (this.targetPlane?.constructor !== other.targetPlane?.constructor) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
return this.endPoint.compareTo(other.endPoint) &&
|
|
81
|
-
this.radius === other.radius;
|
|
82
|
-
}
|
|
83
|
-
getType() {
|
|
84
|
-
return 'arc';
|
|
85
|
-
}
|
|
86
|
-
getUniqueType() {
|
|
87
|
-
return 'arc-to-point';
|
|
88
|
-
}
|
|
89
|
-
serialize() {
|
|
90
|
-
return {
|
|
91
|
-
endPoint: this.endPoint.serialize(),
|
|
92
|
-
radius: this.radius
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
}
|