@selvajs/visualization 1.0.0 → 1.1.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/README.md +47 -59
- package/dist/parse.cjs +1 -1
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +1 -1
- package/dist/parse.js.map +1 -1
- package/dist/render.cjs +3 -3
- package/dist/render.cjs.map +1 -1
- package/dist/render.d.cts +6 -0
- package/dist/render.d.ts +6 -0
- package/dist/render.js +2 -2
- package/dist/render.js.map +1 -1
- package/dist/scene.cjs +1 -1
- package/dist/scene.cjs.map +1 -1
- package/dist/scene.d.cts +12 -7
- package/dist/scene.d.ts +12 -7
- package/dist/scene.js +1 -1
- package/dist/scene.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
# `@selvajs/visualization`
|
|
2
2
|
|
|
3
|
-
A headless, extensible viewer core
|
|
4
|
-
|
|
3
|
+
A headless, extensible viewer core: no Svelte, no runes, `three` as a peer dep. Consumers build
|
|
4
|
+
their own UI over it.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Layers
|
|
7
7
|
|
|
8
|
-
Layers depend **downward only
|
|
8
|
+
Layers depend **downward only** — nothing imports upward, so where a file belongs follows from what
|
|
9
|
+
it depends on.
|
|
9
10
|
|
|
10
11
|
```
|
|
11
12
|
scene/ SceneOutliner: reads a live THREE.Scene → content list, layers, visibility, selection
|
|
12
|
-
│ ↓ depends on `three` only — it reads the scene graph, render/ owns its contents
|
|
13
13
|
render/ THREE scene setup + CAD viewer toolkit (camera, edges, grid, gizmo, measure…)
|
|
14
|
-
│ ↓
|
|
15
14
|
parse/ backend payload → THREE meshes + metadata (webdisplay, display-items)
|
|
16
|
-
|
|
17
|
-
shared/ coordinate frame, look presets, errors, logging, geometry/color
|
|
15
|
+
↑ all three depend only on:
|
|
16
|
+
shared/ coordinate frame, look presets, errors, logging, geometry/color, GPU ownership [internal]
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
The three upper layers are **siblings**, not a chain: `scene/` reads the scene graph but never
|
|
20
|
+
imports `render/`, and `render/` never imports `parse/`. A host composes them — see [the
|
|
21
|
+
render↔parse seam](./src/render/README.md#the-renderparse-seam) for the one place that needs care.
|
|
23
22
|
|
|
24
|
-
**
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
**The solve session lives in `@selvajs/solve/client`, not here.** What stays behind is the three.js
|
|
24
|
+
mesh ownership policy solve's result memo needs but deliberately doesn't know: `meshPolicy` in
|
|
25
|
+
[`parse/mesh-policy.ts`](./src/parse/mesh-policy.ts).
|
|
26
|
+
|
|
27
|
+
**Each layer's barrel (`index.ts`) is the only cross-layer import surface.** Files inside a layer
|
|
28
|
+
import siblings by relative path; other layers import the barrel.
|
|
27
29
|
|
|
28
30
|
## Sub-path exports
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
The three upper layers are published entrypoints, so consumers tree-shake:
|
|
31
33
|
|
|
32
34
|
```ts
|
|
33
35
|
import { getThreeMeshesFromComputeResponse, meshPolicy } from '@selvajs/visualization/parse';
|
|
@@ -42,64 +44,55 @@ layering enforced by the import graph rather than merely documented.
|
|
|
42
44
|
|
|
43
45
|
### The API is deliberately minimal
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
A published symbol is a compatibility promise, so don't re-export one just because it exists. Three
|
|
48
|
+
consequences worth knowing before you go looking for a missing export:
|
|
46
49
|
|
|
47
50
|
- **`initThree` owns the render toolkit.** It builds the camera controller, grid, gizmo, measure
|
|
48
|
-
tool, render pipeline and
|
|
49
|
-
[`ThreeViewer`](./src/render/scene-setup/viewer.ts). Configure
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
so hosts can annotate what they hold.
|
|
51
|
+
tool, render pipeline and near-plane fitter, and returns the live instances on
|
|
52
|
+
[`ThreeViewer`](./src/render/scene-setup/viewer.ts). Configure through `ThreeInitializerOptions`,
|
|
53
|
+
reach through the viewer (`viewer.grid`, `viewer.measureTool`, `viewer.applyEdges`, …). The
|
|
54
|
+
factories are internal; their handle _types_ are exported so hosts can annotate.
|
|
53
55
|
- **`createSceneOutliner` composes the scene layer.** Content filtering, layer grouping, visibility
|
|
54
|
-
and selection
|
|
55
|
-
- **The SLVA
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
When adding a feature, resist re-exporting a symbol just because it exists — a published surface is
|
|
59
|
-
a compatibility promise.
|
|
56
|
+
and selection are reachable via `outliner.visibility` / `.selection` / `.layerGroups()`.
|
|
57
|
+
- **The SLVA wire format is private.** Magics, version gates and flag bits are implementation
|
|
58
|
+
details of `parseMeshBatch*` and change without a major bump.
|
|
60
59
|
|
|
61
|
-
`scene/`
|
|
62
|
-
|
|
63
|
-
[`src/scene/README.md`](./src/scene/README.md).
|
|
60
|
+
`scene/` gets its reactivity with no seam at all: its state is three sets, so a host injects its own
|
|
61
|
+
(`SvelteSet` in a Svelte app) — see [`src/scene/README.md`](./src/scene/README.md).
|
|
64
62
|
|
|
65
63
|
## Examples (`pnpm example`)
|
|
66
64
|
|
|
67
|
-
`examples/` is a Vite playground for the render pipeline — the only place the GPU-dependent parts
|
|
68
|
-
(edge overlays, the screen-space edge pass, AO, the measure tool) can actually be checked, since
|
|
69
|
-
jsdom has no WebGL.
|
|
70
|
-
|
|
71
65
|
```bash
|
|
72
66
|
pnpm example # http://localhost:5173
|
|
73
67
|
```
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
(
|
|
69
|
+
A Vite playground, and the only place the GPU-dependent parts (edge overlays, the screen-space edge
|
|
70
|
+
pass, AO, the measure tool) can be checked at all — jsdom has no WebGL. Three demos: **Viewer**
|
|
71
|
+
(every `initThree` control), **Mesh File** (a `.slvm` through the same parse + `updateScene` calls
|
|
72
|
+
`Viewer.svelte` makes), **Display Items** (a GH compute response through
|
|
73
|
+
`getThreeMeshesFromComputeResponse`).
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
covered by `pnpm type-check`, so a rename that breaks a demo fails the build instead of rotting.
|
|
75
|
+
Demos import from the public barrels on purpose: a demo that needs an unexported symbol is a gap in
|
|
76
|
+
the published API, not a reason to deep-import. `pnpm type-check` covers them, so a rename that
|
|
77
|
+
breaks a demo fails the build instead of rotting.
|
|
83
78
|
|
|
84
79
|
## Dependencies
|
|
85
80
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
own errors ([`shared/errors.ts`](./src/shared/errors.ts)), logging
|
|
81
|
+
**Nothing from Selva** — only `fflate`, plus `three` as a peer dep. Errors
|
|
82
|
+
([`shared/errors.ts`](./src/shared/errors.ts)), logging
|
|
89
83
|
([`shared/logger.ts`](./src/shared/logger.ts)) and base64 decoding
|
|
90
|
-
([`shared/encoding.ts`](./src/shared/encoding.ts)) rather than
|
|
91
|
-
`@selvajs/compute`, so
|
|
92
|
-
Rhino.Compute.
|
|
84
|
+
([`shared/encoding.ts`](./src/shared/encoding.ts)) are owned here rather than imported from
|
|
85
|
+
`@selvajs/compute`, so the viewer works for a consumer with neither Selva nor Rhino.Compute.
|
|
93
86
|
|
|
94
|
-
|
|
95
|
-
[`parse/webdisplay/response-envelope.ts`](./src/parse/webdisplay/response-envelope.ts) as
|
|
96
|
-
fields the parser reads
|
|
97
|
-
|
|
87
|
+
Likewise the response shape `getThreeMeshesFromComputeResponse` accepts is declared structurally in
|
|
88
|
+
[`parse/webdisplay/response-envelope.ts`](./src/parse/webdisplay/response-envelope.ts) as only the
|
|
89
|
+
fields the parser reads. Compute's `GrasshopperComputeResponse` is a superset and stays assignable,
|
|
90
|
+
so neither package depends on the other.
|
|
98
91
|
|
|
99
|
-
|
|
92
|
+
**`three` (>=0.179.0) is a peer dep** — the host owns the single instance. A second copy breaks
|
|
93
|
+
`instanceof` across the boundary.
|
|
100
94
|
|
|
101
|
-
The package logs nothing by default. To
|
|
102
|
-
`@selvajs/compute`'s, so both packages share a sink:
|
|
95
|
+
The package logs nothing by default. To share a sink with `@selvajs/compute`:
|
|
103
96
|
|
|
104
97
|
```ts
|
|
105
98
|
import { setLogger } from '@selvajs/visualization/render';
|
|
@@ -107,8 +100,3 @@ import { getLogger } from '@selvajs/compute/core';
|
|
|
107
100
|
|
|
108
101
|
setLogger(getLogger());
|
|
109
102
|
```
|
|
110
|
-
|
|
111
|
-
## Peer dependencies
|
|
112
|
-
|
|
113
|
-
`three` (>=0.179.0) is a peer dep — the host app owns the single `three` instance. Installing a
|
|
114
|
-
second copy breaks `instanceof` checks across the boundary.
|
package/dist/parse.cjs
CHANGED
|
@@ -6,5 +6,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
6
6
|
pow( ( vColor.rgb + 0.055 ) / 1.055, vec3( 2.4 ) ),
|
|
7
7
|
step( vec3( 0.04045 ), vColor.rgb )
|
|
8
8
|
);
|
|
9
|
-
#endif`)}}function V(e,n){return new t.d(e,t.u.VALIDATION_ERROR,{context:n})}function H(e,t,n,r){for(let i of e){if(!Number.isInteger(i.materialId)||i.materialId<0||i.materialId>=t)throw V(`Group materialId out of range of the materials array.`,{materialId:i.materialId,materialCount:t});for(let e of i.meshes){let t={vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount};for(let[n,r]of Object.entries(t))if(!Number.isInteger(r)||r<0)throw V(`Mesh metadata field "${n}" must be a non-negative integer.`,{meshName:e.name,field:n,value:r});if(e.vertexStart+e.vertexCount>n)throw V(`Mesh vertex window exceeds the batch vertex buffer.`,{meshName:e.name,vertexStart:e.vertexStart,vertexCount:e.vertexCount,totalVertexCount:n});if(e.indexStart+e.indexCount>r)throw V(`Mesh index window exceeds the batch index buffer.`,{meshName:e.name,indexStart:e.indexStart,indexCount:e.indexCount,totalIndexCount:r})}}}function U(e,t){return V(`Index references a vertex outside its mesh's vertex window.`,{meshName:t.name,indexValue:e,vertexStart:t.vertexStart,vertexCount:t.vertexCount})}function oe(e,t,n){let r=new Float32Array(e.length),i=t[0],a=t[1],o=t[2],s=n[0],c=n[1],l=n[2];for(let t=0;t<e.length;t+=3)r[t]=i+(e[t]+32767)*s,r[t+1]=a+(e[t+1]+32767)*c,r[t+2]=o+(e[t+2]+32767)*l;return r}function W(e,t,r,i,a=null,o=null){let s=0,c=0;for(let t of e.meshes)s+=t.vertexCount,c+=t.indexCount;let l=new Float32Array(s*3),u=new Uint32Array(c),d=a?new Float32Array(s*2):null,f=o?new Uint8Array(s*3):null,p=0,m=0;for(let n of e.meshes){let e=n.vertexStart*3,i=n.vertexCount*3;if(l.set(t.subarray(e,e+i),p*3),d&&a){let e=n.vertexStart*2;d.set(a.subarray(e,e+n.vertexCount*2),p*2)}f&&o&&f.set(o.subarray(e,e+i),p*3);let s=r.subarray(n.indexStart,n.indexStart+n.indexCount),c=p-n.vertexStart,h=n.vertexStart,g=n.vertexStart+n.vertexCount;for(let e=0;e<s.length;e++){let t=s[e];if(t<h||t>=g)throw U(t,n);u[m+e]=t+c}p+=n.vertexCount,m+=n.indexCount}let h=new n.BufferGeometry;return h.setAttribute(`position`,new n.BufferAttribute(l,3)),h.setIndex(new n.BufferAttribute(u,1)),d&&h.setAttribute(`uv`,new n.BufferAttribute(d,2)),f&&h.setAttribute(`color`,new n.BufferAttribute(f,3,!0)),h.computeVertexNormals(),G(h,e,i)}function G(e,t,r){let i=new n.Mesh(e,r[t.materialId]),a=t.meshes[0],o=t.meshes.map(e=>e.name).filter(e=>e&&e.length>0);return i.name=o.length>0?o[0]:`merged_material_${t.materialId}`,i.castShadow=!0,i.receiveShadow=!0,i.userData={source:`compute`,name:i.name,layer:a?.layer??``,originalIndex:a?.originalIndex??0,metadata:a?.metadata??{},mergedFrom:t.meshes.slice(1).map(e=>({name:e.name,layer:e.layer,originalIndex:e.originalIndex}))},i}function K(e,t,r,i,a=null,o=null){let s=[];for(let c of e.meshes){let l=c.vertexStart*3,u=c.vertexCount*3,d=t.slice(l,l+u),f=r.subarray(c.indexStart,c.indexStart+c.indexCount),p=new Uint32Array(f.length),m=c.vertexStart,h=c.vertexStart+c.vertexCount;for(let e=0;e<f.length;e++){let t=f[e];if(t<m||t>=h)throw U(t,c);p[e]=t-m}let g=new n.BufferGeometry;if(g.setAttribute(`position`,new n.BufferAttribute(d,3)),g.setIndex(new n.BufferAttribute(p,1)),a){let e=c.vertexStart*2,t=a.slice(e,e+c.vertexCount*2);g.setAttribute(`uv`,new n.BufferAttribute(t,2))}if(o){let e=o.slice(l,l+u);g.setAttribute(`color`,new n.BufferAttribute(e,3,!0))}g.computeVertexNormals(),s.push(q(g,c,e,i))}return s}function q(e,t,r,i){let a=new n.Mesh(e,i[r.materialId]);return a.name=t.name,a.userData={source:`compute`,name:t.name,layer:t.layer??``,originalIndex:t.originalIndex,metadata:t.metadata??{}},a.castShadow=!0,a.receiveShadow=!0,a}async function J(e,t,n){let{mergeByMaterial:r=!0,debug:i=!1,material:a}=t??{},{parseTime:o=0,perfStart:s=i?performance.now():0}=n??{};if(!e.compressedData)return[];let c=await X(e.compressedData,{mergeByMaterial:r,debug:i,material:a,fallback:{materials:e.materials,groups:e.groups,sourceComponentId:e.sourceComponentId}});if(c)return c;let l=performance.now();return Y(A(e.compressedData),{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:performance.now()-l,perfStart:s,blobBytes:i?ce(e.compressedData):0,fallback:{materials:e.materials,groups:e.groups,sourceComponentId:e.sourceComponentId}})}async function se(e,t){let{mergeByMaterial:n=!0,debug:r=!1,material:i}=t??{},a=r?performance.now():0,o=await X(e,{mergeByMaterial:n,debug:r,material:i});if(o)return o;let s=performance.now(),c=A(e),l=performance.now()-s,u=e.byteLength;return Y(c,{mergeByMaterial:n,debug:r,material:i,parseTime:0,decodeTime:l,perfStart:a,blobBytes:u})}function Y(e,n){let{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:s,perfStart:c,blobBytes:l,fallback:u}=n,d=e.metadata.materials??u?.materials??[],f=e.metadata.groups??u?.groups??[],p=u?.sourceComponentId??e.metadata.sourceComponentId,m=!!(e.flags&1);H(f,d.length,e.vertices.length/3,e.indices.length);let h=m?e.vertices:oe(e.vertices,e.origin,e.scale);if(i){let n=e.vertices.byteLength+e.indices.byteLength;t.c().debug(`Mesh Batch Stats:`),t.c().debug(` Materials: ${d.length} | Groups: ${f.length}`),t.c().debug(` Vertices: ${e.vertices.length/3} | Indices: ${e.indices.length}`),t.c().debug(` Format: ${m?`float32`:`int16 quantized`}`),t.c().debug(` Blob: ${(l/1024/1024).toFixed(2)} MB | Geometry on wire: ${(n/1024/1024).toFixed(2)} MB`)}let g=performance.now(),_=d.map(t=>B(t,{vertexColors:e.colors!=null,appearance:a})),v=[];for(let t of f)if(r&&t.meshes.length>1){let n=W(t,h,e.indices,_,e.uvs,e.colors);n.userData.sourceComponentId=p
|
|
9
|
+
#endif`)}}function V(e,n){return new t.d(e,t.u.VALIDATION_ERROR,{context:n})}function H(e,t,n,r){for(let i of e){if(!Number.isInteger(i.materialId)||i.materialId<0||i.materialId>=t)throw V(`Group materialId out of range of the materials array.`,{materialId:i.materialId,materialCount:t});for(let e of i.meshes){let t={vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount};for(let[n,r]of Object.entries(t))if(!Number.isInteger(r)||r<0)throw V(`Mesh metadata field "${n}" must be a non-negative integer.`,{meshName:e.name,field:n,value:r});if(e.vertexStart+e.vertexCount>n)throw V(`Mesh vertex window exceeds the batch vertex buffer.`,{meshName:e.name,vertexStart:e.vertexStart,vertexCount:e.vertexCount,totalVertexCount:n});if(e.indexStart+e.indexCount>r)throw V(`Mesh index window exceeds the batch index buffer.`,{meshName:e.name,indexStart:e.indexStart,indexCount:e.indexCount,totalIndexCount:r})}}}function U(e,t){return V(`Index references a vertex outside its mesh's vertex window.`,{meshName:t.name,indexValue:e,vertexStart:t.vertexStart,vertexCount:t.vertexCount})}function oe(e,t,n){let r=new Float32Array(e.length),i=t[0],a=t[1],o=t[2],s=n[0],c=n[1],l=n[2];for(let t=0;t<e.length;t+=3)r[t]=i+(e[t]+32767)*s,r[t+1]=a+(e[t+1]+32767)*c,r[t+2]=o+(e[t+2]+32767)*l;return r}function W(e,t,r,i,a=null,o=null){let s=0,c=0;for(let t of e.meshes)s+=t.vertexCount,c+=t.indexCount;let l=new Float32Array(s*3),u=new Uint32Array(c),d=a?new Float32Array(s*2):null,f=o?new Uint8Array(s*3):null,p=0,m=0;for(let n of e.meshes){let e=n.vertexStart*3,i=n.vertexCount*3;if(l.set(t.subarray(e,e+i),p*3),d&&a){let e=n.vertexStart*2;d.set(a.subarray(e,e+n.vertexCount*2),p*2)}f&&o&&f.set(o.subarray(e,e+i),p*3);let s=r.subarray(n.indexStart,n.indexStart+n.indexCount),c=p-n.vertexStart,h=n.vertexStart,g=n.vertexStart+n.vertexCount;for(let e=0;e<s.length;e++){let t=s[e];if(t<h||t>=g)throw U(t,n);u[m+e]=t+c}p+=n.vertexCount,m+=n.indexCount}let h=new n.BufferGeometry;return h.setAttribute(`position`,new n.BufferAttribute(l,3)),h.setIndex(new n.BufferAttribute(u,1)),d&&h.setAttribute(`uv`,new n.BufferAttribute(d,2)),f&&h.setAttribute(`color`,new n.BufferAttribute(f,3,!0)),h.computeVertexNormals(),G(h,e,i)}function G(e,t,r){let i=new n.Mesh(e,r[t.materialId]),a=t.meshes[0],o=t.meshes.map(e=>e.name).filter(e=>e&&e.length>0);return i.name=o.length>0?o[0]:`merged_material_${t.materialId}`,i.castShadow=!0,i.receiveShadow=!0,i.userData={source:`compute`,name:i.name,layer:a?.layer??``,originalIndex:a?.originalIndex??0,mergedIndices:t.meshes.map(e=>e.originalIndex).sort((e,t)=>e-t),metadata:a?.metadata??{},mergedFrom:t.meshes.slice(1).map(e=>({name:e.name,layer:e.layer,originalIndex:e.originalIndex}))},i}function K(e,t,r,i,a=null,o=null){let s=[];for(let c of e.meshes){let l=c.vertexStart*3,u=c.vertexCount*3,d=t.slice(l,l+u),f=r.subarray(c.indexStart,c.indexStart+c.indexCount),p=new Uint32Array(f.length),m=c.vertexStart,h=c.vertexStart+c.vertexCount;for(let e=0;e<f.length;e++){let t=f[e];if(t<m||t>=h)throw U(t,c);p[e]=t-m}let g=new n.BufferGeometry;if(g.setAttribute(`position`,new n.BufferAttribute(d,3)),g.setIndex(new n.BufferAttribute(p,1)),a){let e=c.vertexStart*2,t=a.slice(e,e+c.vertexCount*2);g.setAttribute(`uv`,new n.BufferAttribute(t,2))}if(o){let e=o.slice(l,l+u);g.setAttribute(`color`,new n.BufferAttribute(e,3,!0))}g.computeVertexNormals(),s.push(q(g,c,e,i))}return s}function q(e,t,r,i){let a=new n.Mesh(e,i[r.materialId]);return a.name=t.name,a.userData={source:`compute`,name:t.name,layer:t.layer??``,originalIndex:t.originalIndex,metadata:t.metadata??{}},a.castShadow=!0,a.receiveShadow=!0,a}async function J(e,t,n){let{mergeByMaterial:r=!0,debug:i=!1,material:a}=t??{},{parseTime:o=0,perfStart:s=i?performance.now():0}=n??{};if(!e.compressedData)return[];let c=await X(e.compressedData,{mergeByMaterial:r,debug:i,material:a,fallback:{materials:e.materials,groups:e.groups,sourceComponentId:e.sourceComponentId}});if(c)return c;let l=performance.now();return Y(A(e.compressedData),{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:performance.now()-l,perfStart:s,blobBytes:i?ce(e.compressedData):0,fallback:{materials:e.materials,groups:e.groups,sourceComponentId:e.sourceComponentId}})}async function se(e,t){let{mergeByMaterial:n=!0,debug:r=!1,material:i}=t??{},a=r?performance.now():0,o=await X(e,{mergeByMaterial:n,debug:r,material:i});if(o)return o;let s=performance.now(),c=A(e),l=performance.now()-s,u=e.byteLength;return Y(c,{mergeByMaterial:n,debug:r,material:i,parseTime:0,decodeTime:l,perfStart:a,blobBytes:u})}function Y(e,n){let{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:s,perfStart:c,blobBytes:l,fallback:u}=n,d=e.metadata.materials??u?.materials??[],f=e.metadata.groups??u?.groups??[],p=u?.sourceComponentId??e.metadata.sourceComponentId,m=!!(e.flags&1);H(f,d.length,e.vertices.length/3,e.indices.length);let h=m?e.vertices:oe(e.vertices,e.origin,e.scale);if(i){let n=e.vertices.byteLength+e.indices.byteLength;t.c().debug(`Mesh Batch Stats:`),t.c().debug(` Materials: ${d.length} | Groups: ${f.length}`),t.c().debug(` Vertices: ${e.vertices.length/3} | Indices: ${e.indices.length}`),t.c().debug(` Format: ${m?`float32`:`int16 quantized`}`),t.c().debug(` Blob: ${(l/1024/1024).toFixed(2)} MB | Geometry on wire: ${(n/1024/1024).toFixed(2)} MB`)}let g=performance.now(),_=d.map(t=>B(t,{vertexColors:e.colors!=null,appearance:a})),v=[];for(let t of f)if(r&&t.meshes.length>1){let n=W(t,h,e.indices,_,e.uvs,e.colors);p&&(n.userData.sourceComponentId=p),v.push(n)}else{let n=K(t,h,e.indices,_,e.uvs,e.colors);if(p)for(let e of n)e.userData.sourceComponentId=p;v.push(...n)}let y=performance.now()-g;if(i){let e=performance.now()-c;t.c().debug(`Performance:`),o>0&&t.c().debug(` Parse JSON: ${o.toFixed(2)}ms`),t.c().debug(` Decode binary: ${s.toFixed(2)}ms`),t.c().debug(` Create Meshes: ${y.toFixed(2)}ms`),t.c().debug(` Total: ${e.toFixed(2)}ms`)}return Promise.resolve(v)}async function X(e,r){if(typeof Worker>`u`)return null;let i=j(e);if(i.indexData.length/3<5e4)return null;let a=L();if(!a)return null;let o=i.metadata.materials??r.fallback?.materials??[],s=i.metadata.groups??r.fallback?.groups??[],c=r.fallback?.sourceComponentId??i.metadata.sourceComponentId;H(s,o.length,i.vertexCount,i.indexData.length);let l=e=>({vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount}),u=[],d=[];for(let e of s)if(r.mergeByMaterial&&e.meshes.length>1)u.push({kind:`merged`,windows:e.meshes.map(l)}),d.push({kind:`merged`,group:e});else for(let t of e.meshes)u.push({kind:`single`,windows:[l(t)]}),d.push({kind:`single`,group:e,meshMeta:t});let f=i.vertexData.slice(),p=i.indexData.slice(),m=[f.buffer,p.buffer];i.uvs&&m.push(i.uvs.buffer),i.colors&&m.push(i.colors.buffer);let h;try{h=await re(a,{vertexData:f,isFloat32:i.isFloat32,deltaEncoded:i.deltaEncoded,origin:i.origin,scale:i.scale,indexData:p,uvs:i.uvs,colors:i.colors,jobs:u},m)}catch(e){return t.c().warn(`Mesh assembly worker failed; falling back to main-thread parse.`,e),null}if(h.length!==u.length)return null;let g=o.map(e=>B(e,{vertexColors:i.colors!=null,appearance:r.material})),_=[];for(let e=0;e<h.length;e++){let t=h[e],r=d[e],i=new n.BufferGeometry;i.setAttribute(`position`,new n.BufferAttribute(t.positions,3)),i.setAttribute(`normal`,new n.BufferAttribute(t.normals,3)),i.setIndex(new n.BufferAttribute(t.indices,1)),t.uvs&&i.setAttribute(`uv`,new n.BufferAttribute(t.uvs,2)),t.colors&&i.setAttribute(`color`,new n.BufferAttribute(t.colors,3,!0));let a=r.kind===`merged`?G(i,r.group,g):q(i,r.meshMeta,r.group,g);c&&(a.userData.sourceComponentId=c),_.push(a)}return r.debug&&t.c().debug(`Mesh batch assembled off-thread: ${_.length} meshes, ${i.indexData.length/3} triangles`),_}function ce(e){return Math.floor(e.length*3/4)}const Z={Angstroms:1e-10,Nanometers:1e-9,Microns:1e-6,Millimeters:.001,Centimeters:.01,Decimeters:.1,Meters:1,Dekameters:10,Hectometers:100,Kilometers:1e3,Megameters:1e6,Gigameters:1e9,Microinches:2.54e-8,Mils:254e-7,Inches:.0254,Feet:.3048,Yards:.9144,Miles:1609.344,NauticalMiles:1852};function le(e){let t=e.split(`.`);return t.includes(`Display`)||t.includes(`DisplayBatch`)}const Q=new Set;async function ue(e,t){let n=performance.now(),r=[],{allowScaling:i=!0,allowAutoPosition:a=!1,groundAxis:o=`z`,debug:s=!1,parsing:c={}}=t??{};try{return await fe(e,r,i?de(e.modelunits):1,c,s),a&&he(r,o),r}catch(e){throw ge(e,r),e}finally{s&&ve(n)}}function de(e){let n=Z[e];return n===void 0?(Q.has(e)||(Q.add(e),t.c().warn(`Unknown Rhino model unit "${e}" — geometry will not be scaled (factor 1). Known units: ${Object.keys(Z).join(`, `)}.`)),1):n}async function fe(e,t,n,r,i){for(let a of e.values){let e=a.InnerTree;for(let a in e){let o=e[a];o&&await pe(o,t,n,r,i)}}}async function pe(e,n,r,i,a){for(let o of e){if(!le(o.type))continue;let e={mergeByMaterial:!0,debug:!1,...i},s=me(o.data);if(!s){t.c().error(`Error parsing display batch envelope: invalid JSON`);continue}let c=await J(s,e),l=g(s.items),u=[...c,...l];if(r!==1)for(let e of u)e.scale.set(r,r,r);n.push(...u),a&&t.c().debug(`Extracted ${c.length} meshes and ${l.length} items from batch`)}}function me(e){return typeof e==`string`?$(e):e}function $(e){try{return JSON.parse(e)}catch{return}}function he(e,n){if(e.length===0)return;let r=t.a(e);t.i(e,r.min[n],n)}function ge(e,n){t.c().error(`An unexpected error occurred:`,e),_e(n)}function _e(e){for(let t of e){let e=t;e.geometry&&e.geometry.dispose(),e.material&&(Array.isArray(e.material)?e.material.forEach(e=>e.dispose()):e.material.dispose())}}function ve(e){let n=performance.now()-e;t.c().info(`Time to process meshes:`,`${n.toFixed(2)}ms`)}exports.SCALE_FACTORS=Z,exports.getThreeMeshesFromComputeResponse=ue,exports.meshPolicy=d,exports.parseDisplayItems=g,exports.parseMeshBatchBlob=se,exports.parseMeshBatchObject=J,exports.setTextureAnisotropy=z;
|
|
10
10
|
//# sourceMappingURL=parse.cjs.map
|