@pascal-app/viewer 0.7.0 → 0.9.1
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/dist/components/renderers/node-renderer.d.ts +1 -1
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +38 -22
- package/dist/components/renderers/parametric-node-renderer.d.ts +5 -0
- package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -0
- package/dist/components/renderers/parametric-node-renderer.js +34 -0
- package/dist/components/renderers/scene-renderer.d.ts +1 -1
- package/dist/components/renderers/scene-renderer.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +5 -1
- package/dist/components/viewer/ground-occluder.d.ts +1 -1
- package/dist/components/viewer/ground-occluder.d.ts.map +1 -1
- package/dist/components/viewer/ground-occluder.js +12 -24
- package/dist/components/viewer/index.d.ts +38 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +183 -60
- package/dist/components/viewer/lights.d.ts +1 -1
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +170 -43
- package/dist/components/viewer/perf-monitor.d.ts +1 -1
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +99 -11
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +217 -61
- package/dist/components/viewer/registered-systems.d.ts +12 -0
- package/dist/components/viewer/registered-systems.d.ts.map +1 -0
- package/dist/components/viewer/registered-systems.js +47 -0
- package/dist/components/viewer/scene-bvh.d.ts +17 -0
- package/dist/components/viewer/scene-bvh.d.ts.map +1 -0
- package/dist/components/viewer/scene-bvh.js +94 -0
- package/dist/components/viewer/selection-manager.d.ts +1 -1
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +20 -5
- package/dist/components/viewer/viewer-camera.d.ts +1 -1
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/walkthrough-controls.d.ts +1 -1
- package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-node-events.d.ts +5 -73
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +19 -7
- package/dist/index.d.ts +36 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +67 -3
- package/dist/lib/csg-utils.d.ts +16 -0
- package/dist/lib/csg-utils.d.ts.map +1 -0
- package/dist/lib/csg-utils.js +33 -0
- package/dist/lib/drawable-geometry.d.ts +21 -0
- package/dist/lib/drawable-geometry.d.ts.map +1 -0
- package/dist/lib/drawable-geometry.js +22 -0
- package/dist/lib/edge-style.d.ts +3 -0
- package/dist/lib/edge-style.d.ts.map +1 -0
- package/dist/lib/edge-style.js +11 -0
- package/dist/lib/gpu-perf.d.ts +4 -0
- package/dist/lib/gpu-perf.d.ts.map +1 -0
- package/dist/lib/gpu-perf.js +23 -0
- package/dist/lib/ink-edges.d.ts +9 -0
- package/dist/lib/ink-edges.d.ts.map +1 -0
- package/dist/lib/ink-edges.js +43 -0
- package/dist/lib/isolation.d.ts +39 -0
- package/dist/lib/isolation.d.ts.map +1 -0
- package/dist/lib/isolation.js +103 -0
- package/dist/lib/layers.d.ts +18 -0
- package/dist/lib/layers.d.ts.map +1 -1
- package/dist/lib/layers.js +18 -0
- package/dist/lib/materials.d.ts +25 -15
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +277 -63
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +11 -11
- package/dist/lib/polygon-union.d.ts +4 -0
- package/dist/lib/polygon-union.d.ts.map +1 -0
- package/dist/lib/polygon-union.js +289 -0
- package/dist/lib/polygon-union.test.d.ts +2 -0
- package/dist/lib/polygon-union.test.d.ts.map +1 -0
- package/dist/lib/polygon-union.test.js +105 -0
- package/dist/lib/scene-themes.d.ts +29 -0
- package/dist/lib/scene-themes.d.ts.map +1 -0
- package/dist/lib/scene-themes.js +193 -0
- package/dist/store/use-viewer.d.ts +42 -4
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +26 -3
- package/dist/systems/ceiling/ceiling-system.d.ts +6 -2
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +62 -12
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +373 -22
- package/dist/systems/elevator/elevator-interaction-system.d.ts +2 -0
- package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-interaction-system.js +62 -0
- package/dist/systems/fence/fence-system.d.ts +3 -0
- package/dist/systems/fence/fence-system.d.ts.map +1 -1
- package/dist/systems/fence/fence-system.js +10 -6
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts +20 -0
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -0
- package/dist/systems/floor-elevation/floor-elevation-system.js +78 -0
- package/dist/systems/geometry/geometry-system.d.ts +34 -0
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -0
- package/dist/systems/geometry/geometry-system.js +279 -0
- package/dist/systems/guide/guide-system.d.ts.map +1 -1
- package/dist/systems/guide/guide-system.js +1 -26
- package/dist/systems/interactive/interactive-system.d.ts +1 -1
- package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
- package/dist/systems/item/item-system.d.ts +7 -0
- package/dist/systems/item/item-system.d.ts.map +1 -1
- package/dist/systems/item/item-system.js +8 -11
- package/dist/systems/item-light/item-light-system.d.ts +1 -1
- package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
- package/dist/systems/item-light/item-light-system.js +18 -5
- package/dist/systems/roof/roof-materials.d.ts +3 -2
- package/dist/systems/roof/roof-materials.d.ts.map +1 -1
- package/dist/systems/roof/roof-materials.js +38 -14
- package/dist/systems/roof/roof-system.d.ts +27 -0
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +411 -71
- package/dist/systems/scan/scan-system.d.ts.map +1 -1
- package/dist/systems/scan/scan-system.js +1 -26
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +167 -49
- package/dist/systems/slab/slab-system.test.d.ts +2 -0
- package/dist/systems/slab/slab-system.test.d.ts.map +1 -0
- package/dist/systems/slab/slab-system.test.js +62 -0
- package/dist/systems/stair/stair-materials.d.ts +4 -3
- package/dist/systems/stair/stair-materials.d.ts.map +1 -1
- package/dist/systems/stair/stair-materials.js +30 -15
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +58 -71
- package/dist/systems/surface-hole-geometry.d.ts +3 -0
- package/dist/systems/surface-hole-geometry.d.ts.map +1 -0
- package/dist/systems/surface-hole-geometry.js +4 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +18 -2
- package/dist/systems/wall/wall-materials.d.ts +4 -3
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +52 -28
- package/dist/systems/wall/wall-system.d.ts +1 -1
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +179 -31
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +71 -7
- package/package.json +4 -5
- package/dist/components/renderers/building/building-renderer.d.ts +0 -5
- package/dist/components/renderers/building/building-renderer.d.ts.map +0 -1
- package/dist/components/renderers/building/building-renderer.js +0 -11
- package/dist/components/renderers/ceiling/ceiling-renderer.d.ts +0 -5
- package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +0 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.js +0 -58
- package/dist/components/renderers/column/column-renderer.d.ts +0 -5
- package/dist/components/renderers/column/column-renderer.d.ts.map +0 -1
- package/dist/components/renderers/column/column-renderer.js +0 -594
- package/dist/components/renderers/door/door-renderer.d.ts +0 -5
- package/dist/components/renderers/door/door-renderer.d.ts.map +0 -1
- package/dist/components/renderers/door/door-renderer.js +0 -16
- package/dist/components/renderers/fence/fence-renderer.d.ts +0 -5
- package/dist/components/renderers/fence/fence-renderer.d.ts.map +0 -1
- package/dist/components/renderers/fence/fence-renderer.js +0 -29
- package/dist/components/renderers/guide/guide-renderer.d.ts +0 -5
- package/dist/components/renderers/guide/guide-renderer.d.ts.map +0 -1
- package/dist/components/renderers/guide/guide-renderer.js +0 -38
- package/dist/components/renderers/item/item-renderer.d.ts +0 -5
- package/dist/components/renderers/item/item-renderer.d.ts.map +0 -1
- package/dist/components/renderers/item/item-renderer.js +0 -172
- package/dist/components/renderers/level/level-renderer.d.ts +0 -5
- package/dist/components/renderers/level/level-renderer.d.ts.map +0 -1
- package/dist/components/renderers/level/level-renderer.js +0 -11
- package/dist/components/renderers/roof/roof-materials.d.ts +0 -4
- package/dist/components/renderers/roof/roof-materials.d.ts.map +0 -1
- package/dist/components/renderers/roof/roof-materials.js +0 -16
- package/dist/components/renderers/roof/roof-renderer.d.ts +0 -5
- package/dist/components/renderers/roof/roof-renderer.d.ts.map +0 -1
- package/dist/components/renderers/roof/roof-renderer.js +0 -32
- package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts +0 -5
- package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +0 -1
- package/dist/components/renderers/roof-segment/roof-segment-renderer.js +0 -40
- package/dist/components/renderers/scan/scan-renderer.d.ts +0 -5
- package/dist/components/renderers/scan/scan-renderer.d.ts.map +0 -1
- package/dist/components/renderers/scan/scan-renderer.js +0 -54
- package/dist/components/renderers/site/site-renderer.d.ts +0 -5
- package/dist/components/renderers/site/site-renderer.d.ts.map +0 -1
- package/dist/components/renderers/site/site-renderer.js +0 -106
- package/dist/components/renderers/slab/slab-renderer.d.ts +0 -5
- package/dist/components/renderers/slab/slab-renderer.d.ts.map +0 -1
- package/dist/components/renderers/slab/slab-renderer.js +0 -58
- package/dist/components/renderers/spawn/spawn-renderer.d.ts +0 -5
- package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +0 -1
- package/dist/components/renderers/spawn/spawn-renderer.js +0 -32
- package/dist/components/renderers/stair/stair-renderer.d.ts +0 -5
- package/dist/components/renderers/stair/stair-renderer.d.ts.map +0 -1
- package/dist/components/renderers/stair/stair-renderer.js +0 -603
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +0 -5
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +0 -1
- package/dist/components/renderers/stair-segment/stair-segment-renderer.js +0 -32
- package/dist/components/renderers/wall/wall-renderer.d.ts +0 -5
- package/dist/components/renderers/wall/wall-renderer.d.ts.map +0 -1
- package/dist/components/renderers/wall/wall-renderer.js +0 -16
- package/dist/components/renderers/window/window-renderer.d.ts +0 -5
- package/dist/components/renderers/window/window-renderer.d.ts.map +0 -1
- package/dist/components/renderers/window/window-renderer.js +0 -21
- package/dist/components/renderers/zone/zone-renderer.d.ts +0 -5
- package/dist/components/renderers/zone/zone-renderer.d.ts.map +0 -1
- package/dist/components/renderers/zone/zone-renderer.js +0 -181
- package/dist/lib/suppress-three-clock-warning.d.ts +0 -25
- package/dist/lib/suppress-three-clock-warning.d.ts.map +0 -1
- package/dist/lib/suppress-three-clock-warning.js +0 -51
- package/dist/systems/export/export-system.d.ts +0 -2
- package/dist/systems/export/export-system.d.ts.map +0 -1
- package/dist/systems/export/export-system.js +0 -60
- package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.d.ts +0 -14
- package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.d.ts.map +0 -1
- package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.js +0 -155
- package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.d.ts +0 -6
- package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.d.ts.map +0 -1
- package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.js +0 -75
- package/dist/systems/item-mesh-metadata/sync-request.d.ts +0 -7
- package/dist/systems/item-mesh-metadata/sync-request.d.ts.map +0 -1
- package/dist/systems/item-mesh-metadata/sync-request.js +0 -25
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
-
import { useLayoutEffect, useRef } from 'react';
|
|
4
|
-
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
|
-
import { getVisibleWallMaterials } from '../../../systems/wall/wall-materials';
|
|
6
|
-
import { NodeRenderer } from '../node-renderer';
|
|
7
|
-
export const WallRenderer = ({ node }) => {
|
|
8
|
-
const ref = useRef(null);
|
|
9
|
-
useRegistry(node.id, 'wall', ref);
|
|
10
|
-
useLayoutEffect(() => {
|
|
11
|
-
useScene.getState().markDirty(node.id);
|
|
12
|
-
}, [node.id]);
|
|
13
|
-
const handlers = useNodeEvents(node, 'wall');
|
|
14
|
-
const material = getVisibleWallMaterials(node);
|
|
15
|
-
return (_jsxs("mesh", { castShadow: true, material: material, receiveShadow: true, ref: ref, visible: node.visible, children: [_jsx("boxGeometry", { args: [0, 0, 0] }), _jsx("mesh", { name: "collision-mesh", visible: false, ...handlers, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }), node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, `${node.id}:${childId}`)))] }));
|
|
16
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"window-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/window/window-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAMzE,eAAO,MAAM,cAAc,GAAI,UAAU;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,4CA8B5D,CAAA"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
-
import { useLayoutEffect, useMemo, useRef } from 'react';
|
|
4
|
-
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
|
-
import { createMaterial, DEFAULT_WINDOW_MATERIAL } from '../../../lib/materials';
|
|
6
|
-
export const WindowRenderer = ({ node }) => {
|
|
7
|
-
const ref = useRef(null);
|
|
8
|
-
useRegistry(node.id, 'window', ref);
|
|
9
|
-
useLayoutEffect(() => {
|
|
10
|
-
useScene.getState().markDirty(node.id);
|
|
11
|
-
}, [node.id]);
|
|
12
|
-
const handlers = useNodeEvents(node, 'window');
|
|
13
|
-
const isTransient = !!node.metadata?.isTransient;
|
|
14
|
-
const material = useMemo(() => {
|
|
15
|
-
const mat = node.material;
|
|
16
|
-
if (!mat)
|
|
17
|
-
return DEFAULT_WINDOW_MATERIAL;
|
|
18
|
-
return createMaterial(mat);
|
|
19
|
-
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
|
|
20
|
-
return (_jsx("mesh", { castShadow: true, material: material, position: node.position, receiveShadow: true, ref: ref, rotation: node.rotation, visible: node.visible, ...(isTransient ? {} : handlers), children: _jsx("boxGeometry", { args: [0, 0, 0] }) }));
|
|
21
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"zone-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/zone/zone-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAyG7D,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,mDAqJxD,CAAA"}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRegistry } from '@pascal-app/core';
|
|
3
|
-
import { Html } from '@react-three/drei';
|
|
4
|
-
import { useMemo, useRef } from 'react';
|
|
5
|
-
import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, Shape } from 'three';
|
|
6
|
-
import { color, float, uniform, uv } from 'three/tsl';
|
|
7
|
-
import { MeshBasicNodeMaterial } from 'three/webgpu';
|
|
8
|
-
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
9
|
-
import { ZONE_LAYER } from '../../../lib/layers';
|
|
10
|
-
const Y_OFFSET = 0.01;
|
|
11
|
-
const WALL_HEIGHT = 2.3;
|
|
12
|
-
/**
|
|
13
|
-
* Creates a gradient material for zone walls using TSL
|
|
14
|
-
* Gradient goes from zone color at bottom to transparent at top
|
|
15
|
-
*/
|
|
16
|
-
const createWallGradientMaterial = (zoneColor) => {
|
|
17
|
-
const baseColor = color(new Color(zoneColor));
|
|
18
|
-
// Use UV y coordinate for vertical gradient (0 at bottom, 1 at top)
|
|
19
|
-
const gradientT = uv().y;
|
|
20
|
-
const opacity = uniform(0);
|
|
21
|
-
// Fade opacity from 0.6 at bottom to 0 at top
|
|
22
|
-
const finalOpacity = float(0.6).mul(float(1).sub(gradientT)).mul(opacity);
|
|
23
|
-
return new MeshBasicNodeMaterial({
|
|
24
|
-
transparent: true,
|
|
25
|
-
colorNode: baseColor,
|
|
26
|
-
opacityNode: finalOpacity,
|
|
27
|
-
side: DoubleSide,
|
|
28
|
-
depthWrite: true,
|
|
29
|
-
depthTest: false,
|
|
30
|
-
userData: {
|
|
31
|
-
uOpacity: opacity,
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Creates a floor material for zones using TSL
|
|
37
|
-
*/
|
|
38
|
-
const createFloorMaterial = (zoneColor) => {
|
|
39
|
-
const baseColor = color(new Color(zoneColor));
|
|
40
|
-
const opacity = uniform(0);
|
|
41
|
-
return new MeshBasicNodeMaterial({
|
|
42
|
-
transparent: true,
|
|
43
|
-
colorNode: baseColor,
|
|
44
|
-
opacityNode: float(0.25).mul(opacity),
|
|
45
|
-
side: DoubleSide,
|
|
46
|
-
depthWrite: false,
|
|
47
|
-
depthTest: false,
|
|
48
|
-
userData: { uOpacity: opacity },
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Creates wall geometry for zone borders
|
|
53
|
-
* Each wall segment is a vertical quad from one polygon point to the next
|
|
54
|
-
*/
|
|
55
|
-
const createWallGeometry = (polygon) => {
|
|
56
|
-
const geometry = new BufferGeometry();
|
|
57
|
-
if (polygon.length < 2)
|
|
58
|
-
return geometry;
|
|
59
|
-
const positions = [];
|
|
60
|
-
const uvs = [];
|
|
61
|
-
const indices = [];
|
|
62
|
-
// Create a wall segment for each edge of the polygon
|
|
63
|
-
for (let i = 0; i < polygon.length; i++) {
|
|
64
|
-
const current = polygon[i];
|
|
65
|
-
const next = polygon[(i + 1) % polygon.length];
|
|
66
|
-
const baseIndex = i * 4;
|
|
67
|
-
// Four vertices per wall segment (two triangles forming a quad)
|
|
68
|
-
// Bottom-left
|
|
69
|
-
positions.push(current[0], Y_OFFSET, current[1]);
|
|
70
|
-
uvs.push(0, 0);
|
|
71
|
-
// Bottom-right
|
|
72
|
-
positions.push(next[0], Y_OFFSET, next[1]);
|
|
73
|
-
uvs.push(1, 0);
|
|
74
|
-
// Top-right
|
|
75
|
-
positions.push(next[0], Y_OFFSET + WALL_HEIGHT, next[1]);
|
|
76
|
-
uvs.push(1, 1);
|
|
77
|
-
// Top-left
|
|
78
|
-
positions.push(current[0], Y_OFFSET + WALL_HEIGHT, current[1]);
|
|
79
|
-
uvs.push(0, 1);
|
|
80
|
-
// Two triangles for the quad
|
|
81
|
-
indices.push(baseIndex, baseIndex + 1, baseIndex + 2, baseIndex, baseIndex + 2, baseIndex + 3);
|
|
82
|
-
}
|
|
83
|
-
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
|
|
84
|
-
geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
|
|
85
|
-
geometry.setIndex(indices);
|
|
86
|
-
geometry.computeVertexNormals();
|
|
87
|
-
return geometry;
|
|
88
|
-
};
|
|
89
|
-
export const ZoneRenderer = ({ node }) => {
|
|
90
|
-
const ref = useRef(null);
|
|
91
|
-
useRegistry(node.id, 'zone', ref);
|
|
92
|
-
// Create floor shape from polygon
|
|
93
|
-
const floorShape = useMemo(() => {
|
|
94
|
-
if (!node?.polygon || node.polygon.length < 3)
|
|
95
|
-
return null;
|
|
96
|
-
const shape = new Shape();
|
|
97
|
-
const firstPt = node.polygon[0];
|
|
98
|
-
// Shape is in X-Y plane, we rotate it to X-Z plane
|
|
99
|
-
// Negate Y (which becomes Z) to get correct orientation
|
|
100
|
-
shape.moveTo(firstPt[0], -firstPt[1]);
|
|
101
|
-
for (let i = 1; i < node.polygon.length; i++) {
|
|
102
|
-
const pt = node.polygon[i];
|
|
103
|
-
shape.lineTo(pt[0], -pt[1]);
|
|
104
|
-
}
|
|
105
|
-
shape.closePath();
|
|
106
|
-
return shape;
|
|
107
|
-
}, [node?.polygon]);
|
|
108
|
-
// Create wall geometry from polygon
|
|
109
|
-
const wallGeometry = useMemo(() => {
|
|
110
|
-
if (!node?.polygon || node.polygon.length < 2)
|
|
111
|
-
return null;
|
|
112
|
-
return createWallGeometry(node.polygon);
|
|
113
|
-
}, [node?.polygon]);
|
|
114
|
-
// Calculate polygon centroid for label positioning using the geometric centroid formula
|
|
115
|
-
// This correctly handles polygons regardless of vertex distribution along edges
|
|
116
|
-
const centroid = useMemo(() => {
|
|
117
|
-
if (!node?.polygon || node.polygon.length < 3)
|
|
118
|
-
return [0, 0];
|
|
119
|
-
const polygon = node.polygon;
|
|
120
|
-
let signedArea = 0;
|
|
121
|
-
let cx = 0;
|
|
122
|
-
let cz = 0;
|
|
123
|
-
for (let i = 0; i < polygon.length; i++) {
|
|
124
|
-
const [x0, z0] = polygon[i];
|
|
125
|
-
const [x1, z1] = polygon[(i + 1) % polygon.length];
|
|
126
|
-
// Cross product for signed area
|
|
127
|
-
const cross = x0 * z1 - x1 * z0;
|
|
128
|
-
signedArea += cross;
|
|
129
|
-
cx += (x0 + x1) * cross;
|
|
130
|
-
cz += (z0 + z1) * cross;
|
|
131
|
-
}
|
|
132
|
-
signedArea /= 2;
|
|
133
|
-
const factor = 1 / (6 * signedArea);
|
|
134
|
-
return [cx * factor, cz * factor];
|
|
135
|
-
}, [node?.polygon]);
|
|
136
|
-
// Create materials
|
|
137
|
-
const floorMaterial = useMemo(() => {
|
|
138
|
-
if (!node?.color)
|
|
139
|
-
return null;
|
|
140
|
-
return createFloorMaterial(node.color);
|
|
141
|
-
}, [node?.color]);
|
|
142
|
-
const wallMaterial = useMemo(() => {
|
|
143
|
-
if (!node?.color)
|
|
144
|
-
return null;
|
|
145
|
-
return createWallGradientMaterial(node.color);
|
|
146
|
-
}, [node?.color]);
|
|
147
|
-
const handlers = useNodeEvents(node, 'zone');
|
|
148
|
-
if (!(node && floorShape && wallGeometry && floorMaterial && wallMaterial)) {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
return (_jsxs("group", { ref: ref, ...handlers, userData: { labelPosition: [centroid[0], 1, centroid[1]] }, children: [_jsx(Html, { name: "label", position: [centroid[0], 1, centroid[1]], style: { pointerEvents: 'none' }, zIndexRange: [10, 0], children: _jsxs("div", { id: `${node.id}-label`, style: {
|
|
152
|
-
display: 'flex',
|
|
153
|
-
flexDirection: 'column',
|
|
154
|
-
alignItems: 'center',
|
|
155
|
-
transform: 'translate3d(-50%, -50%, 0)',
|
|
156
|
-
opacity: 0,
|
|
157
|
-
transition: 'opacity 0.3s ease-in-out',
|
|
158
|
-
}, children: [_jsx("div", { style: {
|
|
159
|
-
width: 'max-content',
|
|
160
|
-
color: 'white',
|
|
161
|
-
textShadow: `-1px -1px 0 ${node.color}, 1px -1px 0 ${node.color}, -1px 1px 0 ${node.color}, 1px 1px 0 ${node.color}`,
|
|
162
|
-
textAlign: 'center',
|
|
163
|
-
}, children: _jsx("span", { children: node.name }) }), _jsxs("div", { className: "label-pin", style: {
|
|
164
|
-
display: 'flex',
|
|
165
|
-
flexDirection: 'column',
|
|
166
|
-
alignItems: 'center',
|
|
167
|
-
marginTop: '2px',
|
|
168
|
-
opacity: 0,
|
|
169
|
-
transition: 'opacity 0.5s ease-in-out',
|
|
170
|
-
}, children: [_jsx("div", { style: {
|
|
171
|
-
width: '2px',
|
|
172
|
-
height: '40px',
|
|
173
|
-
backgroundColor: node.color,
|
|
174
|
-
} }), _jsx("div", { style: {
|
|
175
|
-
width: '10px',
|
|
176
|
-
height: '10px',
|
|
177
|
-
borderRadius: '50%',
|
|
178
|
-
backgroundColor: node.color,
|
|
179
|
-
border: '1px solid white',
|
|
180
|
-
} })] })] }) }), _jsx("mesh", { layers: ZONE_LAYER, material: floorMaterial, name: "floor", position: [0, Y_OFFSET, 0], rotation: [-Math.PI / 2, 0, 0], children: _jsx("shapeGeometry", { args: [floorShape] }) }), _jsx("mesh", { geometry: wallGeometry, layers: ZONE_LAYER, material: wallMaterial, name: "walls" })] }));
|
|
181
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Suppresses the `THREE.Clock: This module has been deprecated` warning
|
|
3
|
-
* emitted by three.js r183+ on every `new THREE.Clock()` call.
|
|
4
|
-
*
|
|
5
|
-
* We don't instantiate `Clock` ourselves — `@react-three/fiber` 9.x
|
|
6
|
-
* (current stable) creates one internally per `<Canvas>` mount. The
|
|
7
|
-
* migration to `THREE.Timer` lands in R3F 10.x (still alpha).
|
|
8
|
-
*
|
|
9
|
-
* Uses three's `setConsoleFunction` hook so we don't touch `console.warn`
|
|
10
|
-
* globally. Only the exact Clock deprecation message is suppressed; all
|
|
11
|
-
* other three.js logs (including TSL stack-trace warnings) pass through
|
|
12
|
-
* untouched.
|
|
13
|
-
*
|
|
14
|
-
* Runs in production as well as dev — the suppressed message is a pure
|
|
15
|
-
* deprecation notice with no user-actionable content.
|
|
16
|
-
*
|
|
17
|
-
* REMOVAL: safe to delete once `@react-three/fiber` no longer constructs
|
|
18
|
-
* `new THREE.Clock()`. To verify after an R3F upgrade:
|
|
19
|
-
* grep -n "new THREE.Clock" node_modules/@react-three/fiber/dist/*.js
|
|
20
|
-
* No hits → delete this file and its import in components/viewer/index.tsx.
|
|
21
|
-
*
|
|
22
|
-
* @see https://github.com/pascalorg/editor/issues/213
|
|
23
|
-
*/
|
|
24
|
-
export {};
|
|
25
|
-
//# sourceMappingURL=suppress-three-clock-warning.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"suppress-three-clock-warning.d.ts","sourceRoot":"","sources":["../../src/lib/suppress-three-clock-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Suppresses the `THREE.Clock: This module has been deprecated` warning
|
|
3
|
-
* emitted by three.js r183+ on every `new THREE.Clock()` call.
|
|
4
|
-
*
|
|
5
|
-
* We don't instantiate `Clock` ourselves — `@react-three/fiber` 9.x
|
|
6
|
-
* (current stable) creates one internally per `<Canvas>` mount. The
|
|
7
|
-
* migration to `THREE.Timer` lands in R3F 10.x (still alpha).
|
|
8
|
-
*
|
|
9
|
-
* Uses three's `setConsoleFunction` hook so we don't touch `console.warn`
|
|
10
|
-
* globally. Only the exact Clock deprecation message is suppressed; all
|
|
11
|
-
* other three.js logs (including TSL stack-trace warnings) pass through
|
|
12
|
-
* untouched.
|
|
13
|
-
*
|
|
14
|
-
* Runs in production as well as dev — the suppressed message is a pure
|
|
15
|
-
* deprecation notice with no user-actionable content.
|
|
16
|
-
*
|
|
17
|
-
* REMOVAL: safe to delete once `@react-three/fiber` no longer constructs
|
|
18
|
-
* `new THREE.Clock()`. To verify after an R3F upgrade:
|
|
19
|
-
* grep -n "new THREE.Clock" node_modules/@react-three/fiber/dist/*.js
|
|
20
|
-
* No hits → delete this file and its import in components/viewer/index.tsx.
|
|
21
|
-
*
|
|
22
|
-
* @see https://github.com/pascalorg/editor/issues/213
|
|
23
|
-
*/
|
|
24
|
-
import { setConsoleFunction } from 'three';
|
|
25
|
-
// three's warn() prepends 'THREE.' to its first argument, and the Clock
|
|
26
|
-
// constructor passes 'THREE.Clock: ...', producing a double-prefixed
|
|
27
|
-
// string. Exact equality keeps the suppression surgical — if three ever
|
|
28
|
-
// rewords this, the filter stops matching and the message resurfaces.
|
|
29
|
-
const CLOCK_DEPRECATION_MESSAGE = 'THREE.THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.';
|
|
30
|
-
// HMR-idempotent install guard. setConsoleFunction is a single-slot global
|
|
31
|
-
// in three, so re-evaluating this module on HMR would reinstall the hook.
|
|
32
|
-
const INSTALLED = Symbol.for('@pascal-app/viewer/suppress-three-clock-warning');
|
|
33
|
-
if (!globalThis[INSTALLED]) {
|
|
34
|
-
;
|
|
35
|
-
globalThis[INSTALLED] = true;
|
|
36
|
-
setConsoleFunction((method, message, ...params) => {
|
|
37
|
-
if (method === 'warn' && message === CLOCK_DEPRECATION_MESSAGE) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// Mirror three's default stack-trace handling so TSL warnings/errors
|
|
41
|
-
// keep their clickable stack frames.
|
|
42
|
-
if (method !== 'log') {
|
|
43
|
-
const first = params[0];
|
|
44
|
-
if (first?.isStackTrace && typeof first.getError === 'function') {
|
|
45
|
-
console[method](first.getError(message));
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
console[method](message, ...params);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"export-system.d.ts","sourceRoot":"","sources":["../../../src/systems/export/export-system.tsx"],"names":[],"mappings":"AAwBA,eAAO,MAAM,YAAY,YAgDxB,CAAA"}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { useThree } from '@react-three/fiber';
|
|
3
|
-
import { useEffect } from 'react';
|
|
4
|
-
import * as THREE from 'three';
|
|
5
|
-
import { STLExporter } from 'three/examples/jsm/exporters/STLExporter.js';
|
|
6
|
-
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
|
7
|
-
import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js';
|
|
8
|
-
import useViewer from '../../store/use-viewer';
|
|
9
|
-
const EDITOR_LAYER = 1; // same constant used across the editor
|
|
10
|
-
function downloadBlob(blob, filename) {
|
|
11
|
-
const url = URL.createObjectURL(blob);
|
|
12
|
-
const a = document.createElement('a');
|
|
13
|
-
a.href = url;
|
|
14
|
-
a.download = filename;
|
|
15
|
-
document.body.appendChild(a);
|
|
16
|
-
a.click();
|
|
17
|
-
document.body.removeChild(a);
|
|
18
|
-
URL.revokeObjectURL(url);
|
|
19
|
-
}
|
|
20
|
-
export const ExportSystem = () => {
|
|
21
|
-
const { scene } = useThree();
|
|
22
|
-
const setExportScene = useViewer((state) => state.setExportScene);
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const exportFn = async (format = 'glb') => {
|
|
25
|
-
const date = new Date().toISOString().split('T')[0];
|
|
26
|
-
const filename = `pascal-export-${date}`;
|
|
27
|
-
// Clone scene and strip editor-only objects (layer 1 = EDITOR_LAYER)
|
|
28
|
-
const exportRoot = scene.clone(true);
|
|
29
|
-
const toRemove = [];
|
|
30
|
-
exportRoot.traverse((obj) => {
|
|
31
|
-
if (obj.layers.isEnabled(EDITOR_LAYER)) {
|
|
32
|
-
toRemove.push(obj);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
for (const obj of toRemove) {
|
|
36
|
-
obj.parent?.remove(obj);
|
|
37
|
-
}
|
|
38
|
-
if (format === 'glb') {
|
|
39
|
-
const exporter = new GLTFExporter();
|
|
40
|
-
const result = await new Promise((resolve, reject) => {
|
|
41
|
-
exporter.parse(exportRoot, (output) => resolve(output), (err) => reject(err), { binary: true });
|
|
42
|
-
});
|
|
43
|
-
downloadBlob(new Blob([result], { type: 'model/gltf-binary' }), `${filename}.glb`);
|
|
44
|
-
}
|
|
45
|
-
else if (format === 'stl') {
|
|
46
|
-
const exporter = new STLExporter();
|
|
47
|
-
const result = exporter.parse(exportRoot, { binary: true });
|
|
48
|
-
downloadBlob(new Blob([result.buffer], { type: 'model/stl' }), `${filename}.stl`);
|
|
49
|
-
}
|
|
50
|
-
else if (format === 'obj') {
|
|
51
|
-
const exporter = new OBJExporter();
|
|
52
|
-
const result = exporter.parse(exportRoot);
|
|
53
|
-
downloadBlob(new Blob([result], { type: 'model/obj' }), `${filename}.obj`);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
setExportScene(exportFn);
|
|
57
|
-
return () => setExportScene(null);
|
|
58
|
-
}, [scene, setExportScene]);
|
|
59
|
-
return null;
|
|
60
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Object3D } from 'three';
|
|
2
|
-
type Point = {
|
|
3
|
-
x: number;
|
|
4
|
-
y: number;
|
|
5
|
-
};
|
|
6
|
-
export type MeshLocalBounds = {
|
|
7
|
-
min: [number, number, number];
|
|
8
|
-
max: [number, number, number];
|
|
9
|
-
};
|
|
10
|
-
/** Plan footprint in the item root's horizontal (x, z) plane — stored as floorplan polygon. */
|
|
11
|
-
export declare function computePlanFootprintPolygonLocal(object: Object3D): Point[];
|
|
12
|
-
export declare function computeMeshLocalBoundsFromObject(object: Object3D): MeshLocalBounds | null;
|
|
13
|
-
export {};
|
|
14
|
-
//# sourceMappingURL=compute-item-mesh-metadata.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compute-item-mesh-metadata.d.ts","sourceRoot":"","sources":["../../../src/systems/item-mesh-metadata/compute-item-mesh-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGrC,KAAK,KAAK,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAErC,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B,CAAA;AAED,+FAA+F;AAC/F,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,EAAE,CA0E1E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,GAAG,IAAI,CAmDzF"}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { Box3, Matrix4, Vector3 } from 'three';
|
|
2
|
-
/** Plan footprint in the item root's horizontal (x, z) plane — stored as floorplan polygon. */
|
|
3
|
-
export function computePlanFootprintPolygonLocal(object) {
|
|
4
|
-
object.updateWorldMatrix(true, true);
|
|
5
|
-
const inverseRootMatrix = new Matrix4().copy(object.matrixWorld).invert();
|
|
6
|
-
const localMatrix = new Matrix4();
|
|
7
|
-
const scratchBounds = new Box3();
|
|
8
|
-
const scratchPosition = new Vector3();
|
|
9
|
-
const footprintPoints = [];
|
|
10
|
-
const collectPoints = (child) => {
|
|
11
|
-
const mesh = child;
|
|
12
|
-
if (mesh.isMesh && mesh.name !== 'cutout' && mesh.geometry) {
|
|
13
|
-
if (!mesh.geometry.boundingBox && mesh.geometry.computeBoundingBox) {
|
|
14
|
-
mesh.geometry.computeBoundingBox();
|
|
15
|
-
}
|
|
16
|
-
localMatrix.copy(inverseRootMatrix).multiply(mesh.matrixWorld);
|
|
17
|
-
const vertexPositions = mesh.geometry.attributes?.position;
|
|
18
|
-
if (vertexPositions && vertexPositions.count > 0) {
|
|
19
|
-
for (let index = 0; index < vertexPositions.count; index += 1) {
|
|
20
|
-
scratchPosition
|
|
21
|
-
.set(vertexPositions.getX(index), vertexPositions.getY(index), vertexPositions.getZ(index))
|
|
22
|
-
.applyMatrix4(localMatrix);
|
|
23
|
-
if (Number.isFinite(scratchPosition.x) && Number.isFinite(scratchPosition.z)) {
|
|
24
|
-
footprintPoints.push({ x: scratchPosition.x, y: scratchPosition.z });
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
else if (mesh.geometry.boundingBox) {
|
|
29
|
-
scratchBounds.copy(mesh.geometry.boundingBox);
|
|
30
|
-
scratchBounds.applyMatrix4(localMatrix);
|
|
31
|
-
if (Number.isFinite(scratchBounds.min.x) && Number.isFinite(scratchBounds.max.x)) {
|
|
32
|
-
footprintPoints.push({ x: scratchBounds.min.x, y: scratchBounds.min.z }, { x: scratchBounds.max.x, y: scratchBounds.min.z }, { x: scratchBounds.max.x, y: scratchBounds.max.z }, { x: scratchBounds.min.x, y: scratchBounds.max.z });
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
for (const grandchild of child.children) {
|
|
37
|
-
collectPoints(grandchild);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
for (const child of object.children) {
|
|
41
|
-
collectPoints(child);
|
|
42
|
-
}
|
|
43
|
-
return getMinimumAreaBoundingRect(footprintPoints) ?? [];
|
|
44
|
-
}
|
|
45
|
-
export function computeMeshLocalBoundsFromObject(object) {
|
|
46
|
-
object.updateWorldMatrix(true, true);
|
|
47
|
-
const inverseRootMatrix = new Matrix4().copy(object.matrixWorld).invert();
|
|
48
|
-
const localMatrix = new Matrix4();
|
|
49
|
-
const localBounds = new Box3();
|
|
50
|
-
const scratchBounds = new Box3();
|
|
51
|
-
let hasBounds = false;
|
|
52
|
-
const expandBounds = (child) => {
|
|
53
|
-
const mesh = child;
|
|
54
|
-
if (mesh.isMesh && mesh.name !== 'cutout' && mesh.geometry) {
|
|
55
|
-
if (!mesh.geometry.boundingBox && mesh.geometry.computeBoundingBox) {
|
|
56
|
-
mesh.geometry.computeBoundingBox();
|
|
57
|
-
}
|
|
58
|
-
if (mesh.geometry.boundingBox) {
|
|
59
|
-
localMatrix.copy(inverseRootMatrix).multiply(mesh.matrixWorld);
|
|
60
|
-
scratchBounds.copy(mesh.geometry.boundingBox).applyMatrix4(localMatrix);
|
|
61
|
-
if (!hasBounds) {
|
|
62
|
-
localBounds.copy(scratchBounds);
|
|
63
|
-
hasBounds = true;
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
localBounds.union(scratchBounds);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
for (const grandchild of child.children) {
|
|
71
|
-
expandBounds(grandchild);
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
for (const child of object.children) {
|
|
75
|
-
expandBounds(child);
|
|
76
|
-
}
|
|
77
|
-
if (!hasBounds)
|
|
78
|
-
return null;
|
|
79
|
-
return {
|
|
80
|
-
min: [localBounds.min.x, localBounds.min.y, localBounds.min.z],
|
|
81
|
-
max: [localBounds.max.x, localBounds.max.y, localBounds.max.z],
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function getMinimumAreaBoundingRect(points) {
|
|
85
|
-
if (points.length === 0)
|
|
86
|
-
return null;
|
|
87
|
-
if (points.length < 3)
|
|
88
|
-
return points;
|
|
89
|
-
const hull = getConvexHull(points);
|
|
90
|
-
if (hull.length < 3)
|
|
91
|
-
return hull;
|
|
92
|
-
let bestArea = Number.POSITIVE_INFINITY;
|
|
93
|
-
let bestRect = null;
|
|
94
|
-
for (let index = 0; index < hull.length; index += 1) {
|
|
95
|
-
const nextIndex = (index + 1) % hull.length;
|
|
96
|
-
const current = hull[index];
|
|
97
|
-
const next = hull[nextIndex];
|
|
98
|
-
const angle = Math.atan2(next.y - current.y, next.x - current.x);
|
|
99
|
-
const cos = Math.cos(-angle);
|
|
100
|
-
const sin = Math.sin(-angle);
|
|
101
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
102
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
103
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
104
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
105
|
-
for (const point of hull) {
|
|
106
|
-
const rx = point.x * cos - point.y * sin;
|
|
107
|
-
const ry = point.x * sin + point.y * cos;
|
|
108
|
-
minX = Math.min(minX, rx);
|
|
109
|
-
maxX = Math.max(maxX, rx);
|
|
110
|
-
minY = Math.min(minY, ry);
|
|
111
|
-
maxY = Math.max(maxY, ry);
|
|
112
|
-
}
|
|
113
|
-
const area = (maxX - minX) * (maxY - minY);
|
|
114
|
-
if (area >= bestArea)
|
|
115
|
-
continue;
|
|
116
|
-
bestArea = area;
|
|
117
|
-
const unrotate = (x, y) => ({
|
|
118
|
-
x: x * Math.cos(angle) - y * Math.sin(angle),
|
|
119
|
-
y: x * Math.sin(angle) + y * Math.cos(angle),
|
|
120
|
-
});
|
|
121
|
-
bestRect = [
|
|
122
|
-
unrotate(minX, minY),
|
|
123
|
-
unrotate(maxX, minY),
|
|
124
|
-
unrotate(maxX, maxY),
|
|
125
|
-
unrotate(minX, maxY),
|
|
126
|
-
];
|
|
127
|
-
}
|
|
128
|
-
return bestRect;
|
|
129
|
-
}
|
|
130
|
-
function getConvexHull(points) {
|
|
131
|
-
if (points.length <= 1)
|
|
132
|
-
return points;
|
|
133
|
-
const sorted = [...points].sort((a, b) => (a.x === b.x ? a.y - b.y : a.x - b.x));
|
|
134
|
-
const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
135
|
-
const lower = [];
|
|
136
|
-
for (const point of sorted) {
|
|
137
|
-
while (lower.length >= 2 &&
|
|
138
|
-
cross(lower[lower.length - 2], lower[lower.length - 1], point) <= 0) {
|
|
139
|
-
lower.pop();
|
|
140
|
-
}
|
|
141
|
-
lower.push(point);
|
|
142
|
-
}
|
|
143
|
-
const upper = [];
|
|
144
|
-
for (let index = sorted.length - 1; index >= 0; index -= 1) {
|
|
145
|
-
const point = sorted[index];
|
|
146
|
-
while (upper.length >= 2 &&
|
|
147
|
-
cross(upper[upper.length - 2], upper[upper.length - 1], point) <= 0) {
|
|
148
|
-
upper.pop();
|
|
149
|
-
}
|
|
150
|
-
upper.push(point);
|
|
151
|
-
}
|
|
152
|
-
lower.pop();
|
|
153
|
-
upper.pop();
|
|
154
|
-
return [...lower, ...upper];
|
|
155
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Writes `meshLocalPlanPolygon` / `meshLocalBounds` from loaded item meshes.
|
|
3
|
-
* ModelRenderer requests sync via `requestItemMeshMetadataSync` when GLTF is ready.
|
|
4
|
-
*/
|
|
5
|
-
export declare function ItemMeshMetadataSystem(): null;
|
|
6
|
-
//# sourceMappingURL=item-mesh-metadata-system.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"item-mesh-metadata-system.d.ts","sourceRoot":"","sources":["../../../src/systems/item-mesh-metadata/item-mesh-metadata-system.tsx"],"names":[],"mappings":"AAoFA;;;GAGG;AACH,wBAAgB,sBAAsB,SAYrC"}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { sceneRegistry, useScene } from '@pascal-app/core';
|
|
3
|
-
import { useFrame } from '@react-three/fiber';
|
|
4
|
-
import { computeMeshLocalBoundsFromObject, computePlanFootprintPolygonLocal, } from './compute-item-mesh-metadata';
|
|
5
|
-
import { drainItemMeshMetadataSyncRequests, getItemMeshMetadataSourceRoot } from './sync-request';
|
|
6
|
-
function isMetadataUnchanged(nextPolygon, nextBounds, metadata) {
|
|
7
|
-
const currentPolygon = metadata.meshLocalPlanPolygon;
|
|
8
|
-
const currentBounds = typeof metadata.meshLocalBounds === 'object' &&
|
|
9
|
-
metadata.meshLocalBounds !== null &&
|
|
10
|
-
!Array.isArray(metadata.meshLocalBounds)
|
|
11
|
-
? metadata.meshLocalBounds
|
|
12
|
-
: null;
|
|
13
|
-
const polygonUnchanged = (nextPolygon === null &&
|
|
14
|
-
(currentPolygon === undefined || currentPolygon === null || currentPolygon === false)) ||
|
|
15
|
-
(Array.isArray(currentPolygon) &&
|
|
16
|
-
nextPolygon !== null &&
|
|
17
|
-
currentPolygon.length === nextPolygon.length &&
|
|
18
|
-
currentPolygon.every((point, index) => Array.isArray(point) &&
|
|
19
|
-
point[0] === nextPolygon[index]?.[0] &&
|
|
20
|
-
point[1] === nextPolygon[index]?.[1]));
|
|
21
|
-
const boundsUnchanged = (nextBounds === null && (currentBounds === undefined || currentBounds === null)) ||
|
|
22
|
-
(nextBounds !== null &&
|
|
23
|
-
Array.isArray(currentBounds?.min) &&
|
|
24
|
-
Array.isArray(currentBounds?.max) &&
|
|
25
|
-
currentBounds.min[0] === nextBounds.min[0] &&
|
|
26
|
-
currentBounds.min[1] === nextBounds.min[1] &&
|
|
27
|
-
currentBounds.min[2] === nextBounds.min[2] &&
|
|
28
|
-
currentBounds.max[0] === nextBounds.max[0] &&
|
|
29
|
-
currentBounds.max[1] === nextBounds.max[1] &&
|
|
30
|
-
currentBounds.max[2] === nextBounds.max[2]);
|
|
31
|
-
return polygonUnchanged && boundsUnchanged;
|
|
32
|
-
}
|
|
33
|
-
function trySyncItemMeshMetadata(itemId, nodes) {
|
|
34
|
-
const node = nodes[itemId];
|
|
35
|
-
if (!node || node.type !== 'item')
|
|
36
|
-
return;
|
|
37
|
-
const root = getItemMeshMetadataSourceRoot(itemId) ??
|
|
38
|
-
sceneRegistry.nodes.get(itemId);
|
|
39
|
-
if (!root)
|
|
40
|
-
return;
|
|
41
|
-
const polygon = computePlanFootprintPolygonLocal(root);
|
|
42
|
-
const bounds = computeMeshLocalBoundsFromObject(root);
|
|
43
|
-
if (polygon.length < 3 && !bounds)
|
|
44
|
-
return;
|
|
45
|
-
const nextPolygon = polygon.length >= 3 ? polygon.map(({ x, y }) => [x, y]) : null;
|
|
46
|
-
const nextBounds = bounds ? { min: bounds.min, max: bounds.max } : null;
|
|
47
|
-
const metadata = typeof node.metadata === 'object' && node.metadata !== null && !Array.isArray(node.metadata)
|
|
48
|
-
? node.metadata
|
|
49
|
-
: {};
|
|
50
|
-
if (isMetadataUnchanged(nextPolygon, nextBounds, metadata))
|
|
51
|
-
return;
|
|
52
|
-
useScene.getState().updateNode(itemId, {
|
|
53
|
-
metadata: {
|
|
54
|
-
...metadata,
|
|
55
|
-
...(nextPolygon ? { meshLocalPlanPolygon: nextPolygon } : {}),
|
|
56
|
-
...(nextBounds ? { meshLocalBounds: nextBounds } : {}),
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Writes `meshLocalPlanPolygon` / `meshLocalBounds` from loaded item meshes.
|
|
62
|
-
* ModelRenderer requests sync via `requestItemMeshMetadataSync` when GLTF is ready.
|
|
63
|
-
*/
|
|
64
|
-
export function ItemMeshMetadataSystem() {
|
|
65
|
-
useFrame(() => {
|
|
66
|
-
const ids = drainItemMeshMetadataSyncRequests();
|
|
67
|
-
if (ids.length === 0)
|
|
68
|
-
return;
|
|
69
|
-
const nodes = useScene.getState().nodes;
|
|
70
|
-
for (const id of ids) {
|
|
71
|
-
trySyncItemMeshMetadata(id, nodes);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Object3D } from 'three';
|
|
2
|
-
/** Called when an item's loaded GLTF (or metadata driving footprint) may need re-syncing. */
|
|
3
|
-
export declare function requestItemMeshMetadataSync(itemId: string): void;
|
|
4
|
-
export declare function setItemMeshMetadataSourceRoot(itemId: string, root: Object3D | null): void;
|
|
5
|
-
export declare function getItemMeshMetadataSourceRoot(itemId: string): Object3D | undefined;
|
|
6
|
-
export declare function drainItemMeshMetadataSyncRequests(): string[];
|
|
7
|
-
//# sourceMappingURL=sync-request.d.ts.map
|