@crystaldesign/real-time-viewer-next 26.11.0-beta.24 → 26.11.0-beta.26
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/build/esm/{DeckCutoutSubsystem-4369a7a2.js → DeckCutoutSubsystem-9560be24.js} +258 -174
- package/build/esm/{SunLensflare-6d65fd17.js → SunLensflare-5113b471.js} +6 -3
- package/build/esm/{WaterSurface-95b630aa.js → WaterSurface-c54c2940.js} +115 -79
- package/build/esm/{index-fa3c5a24.js → index-8a26c68f.js} +4348 -2915
- package/build/esm/index.js +7 -4
- package/build/types/real-time-viewer-next/src/RealTimeRendererNext.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/config/environment.config.d.ts +2 -0
- package/build/types/real-time-viewer-next/src/config/environment.config.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/AssetErrorGate.d.ts +7 -0
- package/build/types/real-time-viewer-next/src/core/AssetErrorGate.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/core/ErrorView.d.ts +16 -0
- package/build/types/real-time-viewer-next/src/core/ErrorView.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/core/GeoInstance.d.ts +3 -1
- package/build/types/real-time-viewer-next/src/core/GeoInstance.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/RTVErrorBoundary.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/SceneRenderer.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/SceneTree.d.ts +1 -1
- package/build/types/real-time-viewer-next/src/core/SceneTree.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/VariantMeshOverride.d.ts +1 -1
- package/build/types/real-time-viewer-next/src/core/VariantMeshOverride.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLines3D.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSceneLoader.d.ts +5 -0
- package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSceneLoader.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/SceneEnvironment.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/SkydomeBackground.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutArticleSync.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutCollar.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/articleFootprint.d.ts +3 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/articleFootprint.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/buildCollarGeometry.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureDiagnostics.d.ts +2 -1
- package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureDiagnostics.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/useEnvironmentMap.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/interaction/FreeGridLayer.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/interaction/InteractionGuides.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/materials/caches.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/materials/factory.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/materials/materials.config.d.ts +15 -0
- package/build/types/real-time-viewer-next/src/core/materials/materials.config.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/materials/textureCache.d.ts +14 -0
- package/build/types/real-time-viewer-next/src/core/materials/textureCache.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/meshBVH.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/postprocessing/PostProcessingStack.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/useFrameloopVisibility.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/view2d/Element2DPlane.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/water/CausticReceiver.d.ts +2 -0
- package/build/types/real-time-viewer-next/src/core/water/CausticReceiver.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/water/CausticsTexture.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/water/WaterSurface.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/water/WaterSurfaceRenderer.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/water/waterShaders.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/hooks/useStableEnvSlice.d.ts +9 -0
- package/build/types/real-time-viewer-next/src/hooks/useStableEnvSlice.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/presets/polyfaser-pool.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/store/index.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/store/slices/assetErrors.d.ts +15 -0
- package/build/types/real-time-viewer-next/src/store/slices/assetErrors.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/store/slices/glGeneration.d.ts +12 -0
- package/build/types/real-time-viewer-next/src/store/slices/glGeneration.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/store/types.d.ts +2 -1
- package/build/types/real-time-viewer-next/src/store/types.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/equirectCache.d.ts +16 -0
- package/build/types/real-time-viewer-next/src/utils/equirectCache.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/footprintTrace.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/gltfLoader.d.ts +20 -0
- package/build/types/real-time-viewer-next/src/utils/gltfLoader.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/gltfLoader.preview.test.d.ts +5 -0
- package/build/types/real-time-viewer-next/src/utils/gltfLoader.preview.test.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/utils/gpuMemoryAudit.d.ts +12 -0
- package/build/types/real-time-viewer-next/src/utils/gpuMemoryAudit.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/utils/polygon2d.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/profiles.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/rasterMask.d.ts +1 -0
- package/build/types/real-time-viewer-next/src/utils/rasterMask.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/suspense.d.ts +2 -0
- package/build/types/real-time-viewer-next/src/utils/suspense.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/utils/suspense.test.d.ts +2 -0
- package/build/types/real-time-viewer-next/src/utils/suspense.test.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/utils/textureSourceRelease.d.ts +23 -0
- package/build/types/real-time-viewer-next/src/utils/textureSourceRelease.d.ts.map +1 -0
- package/build/types/real-time-viewer-next/src/utils/textureSourceRelease.test.d.ts +5 -0
- package/build/types/real-time-viewer-next/src/utils/textureSourceRelease.test.d.ts.map +1 -0
- package/build/umd/699.real-time-viewer-next.umd.min.js +1 -1
- package/build/umd/964.real-time-viewer-next.umd.min.js +1 -1
- package/build/umd/real-time-viewer-next.umd.min.js +1 -1
- package/build/umd/report.html +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as parseElementKey, u as useRTVStore, b as bootPhase, D as DECK_COLLAR_LOAD_ID } from './index-
|
|
2
|
-
import {
|
|
1
|
+
import { p as parseElementKey, u as useStableEnvSlice, a as useRTVStore, b as bootPhase, D as DECK_COLLAR_LOAD_ID } from './index-8a26c68f.js';
|
|
2
|
+
import { useRef, useEffect, useMemo, useState, useCallback } from 'react';
|
|
3
3
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
4
4
|
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
5
5
|
import { useThree, useFrame } from '@react-three/fiber';
|
|
@@ -9,12 +9,12 @@ import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
|
9
9
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
10
|
import '@babel/runtime/helpers/asyncToGenerator';
|
|
11
11
|
import '@babel/runtime/regenerator';
|
|
12
|
-
import 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
13
|
-
import 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
14
12
|
import 'zustand';
|
|
15
13
|
import 'zustand/middleware';
|
|
16
14
|
import '@babel/runtime/helpers/typeof';
|
|
17
15
|
import 'postprocessing';
|
|
16
|
+
import 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
17
|
+
import 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
18
18
|
import '@react-three/drei';
|
|
19
19
|
import '@babel/runtime/helpers/classCallCheck';
|
|
20
20
|
import '@babel/runtime/helpers/createClass';
|
|
@@ -23,6 +23,9 @@ import '@babel/runtime/helpers/getPrototypeOf';
|
|
|
23
23
|
import '@babel/runtime/helpers/inherits';
|
|
24
24
|
import 'classnames';
|
|
25
25
|
import 'three-mesh-bvh';
|
|
26
|
+
import 'three/examples/jsm/lines/LineSegments2.js';
|
|
27
|
+
import 'three/examples/jsm/lines/LineSegmentsGeometry.js';
|
|
28
|
+
import 'three/examples/jsm/lines/LineMaterial.js';
|
|
26
29
|
import '@babel/runtime/helpers/objectWithoutProperties';
|
|
27
30
|
import 'three/examples/jsm/environments/RoomEnvironment.js';
|
|
28
31
|
import 'three/examples/jsm/loaders/RGBELoader.js';
|
|
@@ -133,9 +136,9 @@ function measureArticle(scene, patterns, elementsInfo) {
|
|
|
133
136
|
};
|
|
134
137
|
}
|
|
135
138
|
|
|
136
|
-
function _createForOfIteratorHelper$
|
|
137
|
-
function _unsupportedIterableToArray$
|
|
138
|
-
function _arrayLikeToArray$
|
|
139
|
+
function _createForOfIteratorHelper$7(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$7(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
140
|
+
function _unsupportedIterableToArray$7(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$7(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$7(r, a) : void 0; } }
|
|
141
|
+
function _arrayLikeToArray$7(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
139
142
|
/*
|
|
140
143
|
* 2D polygon primitives — area, simplification, self-intersection guard, hull.
|
|
141
144
|
*/
|
|
@@ -159,45 +162,54 @@ function polygonSignedArea(points) {
|
|
|
159
162
|
return area / 2;
|
|
160
163
|
}
|
|
161
164
|
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
var maxIdx = -1;
|
|
177
|
-
for (var _i = 1; _i < points.length - 1; _i++) {
|
|
178
|
-
var _points$_i = _slicedToArray(points[_i], 2),
|
|
179
|
-
px = _points$_i[0],
|
|
180
|
-
pz = _points$_i[1];
|
|
181
|
-
var dist = Math.abs((bx - ax) * (az - pz) - (ax - px) * (bz - az)) / len;
|
|
182
|
-
if (dist > maxDist) {
|
|
183
|
-
maxDist = dist;
|
|
184
|
-
maxIdx = _i;
|
|
165
|
+
/**
|
|
166
|
+
* Douglas–Peucker on an open chain (endpoints kept), iterating over [lo, hi] index ranges with an
|
|
167
|
+
* explicit stack. The recursive form sliced a fresh sub-array per level — O(n log n) copied points
|
|
168
|
+
* and matching GC churn on the multi-thousand-point contours a fine raster produces.
|
|
169
|
+
*/
|
|
170
|
+
function simplifyChain(points, lo, hi, tolerance, out) {
|
|
171
|
+
// Flat [lo, hi] pairs; the right half is pushed first so the left half pops (and emits) first.
|
|
172
|
+
var ranges = [lo, hi];
|
|
173
|
+
while (ranges.length > 0) {
|
|
174
|
+
var rangeHi = ranges.pop();
|
|
175
|
+
var rangeLo = ranges.pop();
|
|
176
|
+
if (rangeHi - rangeLo < 2) {
|
|
177
|
+
for (var i = rangeLo; i < rangeHi; i++) out.push(points[i]);
|
|
178
|
+
continue;
|
|
185
179
|
}
|
|
180
|
+
var _points$rangeLo = _slicedToArray(points[rangeLo], 2),
|
|
181
|
+
ax = _points$rangeLo[0],
|
|
182
|
+
az = _points$rangeLo[1];
|
|
183
|
+
var _points$rangeHi = _slicedToArray(points[rangeHi], 2),
|
|
184
|
+
bx = _points$rangeHi[0],
|
|
185
|
+
bz = _points$rangeHi[1];
|
|
186
|
+
var len = Math.hypot(bx - ax, bz - az) || EPS$2;
|
|
187
|
+
var maxDist = -1;
|
|
188
|
+
var maxIdx = -1;
|
|
189
|
+
for (var _i = rangeLo + 1; _i < rangeHi; _i++) {
|
|
190
|
+
var _points$_i = _slicedToArray(points[_i], 2),
|
|
191
|
+
px = _points$_i[0],
|
|
192
|
+
pz = _points$_i[1];
|
|
193
|
+
var dist = Math.abs((bx - ax) * (az - pz) - (ax - px) * (bz - az)) / len;
|
|
194
|
+
if (dist > maxDist) {
|
|
195
|
+
maxDist = dist;
|
|
196
|
+
maxIdx = _i;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (maxDist <= tolerance) {
|
|
200
|
+
out.push(points[rangeLo]);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
ranges.push(maxIdx, rangeHi, rangeLo, maxIdx);
|
|
186
204
|
}
|
|
187
|
-
if (maxDist <= tolerance) {
|
|
188
|
-
out.push(points[0]);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
simplifyChain(points.slice(0, maxIdx + 1), tolerance, out);
|
|
192
|
-
simplifyChain(points.slice(maxIdx), tolerance, out);
|
|
193
205
|
}
|
|
194
206
|
|
|
195
207
|
/** Douglas–Peucker for a closed polygon: split at the point farthest from the start, simplify both halves. */
|
|
196
208
|
function simplifyClosedPolygon(points, tolerance) {
|
|
197
209
|
if (points.length < 4 || tolerance <= 0) return _toConsumableArray(points);
|
|
198
|
-
var _points$
|
|
199
|
-
sx = _points$
|
|
200
|
-
sz = _points$
|
|
210
|
+
var _points$ = _slicedToArray(points[0], 2),
|
|
211
|
+
sx = _points$[0],
|
|
212
|
+
sz = _points$[1];
|
|
201
213
|
var farIdx = 1;
|
|
202
214
|
var farDist = -1;
|
|
203
215
|
for (var i = 1; i < points.length; i++) {
|
|
@@ -208,8 +220,10 @@ function simplifyClosedPolygon(points, tolerance) {
|
|
|
208
220
|
}
|
|
209
221
|
}
|
|
210
222
|
var out = [];
|
|
211
|
-
simplifyChain(points
|
|
212
|
-
|
|
223
|
+
simplifyChain(points, 0, farIdx, tolerance, out);
|
|
224
|
+
// One wrap-around copy for the second half — the per-recursion slices are gone.
|
|
225
|
+
var wrapped = [].concat(_toConsumableArray(points.slice(farIdx)), [points[0]]);
|
|
226
|
+
simplifyChain(wrapped, 0, wrapped.length - 1, tolerance, out);
|
|
213
227
|
return out;
|
|
214
228
|
}
|
|
215
229
|
|
|
@@ -236,18 +250,18 @@ function isSimplePolygon(points) {
|
|
|
236
250
|
var _points$i2 = _slicedToArray(points[i], 2),
|
|
237
251
|
ax = _points$i2[0],
|
|
238
252
|
az = _points$i2[1];
|
|
239
|
-
var
|
|
240
|
-
bx =
|
|
241
|
-
bz =
|
|
253
|
+
var _points2 = _slicedToArray(points[(i + 1) % n], 2),
|
|
254
|
+
bx = _points2[0],
|
|
255
|
+
bz = _points2[1];
|
|
242
256
|
for (var j = i + 1; j < n; j++) {
|
|
243
257
|
// Skip the shared-endpoint neighbours (j === i+1, and the wrap pair).
|
|
244
258
|
if (j === i + 1 || i === 0 && j === n - 1) continue;
|
|
245
259
|
var _points$j = _slicedToArray(points[j], 2),
|
|
246
260
|
cx = _points$j[0],
|
|
247
261
|
cz = _points$j[1];
|
|
248
|
-
var
|
|
249
|
-
dx =
|
|
250
|
-
dz =
|
|
262
|
+
var _points3 = _slicedToArray(points[(j + 1) % n], 2),
|
|
263
|
+
dx = _points3[0],
|
|
264
|
+
dz = _points3[1];
|
|
251
265
|
if (segmentsCross(ax, az, bx, bz, cx, cz, dx, dz)) return false;
|
|
252
266
|
}
|
|
253
267
|
}
|
|
@@ -265,7 +279,7 @@ function convexHull(points) {
|
|
|
265
279
|
};
|
|
266
280
|
var build = function build(input) {
|
|
267
281
|
var chain = [];
|
|
268
|
-
var _iterator = _createForOfIteratorHelper$
|
|
282
|
+
var _iterator = _createForOfIteratorHelper$7(input),
|
|
269
283
|
_step;
|
|
270
284
|
try {
|
|
271
285
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
@@ -316,9 +330,9 @@ function ensureSimplePolygon(points) {
|
|
|
316
330
|
};
|
|
317
331
|
}
|
|
318
332
|
|
|
319
|
-
function _createForOfIteratorHelper$
|
|
320
|
-
function _unsupportedIterableToArray$
|
|
321
|
-
function _arrayLikeToArray$
|
|
333
|
+
function _createForOfIteratorHelper$6(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$6(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
334
|
+
function _unsupportedIterableToArray$6(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$6(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$6(r, a) : void 0; } }
|
|
335
|
+
function _arrayLikeToArray$6(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
322
336
|
/*
|
|
323
337
|
* Binary raster mask operations — morphology (closing, offsetting, enclosed
|
|
324
338
|
* fill) and marching-squares contouring.
|
|
@@ -327,6 +341,21 @@ function _arrayLikeToArray$5(r, a) { (null == a || a > r.length) && (a = r.lengt
|
|
|
327
341
|
* centre; `originX/originZ` and `cell` map cell indices back to world units.
|
|
328
342
|
*/
|
|
329
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Grow-only pooled trace buffers. Every operation here (and the trace's own mask) used to allocate
|
|
346
|
+
* a fresh multi-MB buffer per article change — churn a tablet pays for in GC pauses. The trace is
|
|
347
|
+
* synchronous and single-threaded, so two slots cover it: slot 0 the mask itself, slot 1 the one
|
|
348
|
+
* morphology/flood scratch alive at any time. Buffers are zeroed on acquire and retained at their
|
|
349
|
+
* high-water mark (bounded by the trace's cell budget).
|
|
350
|
+
*/
|
|
351
|
+
var pooledBuffers = [new Uint8Array(0), new Uint8Array(0)];
|
|
352
|
+
function pooledMaskBuffer(slot, size) {
|
|
353
|
+
if (pooledBuffers[slot].length < size) pooledBuffers[slot] = new Uint8Array(size);
|
|
354
|
+
var buffer = pooledBuffers[slot].subarray(0, size);
|
|
355
|
+
buffer.fill(0);
|
|
356
|
+
return buffer;
|
|
357
|
+
}
|
|
358
|
+
|
|
330
359
|
/**
|
|
331
360
|
* Morphological closing (dilate then erode) with a square kernel of the given
|
|
332
361
|
* radius — bridges seams between separately modelled parts without moving the
|
|
@@ -340,7 +369,7 @@ function _arrayLikeToArray$5(r, a) { (null == a || a > r.length) && (a = r.lengt
|
|
|
340
369
|
*/
|
|
341
370
|
function closeMask(mask, nx, nz, radius) {
|
|
342
371
|
if (radius < 1) return;
|
|
343
|
-
var scratch =
|
|
372
|
+
var scratch = pooledMaskBuffer(1, mask.length);
|
|
344
373
|
boxPassX(mask, scratch, nx, nz, radius, true);
|
|
345
374
|
boxPassZ(scratch, mask, nx, nz, radius, true);
|
|
346
375
|
boxPassX(mask, scratch, nx, nz, radius, false);
|
|
@@ -353,12 +382,15 @@ function closeMask(mask, nx, nz, radius) {
|
|
|
353
382
|
* flood could not reach. Returns how many cells were added.
|
|
354
383
|
*/
|
|
355
384
|
function fillEnclosed(mask, nx, nz) {
|
|
356
|
-
var reached =
|
|
357
|
-
|
|
385
|
+
var reached = pooledMaskBuffer(1, mask.length);
|
|
386
|
+
// A typed stack sized for the worst case: one flat allocation the GC frees without scanning,
|
|
387
|
+
// instead of a `number[]` regrowing through millions of pushes on a large background.
|
|
388
|
+
var stack = new Int32Array(mask.length);
|
|
389
|
+
var stackSize = 0;
|
|
358
390
|
var visit = function visit(i) {
|
|
359
391
|
if (mask[i] !== 0 || reached[i] !== 0) return;
|
|
360
392
|
reached[i] = 1;
|
|
361
|
-
stack
|
|
393
|
+
stack[stackSize++] = i;
|
|
362
394
|
};
|
|
363
395
|
for (var ix = 0; ix < nx; ix++) {
|
|
364
396
|
visit(ix);
|
|
@@ -368,8 +400,8 @@ function fillEnclosed(mask, nx, nz) {
|
|
|
368
400
|
visit(iz * nx);
|
|
369
401
|
visit(iz * nx + nx - 1);
|
|
370
402
|
}
|
|
371
|
-
while (
|
|
372
|
-
var i = stack
|
|
403
|
+
while (stackSize > 0) {
|
|
404
|
+
var i = stack[--stackSize];
|
|
373
405
|
var _ix = i % nx;
|
|
374
406
|
var _iz = (i - _ix) / nx;
|
|
375
407
|
if (_ix > 0) visit(i - 1);
|
|
@@ -396,7 +428,7 @@ function fillEnclosed(mask, nx, nz) {
|
|
|
396
428
|
* 45° ones.
|
|
397
429
|
*/
|
|
398
430
|
function offsetMask(mask, nx, nz, radius, dilate) {
|
|
399
|
-
var scratch =
|
|
431
|
+
var scratch = pooledMaskBuffer(1, mask.length);
|
|
400
432
|
boxPassX(mask, scratch, nx, nz, radius, dilate);
|
|
401
433
|
boxPassZ(scratch, mask, nx, nz, radius, dilate);
|
|
402
434
|
}
|
|
@@ -485,7 +517,7 @@ function marchingSquaresLoops(mask, nx, nz, originX, originZ, cell) {
|
|
|
485
517
|
// Fully inside / fully outside is the overwhelming majority of cells —
|
|
486
518
|
// returning before the segment lookup keeps the sweep near memory speed.
|
|
487
519
|
if (c === 0 || c === 15) continue;
|
|
488
|
-
var _iterator = _createForOfIteratorHelper$
|
|
520
|
+
var _iterator = _createForOfIteratorHelper$6(MS_SEGMENTS[c]),
|
|
489
521
|
_step;
|
|
490
522
|
try {
|
|
491
523
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
@@ -503,7 +535,7 @@ function marchingSquaresLoops(mask, nx, nz, originX, originZ, cell) {
|
|
|
503
535
|
}
|
|
504
536
|
var visited = new Set();
|
|
505
537
|
var loops = [];
|
|
506
|
-
var _iterator2 = _createForOfIteratorHelper$
|
|
538
|
+
var _iterator2 = _createForOfIteratorHelper$6(adjacency.keys()),
|
|
507
539
|
_step2;
|
|
508
540
|
try {
|
|
509
541
|
var _loop = function _loop() {
|
|
@@ -540,13 +572,20 @@ var EPS$1 = 1e-9;
|
|
|
540
572
|
|
|
541
573
|
/**
|
|
542
574
|
* Ceiling on the raster's cell count. The extent comes from article geometry, so a mis-scaled
|
|
543
|
-
* model (metres authored as millimetres) can ask for a mask no browser can hold
|
|
544
|
-
*
|
|
545
|
-
* is a 20 m x 20 m article at the default 5 mm cell, far beyond anything real, and refusing is
|
|
575
|
+
* model (metres authored as millimetres) can ask for a mask no browser can hold. 16M cells is a
|
|
576
|
+
* 20 m x 20 m article at the default 5 mm cell, far beyond anything real, and refusing is
|
|
546
577
|
* graceful: the caller falls back to the measured rect.
|
|
547
578
|
*/
|
|
548
579
|
var MAX_MASK_CELLS = 16000000;
|
|
549
580
|
|
|
581
|
+
/**
|
|
582
|
+
* Cell budget the raster COARSENS toward instead of refusing: above it, the cell size grows just
|
|
583
|
+
* enough to fit (a villa-cliff-sized authored pool at 5 mm is ~2.9M cells and stays untouched).
|
|
584
|
+
* Bounds the pooled mask buffers and the sweep time to what a tablet survives, at the price of a
|
|
585
|
+
* coarser outline for outsized articles — still their shape, not the rectangular fallback.
|
|
586
|
+
*/
|
|
587
|
+
var TARGET_MASK_CELLS = 4000000;
|
|
588
|
+
|
|
550
589
|
/** What a trace did internally — see {@link TraceFootprintOptions.diagnostics}. */
|
|
551
590
|
|
|
552
591
|
/**
|
|
@@ -560,16 +599,9 @@ var MAX_MASK_CELLS = 16000000;
|
|
|
560
599
|
function traceFootprintFromTriangles(triangleXZ) {
|
|
561
600
|
var _options$cellSize, _options$simplifyTole, _options$closeGap, _options$offset;
|
|
562
601
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
563
|
-
var
|
|
564
|
-
var tolerance = (_options$simplifyTole = options.simplifyTolerance) !== null && _options$simplifyTole !== void 0 ? _options$simplifyTole : cell;
|
|
565
|
-
// Closing radius in cells, so the sealed gap stays ~`closeGap` at any resolution.
|
|
566
|
-
var closeGap = (_options$closeGap = options.closeGap) !== null && _options$closeGap !== void 0 ? _options$closeGap : 0.02;
|
|
567
|
-
var closeRadius = closeGap <= 0 ? 0 : Math.max(1, Math.round(closeGap / (cell * 2)));
|
|
568
|
-
var offset = (_options$offset = options.offset) !== null && _options$offset !== void 0 ? _options$offset : 0;
|
|
569
|
-
var offsetRadius = Math.round(Math.abs(offset) / cell);
|
|
570
|
-
var grow = offset > 0;
|
|
602
|
+
var requestedCell = (_options$cellSize = options.cellSize) !== null && _options$cellSize !== void 0 ? _options$cellSize : 0.005;
|
|
571
603
|
var triCount = Math.floor(triangleXZ.length / 6);
|
|
572
|
-
if (triCount < 1 ||
|
|
604
|
+
if (triCount < 1 || requestedCell <= 0) return [];
|
|
573
605
|
var minX = Infinity;
|
|
574
606
|
var maxX = -Infinity;
|
|
575
607
|
var minZ = Infinity;
|
|
@@ -582,7 +614,19 @@ function traceFootprintFromTriangles(triangleXZ) {
|
|
|
582
614
|
if (z < minZ) minZ = z;
|
|
583
615
|
if (z > maxZ) maxZ = z;
|
|
584
616
|
}
|
|
585
|
-
if (!Number.isFinite(minX) || maxX - minX <
|
|
617
|
+
if (!Number.isFinite(minX) || maxX - minX < requestedCell || maxZ - minZ < requestedCell) return [];
|
|
618
|
+
|
|
619
|
+
// Coarsen toward the cell budget: everything below derives from the FINAL cell (radii,
|
|
620
|
+
// tolerance, edge-sampling threshold), so the budget check runs before any of them.
|
|
621
|
+
var rawCells = (Math.ceil((maxX - minX) / requestedCell) + 1) * (Math.ceil((maxZ - minZ) / requestedCell) + 1);
|
|
622
|
+
var cell = rawCells > TARGET_MASK_CELLS ? requestedCell * Math.sqrt(rawCells / TARGET_MASK_CELLS) : requestedCell;
|
|
623
|
+
var tolerance = (_options$simplifyTole = options.simplifyTolerance) !== null && _options$simplifyTole !== void 0 ? _options$simplifyTole : cell;
|
|
624
|
+
// Closing radius in cells, so the sealed gap stays ~`closeGap` at any resolution.
|
|
625
|
+
var closeGap = (_options$closeGap = options.closeGap) !== null && _options$closeGap !== void 0 ? _options$closeGap : 0.02;
|
|
626
|
+
var closeRadius = closeGap <= 0 ? 0 : Math.max(1, Math.round(closeGap / (cell * 2)));
|
|
627
|
+
var offset = (_options$offset = options.offset) !== null && _options$offset !== void 0 ? _options$offset : 0;
|
|
628
|
+
var offsetRadius = Math.round(Math.abs(offset) / cell);
|
|
629
|
+
var grow = offset > 0;
|
|
586
630
|
|
|
587
631
|
// Empty border of `closeRadius + 1` cells per side: the closing's dilation
|
|
588
632
|
// must have room to spread without the erosion then eating the shape's
|
|
@@ -593,7 +637,7 @@ function traceFootprintFromTriangles(triangleXZ) {
|
|
|
593
637
|
var nx = Math.ceil((maxX - minX) / cell) + 2 * border + 1;
|
|
594
638
|
var nz = Math.ceil((maxZ - minZ) / cell) + 2 * border + 1;
|
|
595
639
|
if (nx * nz > MAX_MASK_CELLS) return [];
|
|
596
|
-
var mask =
|
|
640
|
+
var mask = pooledMaskBuffer(0, nx * nz);
|
|
597
641
|
var cellOf = function cellOf(v, origin, n) {
|
|
598
642
|
return Math.min(n - border - 1, Math.max(border, Math.floor((v - origin) / cell)));
|
|
599
643
|
};
|
|
@@ -707,9 +751,9 @@ function traceFootprintFromTriangles(triangleXZ) {
|
|
|
707
751
|
return simplified.length >= 3 ? simplified : [];
|
|
708
752
|
}
|
|
709
753
|
|
|
710
|
-
function _createForOfIteratorHelper$
|
|
711
|
-
function _unsupportedIterableToArray$
|
|
712
|
-
function _arrayLikeToArray$
|
|
754
|
+
function _createForOfIteratorHelper$5(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$5(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
755
|
+
function _unsupportedIterableToArray$5(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$5(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$5(r, a) : void 0; } }
|
|
756
|
+
function _arrayLikeToArray$5(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
713
757
|
|
|
714
758
|
/** The subset of a deckCutout article rule the matcher needs. */
|
|
715
759
|
|
|
@@ -720,7 +764,7 @@ function _arrayLikeToArray$4(r, a) { (null == a || a > r.length) && (a = r.lengt
|
|
|
720
764
|
* per-element codexes.
|
|
721
765
|
*/
|
|
722
766
|
function matchArticleRule(rules, articleCodex) {
|
|
723
|
-
var _iterator = _createForOfIteratorHelper$
|
|
767
|
+
var _iterator = _createForOfIteratorHelper$5(rules),
|
|
724
768
|
_step;
|
|
725
769
|
try {
|
|
726
770
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
@@ -745,9 +789,9 @@ function matchArticleRule(rules, articleCodex) {
|
|
|
745
789
|
return null;
|
|
746
790
|
}
|
|
747
791
|
|
|
748
|
-
function _createForOfIteratorHelper$
|
|
749
|
-
function _unsupportedIterableToArray$
|
|
750
|
-
function _arrayLikeToArray$
|
|
792
|
+
function _createForOfIteratorHelper$4(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$4(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
793
|
+
function _unsupportedIterableToArray$4(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$4(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$4(r, a) : void 0; } }
|
|
794
|
+
function _arrayLikeToArray$4(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
751
795
|
|
|
752
796
|
/**
|
|
753
797
|
* Raster cell (m) for the geometry-derived footprint. 5 mm follows cast-in
|
|
@@ -806,7 +850,7 @@ function pickArticleRule(rules, codexesByArea) {
|
|
|
806
850
|
var _codexesByArea$;
|
|
807
851
|
var primaryCodex = (_codexesByArea$ = codexesByArea[0]) === null || _codexesByArea$ === void 0 ? void 0 : _codexesByArea$.codex;
|
|
808
852
|
var rule = matchArticleRule(rules, undefined);
|
|
809
|
-
var _iterator = _createForOfIteratorHelper$
|
|
853
|
+
var _iterator = _createForOfIteratorHelper$4(codexesByArea),
|
|
810
854
|
_step;
|
|
811
855
|
try {
|
|
812
856
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
@@ -837,10 +881,10 @@ function pickArticleRule(rules, codexesByArea) {
|
|
|
837
881
|
* meshes change; anchor moves are pure translations and reuse the cache.
|
|
838
882
|
* Returns the outline in CURRENT floor-local coordinates.
|
|
839
883
|
*/
|
|
840
|
-
function traceArticleFootprint(elements, floorLocal, rect, minLocalY, offset, diagnostics, cache) {
|
|
884
|
+
function traceArticleFootprint(elements, floorLocal, rect, minLocalY, offset, diagnostics, cache, pendingLiftY) {
|
|
841
885
|
var meshes = [];
|
|
842
886
|
var sigParts = [];
|
|
843
|
-
var _iterator2 = _createForOfIteratorHelper$
|
|
887
|
+
var _iterator2 = _createForOfIteratorHelper$4(elements),
|
|
844
888
|
_step2;
|
|
845
889
|
try {
|
|
846
890
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
@@ -863,52 +907,63 @@ function traceArticleFootprint(elements, floorLocal, rect, minLocalY, offset, di
|
|
|
863
907
|
var sizeX = rect.maxX - rect.minX;
|
|
864
908
|
var sizeY = rect.maxY - rect.minY;
|
|
865
909
|
var sizeZ = rect.maxZ - rect.minZ;
|
|
866
|
-
//
|
|
867
|
-
//
|
|
868
|
-
//
|
|
869
|
-
|
|
870
|
-
var signature = "".concat(minLocalY.toFixed(3), "|").concat(rect.maxY.toFixed(3), "|").concat(offset.toFixed(3), "|").concat(sizeX.toFixed(3), "x").concat(sizeY.toFixed(3), "x").concat(sizeZ.toFixed(3), "|").concat(sigParts.join(','));
|
|
910
|
+
// Vertical position decides which triangles clear the fixed slice plane, so the top belongs in
|
|
911
|
+
// the signature. Signed with the POST-lift top: the pre-lift measure then produces the same
|
|
912
|
+
// signature as the post-lift one and the second measure hits the cache instead of re-tracing.
|
|
913
|
+
var signature = "".concat(minLocalY.toFixed(3), "|").concat((rect.maxY + pendingLiftY).toFixed(3), "|").concat(offset.toFixed(3), "|").concat(sizeX.toFixed(3), "x").concat(sizeY.toFixed(3), "x").concat(sizeZ.toFixed(3), "|").concat(sigParts.join(','));
|
|
871
914
|
if (!cache.current || cache.current.signature !== signature) {
|
|
872
915
|
var started = performance.now();
|
|
873
|
-
var xz = [];
|
|
874
|
-
var _triCount = 0;
|
|
875
916
|
var _vertexCount = 0;
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
917
|
+
// Transform every vertex once per mesh; triangles then index into the flat array. Kept per
|
|
918
|
+
// mesh so the count pass below can re-scan triangles without re-transforming.
|
|
919
|
+
var locals = meshes.map(function (mesh) {
|
|
920
|
+
var pos = mesh.geometry.getAttribute('position');
|
|
921
|
+
_vertexCount += pos.count;
|
|
922
|
+
_meshToFloor.multiplyMatrices(floorLocal, mesh.matrixWorld);
|
|
923
|
+
var local = new Float32Array(pos.count * 3);
|
|
924
|
+
for (var i = 0; i < pos.count; i++) {
|
|
925
|
+
_vertex$1.set(pos.getX(i), pos.getY(i), pos.getZ(i)).applyMatrix4(_meshToFloor);
|
|
926
|
+
local[i * 3] = _vertex$1.x;
|
|
927
|
+
// Slice at the post-lift height (see signature); a Y shift cannot change the XZ outline.
|
|
928
|
+
local[i * 3 + 1] = _vertex$1.y + pendingLiftY;
|
|
929
|
+
local[i * 3 + 2] = _vertex$1.z;
|
|
930
|
+
}
|
|
931
|
+
return local;
|
|
932
|
+
});
|
|
933
|
+
// Two passes over cheap index reads: count the slice triangles, then fill ONE exactly-sized
|
|
934
|
+
// typed array — a `number[]` grown by pushes held hundreds of thousands of boxed slots on a
|
|
935
|
+
// dense article and was re-copied on every capacity step.
|
|
936
|
+
var forEachSliceTriangle = function forEachSliceTriangle(emit) {
|
|
937
|
+
var count = 0;
|
|
938
|
+
for (var m = 0; m < meshes.length; m++) {
|
|
939
|
+
var geometry = meshes[m].geometry;
|
|
882
940
|
var pos = geometry.getAttribute('position');
|
|
883
|
-
|
|
884
|
-
_meshToFloor.multiplyMatrices(floorLocal, mesh.matrixWorld);
|
|
885
|
-
// Transform every vertex once; triangles then index into the flat array.
|
|
886
|
-
var local = new Float32Array(pos.count * 3);
|
|
887
|
-
for (var i = 0; i < pos.count; i++) {
|
|
888
|
-
_vertex$1.set(pos.getX(i), pos.getY(i), pos.getZ(i)).applyMatrix4(_meshToFloor);
|
|
889
|
-
local[i * 3] = _vertex$1.x;
|
|
890
|
-
local[i * 3 + 1] = _vertex$1.y;
|
|
891
|
-
local[i * 3 + 2] = _vertex$1.z;
|
|
892
|
-
}
|
|
941
|
+
var local = locals[m];
|
|
893
942
|
var index = geometry.index;
|
|
894
943
|
var triTotal = index ? Math.floor(index.count / 3) : Math.floor(pos.count / 3);
|
|
895
944
|
for (var t = 0; t < triTotal; t++) {
|
|
896
945
|
var a = index ? index.getX(t * 3) : t * 3;
|
|
897
946
|
var b = index ? index.getX(t * 3 + 1) : t * 3 + 1;
|
|
898
947
|
var c = index ? index.getX(t * 3 + 2) : t * 3 + 2;
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
if (ya < minLocalY && yb < minLocalY && yc < minLocalY) continue;
|
|
903
|
-
xz.push(local[a * 3], local[a * 3 + 2], local[b * 3], local[b * 3 + 2], local[c * 3], local[c * 3 + 2]);
|
|
904
|
-
_triCount += 1;
|
|
948
|
+
if (local[a * 3 + 1] < minLocalY && local[b * 3 + 1] < minLocalY && local[c * 3 + 1] < minLocalY) continue;
|
|
949
|
+
count += 1;
|
|
950
|
+
if (emit) emit(local[a * 3], local[a * 3 + 2], local[b * 3], local[b * 3 + 2], local[c * 3], local[c * 3 + 2]);
|
|
905
951
|
}
|
|
906
952
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
953
|
+
return count;
|
|
954
|
+
};
|
|
955
|
+
var _triCount = forEachSliceTriangle(null);
|
|
956
|
+
var xz = new Float32Array(_triCount * 6);
|
|
957
|
+
var write = 0;
|
|
958
|
+
forEachSliceTriangle(function (ax, az, bx, bz, cx, cz) {
|
|
959
|
+
xz[write] = ax;
|
|
960
|
+
xz[write + 1] = az;
|
|
961
|
+
xz[write + 2] = bx;
|
|
962
|
+
xz[write + 3] = bz;
|
|
963
|
+
xz[write + 4] = cx;
|
|
964
|
+
xz[write + 5] = cz;
|
|
965
|
+
write += 6;
|
|
966
|
+
});
|
|
912
967
|
var traced = traceFootprintFromTriangles(xz, {
|
|
913
968
|
cellSize: GEOMETRY_FOOTPRINT_CELL,
|
|
914
969
|
offset: offset,
|
|
@@ -959,6 +1014,7 @@ function traceArticleFootprint(elements, floorLocal, rect, minLocalY, offset, di
|
|
|
959
1014
|
*/
|
|
960
1015
|
function deriveArticleFootprint(measurement, rule, margin, cache) {
|
|
961
1016
|
var _result$points$length, _result$points;
|
|
1017
|
+
var pendingLiftY = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
|
|
962
1018
|
var result = {
|
|
963
1019
|
points: null,
|
|
964
1020
|
rim: null,
|
|
@@ -975,19 +1031,19 @@ function deriveArticleFootprint(measurement, rule, margin, cache) {
|
|
|
975
1031
|
elementObjects = measurement.elementObjects;
|
|
976
1032
|
var rawSizeX = rect.maxX - rect.minX;
|
|
977
1033
|
var rawSizeZ = rect.maxZ - rect.minZ;
|
|
978
|
-
var traced = traceArticleFootprint(topLevelElements(elementObjects), floorLocal, rect, floorTopY - rule.footprintSliceDepth, margin, result.trace, cache);
|
|
1034
|
+
var traced = traceArticleFootprint(topLevelElements(elementObjects), floorLocal, rect, floorTopY - rule.footprintSliceDepth, margin, result.trace, cache, pendingLiftY);
|
|
979
1035
|
var minX = Infinity;
|
|
980
1036
|
var maxX = -Infinity;
|
|
981
1037
|
var minZ = Infinity;
|
|
982
1038
|
var maxZ = -Infinity;
|
|
983
1039
|
if (traced && traced.points.length >= 3) {
|
|
984
|
-
var
|
|
985
|
-
|
|
1040
|
+
var _iterator3 = _createForOfIteratorHelper$4(traced.points),
|
|
1041
|
+
_step3;
|
|
986
1042
|
try {
|
|
987
|
-
for (
|
|
988
|
-
var
|
|
989
|
-
x =
|
|
990
|
-
z =
|
|
1043
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
1044
|
+
var _step3$value = _slicedToArray(_step3.value, 2),
|
|
1045
|
+
x = _step3$value[0],
|
|
1046
|
+
z = _step3$value[1];
|
|
991
1047
|
if (x < minX) minX = x;
|
|
992
1048
|
if (x > maxX) maxX = x;
|
|
993
1049
|
if (z < minZ) minZ = z;
|
|
@@ -997,9 +1053,9 @@ function deriveArticleFootprint(measurement, rule, margin, cache) {
|
|
|
997
1053
|
// what the steps below need is the article's RIM extent (it sizes the
|
|
998
1054
|
// water volume), not the collar's inner boundary.
|
|
999
1055
|
} catch (err) {
|
|
1000
|
-
|
|
1056
|
+
_iterator3.e(err);
|
|
1001
1057
|
} finally {
|
|
1002
|
-
|
|
1058
|
+
_iterator3.f();
|
|
1003
1059
|
}
|
|
1004
1060
|
minX += margin;
|
|
1005
1061
|
maxX -= margin;
|
|
@@ -1042,9 +1098,9 @@ function deriveArticleFootprint(measurement, rule, margin, cache) {
|
|
|
1042
1098
|
return result;
|
|
1043
1099
|
}
|
|
1044
1100
|
|
|
1045
|
-
function _createForOfIteratorHelper$
|
|
1046
|
-
function _unsupportedIterableToArray$
|
|
1047
|
-
function _arrayLikeToArray$
|
|
1101
|
+
function _createForOfIteratorHelper$3(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$3(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
1102
|
+
function _unsupportedIterableToArray$3(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$3(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$3(r, a) : void 0; } }
|
|
1103
|
+
function _arrayLikeToArray$3(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
1048
1104
|
|
|
1049
1105
|
/** Below this world delta (m) the element anchor correction is considered settled. */
|
|
1050
1106
|
var ANCHOR_EPSILON = 1e-3;
|
|
@@ -1098,7 +1154,7 @@ function deriveElementAnchor(_ref) {
|
|
|
1098
1154
|
var topLevel = topLevelElements(elementObjects);
|
|
1099
1155
|
if (topLevel.length === 0) return null;
|
|
1100
1156
|
var offsets = {};
|
|
1101
|
-
var _iterator = _createForOfIteratorHelper$
|
|
1157
|
+
var _iterator = _createForOfIteratorHelper$3(topLevel),
|
|
1102
1158
|
_step;
|
|
1103
1159
|
try {
|
|
1104
1160
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
@@ -1167,10 +1223,14 @@ function deriveWaterVolume(_ref) {
|
|
|
1167
1223
|
};
|
|
1168
1224
|
}
|
|
1169
1225
|
|
|
1226
|
+
function _createForOfIteratorHelper$2(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$2(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
1227
|
+
function _unsupportedIterableToArray$2(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$2(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$2(r, a) : void 0; } }
|
|
1228
|
+
function _arrayLikeToArray$2(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
1170
1229
|
/**
|
|
1171
1230
|
* One line describing the whole cutout pipeline, plus the `key` it changes with:
|
|
1172
1231
|
* the caller logs only when the key moves, so the line appears once per codex /
|
|
1173
1232
|
* rule / outline state (bounds coarse-rounded to cm) rather than every measure.
|
|
1233
|
+
* `message` is lazy — composed only when the key moved.
|
|
1174
1234
|
*/
|
|
1175
1235
|
function measureLog(_ref) {
|
|
1176
1236
|
var _rule$match, _points$length, _fpBounds$map$join;
|
|
@@ -1182,38 +1242,59 @@ function measureLog(_ref) {
|
|
|
1182
1242
|
var rect = measurement.rect,
|
|
1183
1243
|
floorTopY = measurement.floorTopY;
|
|
1184
1244
|
var points = footprint.points;
|
|
1185
|
-
var
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1245
|
+
var fpMinX = Infinity;
|
|
1246
|
+
var fpMaxX = -Infinity;
|
|
1247
|
+
var fpMinZ = Infinity;
|
|
1248
|
+
var fpMaxZ = -Infinity;
|
|
1249
|
+
if (points) {
|
|
1250
|
+
var _iterator = _createForOfIteratorHelper$2(points),
|
|
1251
|
+
_step;
|
|
1252
|
+
try {
|
|
1253
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1254
|
+
var _step$value = _slicedToArray(_step.value, 2),
|
|
1255
|
+
x = _step$value[0],
|
|
1256
|
+
z = _step$value[1];
|
|
1257
|
+
if (x < fpMinX) fpMinX = x;
|
|
1258
|
+
if (x > fpMaxX) fpMaxX = x;
|
|
1259
|
+
if (z < fpMinZ) fpMinZ = z;
|
|
1260
|
+
if (z > fpMaxZ) fpMaxZ = z;
|
|
1261
|
+
}
|
|
1262
|
+
} catch (err) {
|
|
1263
|
+
_iterator.e(err);
|
|
1264
|
+
} finally {
|
|
1265
|
+
_iterator.f();
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
var fpBounds = points ? [fpMinX, fpMaxX, fpMinZ, fpMaxZ] : null;
|
|
1191
1269
|
var key = "".concat(primaryCodex !== null && primaryCodex !== void 0 ? primaryCodex : '', "|").concat((_rule$match = rule === null || rule === void 0 ? void 0 : rule.match) !== null && _rule$match !== void 0 ? _rule$match : '', "|").concat(footprint.sampledCount, "|").concat((_points$length = points === null || points === void 0 ? void 0 : points.length) !== null && _points$length !== void 0 ? _points$length : 0, "|").concat((_fpBounds$map$join = fpBounds === null || fpBounds === void 0 ? void 0 : fpBounds.map(function (v) {
|
|
1192
1270
|
return v.toFixed(2);
|
|
1193
1271
|
}).join(',')) !== null && _fpBounds$map$join !== void 0 ? _fpBounds$map$join : '');
|
|
1194
|
-
var
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1272
|
+
var message = function message() {
|
|
1273
|
+
var rawSizeX = rect.maxX - rect.minX;
|
|
1274
|
+
var rawSizeZ = rect.maxZ - rect.minZ;
|
|
1275
|
+
// Where the slice plane sits relative to the article. The plane is anchored to
|
|
1276
|
+
// the DECK top, so an article whose rim doesn't reach that high contributes
|
|
1277
|
+
// nothing but its topmost stray detail.
|
|
1278
|
+
var sliceInfo = rule && rule.footprintFromGeometry ? " | Y: deck top ".concat(floorTopY.toFixed(2), ", article [").concat(rect.minY.toFixed(2), ", ").concat(rect.maxY.toFixed(2), "], slice keeps \u2265 ").concat((floorTopY - rule.footprintSliceDepth).toFixed(2)) : '';
|
|
1279
|
+
var fpInfo;
|
|
1280
|
+
if (footprint.source === '') {
|
|
1281
|
+
fpInfo = ' | NO outline rule matched this codex → NO COLLAR, the authored hole stays fully open';
|
|
1282
|
+
} else if (fpBounds && points) {
|
|
1283
|
+
// Room left between the outline and each authored hole edge. Negative on any
|
|
1284
|
+
// side = the article is bigger than the hole it sits in; the collar clamps
|
|
1285
|
+
// the outline to the hole and degrades toward a solid slab.
|
|
1286
|
+
var slack = [fpBounds[0] - (hole.centerX - hole.halfExtentX), hole.centerX + hole.halfExtentX - fpBounds[1], fpBounds[2] - (hole.centerZ - hole.halfExtentZ), hole.centerZ + hole.halfExtentZ - fpBounds[3]].map(function (v) {
|
|
1287
|
+
return v.toFixed(2);
|
|
1288
|
+
});
|
|
1289
|
+
fpInfo = " | measured ".concat(rawSizeX.toFixed(2), "\xD7").concat(rawSizeZ.toFixed(2)) + (footprint.tracedBounds === '' ? '' : " | traced ".concat(footprint.sampledCount, " pts ").concat(footprint.tracedBounds)) + " | outline ".concat(points.length, " pts X [").concat(fpBounds[0].toFixed(2), ", ").concat(fpBounds[1].toFixed(2), "] Z [").concat(fpBounds[2].toFixed(2), ", ").concat(fpBounds[3].toFixed(2), "]") + " | hole X [".concat((hole.centerX - hole.halfExtentX).toFixed(2), ", ").concat((hole.centerX + hole.halfExtentX).toFixed(2), "] Z [").concat((hole.centerZ - hole.halfExtentZ).toFixed(2), ", ").concat((hole.centerZ + hole.halfExtentZ).toFixed(2), "]") + " | slack X ".concat(slack[0], "/").concat(slack[1], " Z ").concat(slack[2], "/").concat(slack[3]) + " | ".concat(footprint.source).concat(footprint.repairNote) + (footprint.trace.loops > 0 ? " | trace: ".concat(footprint.trace.filledCells, " cells (").concat(footprint.trace.enclosedFilled, " filled in), ").concat(footprint.trace.loops, " loop(s), kept ").concat((footprint.trace.chosenAreaShare * 100).toFixed(0), "% of contour area, ").concat(footprint.trace.pointsBeforeSimplify, " \u2192 ").concat(footprint.trace.pointsAfterSimplify, " pts") : '');
|
|
1290
|
+
} else {
|
|
1291
|
+
fpInfo = " | ".concat(footprint.source, " produced NO usable outline (").concat(footprint.sampledCount, " pts)").concat(footprint.repairNote, " \u2192 NO COLLAR, the authored hole stays fully open");
|
|
1292
|
+
}
|
|
1293
|
+
return "[DeckCutout] article codex: ".concat(primaryCodex !== null && primaryCodex !== void 0 ? primaryCodex : '(unknown)', " \u2192 rule: ").concat(rule ? "'".concat(rule.match, "'") : '(none — articleSync globals)').concat(sliceInfo).concat(fpInfo);
|
|
1294
|
+
};
|
|
1214
1295
|
return {
|
|
1215
1296
|
key: key,
|
|
1216
|
-
message:
|
|
1297
|
+
message: message
|
|
1217
1298
|
};
|
|
1218
1299
|
}
|
|
1219
1300
|
|
|
@@ -1259,12 +1340,9 @@ function DeckCutoutArticleSync() {
|
|
|
1259
1340
|
var scene = useThree(function (s) {
|
|
1260
1341
|
return s.scene;
|
|
1261
1342
|
});
|
|
1262
|
-
var
|
|
1263
|
-
return
|
|
1343
|
+
var deform = useStableEnvSlice(function (env) {
|
|
1344
|
+
return env.scene.deckCutout;
|
|
1264
1345
|
});
|
|
1265
|
-
var deform = useMemo(function () {
|
|
1266
|
-
return JSON.parse(deckCutoutJson);
|
|
1267
|
-
}, [deckCutoutJson]);
|
|
1268
1346
|
var setWaterOverride = useRTVStore(function (s) {
|
|
1269
1347
|
return s.setWaterVolumeOverride;
|
|
1270
1348
|
});
|
|
@@ -1383,7 +1461,12 @@ function DeckCutoutArticleSync() {
|
|
|
1383
1461
|
var _pickArticleRule = pickArticleRule(deform.articleRules, measured.codexesByArea),
|
|
1384
1462
|
rule = _pickArticleRule.rule,
|
|
1385
1463
|
primaryCodex = _pickArticleRule.primaryCodex;
|
|
1386
|
-
|
|
1464
|
+
// The anchor's lift changes what clears the slice plane and used to force a second full trace
|
|
1465
|
+
// per article load. It is fully determined here (same formula as `deriveElementAnchor`), so
|
|
1466
|
+
// the first trace evaluates the article at its post-lift height directly.
|
|
1467
|
+
var anchorCfg = deform.elementAnchor;
|
|
1468
|
+
var pendingLiftY = anchorActive ? (anchorCfg.alignTopToDeck ? measured.floorTopY - measured.rect.maxY : 0) + anchorCfg.offsetY : 0;
|
|
1469
|
+
var traced = deriveArticleFootprint(measured, rule, deform.articleSync.margin, geometryCacheRef, pendingLiftY);
|
|
1387
1470
|
var rect = traced.rim ? _objectSpread(_objectSpread({}, measured.rect), traced.rim) : measured.rect;
|
|
1388
1471
|
var log = measureLog({
|
|
1389
1472
|
measurement: measured,
|
|
@@ -1394,7 +1477,7 @@ function DeckCutoutArticleSync() {
|
|
|
1394
1477
|
});
|
|
1395
1478
|
if (matchLogRef.current !== log.key) {
|
|
1396
1479
|
matchLogRef.current = log.key;
|
|
1397
|
-
LOG$2.debug(log.message);
|
|
1480
|
+
LOG$2.debug(log.message());
|
|
1398
1481
|
}
|
|
1399
1482
|
|
|
1400
1483
|
// The deck is never reshaped: the collar fills everything between its
|
|
@@ -2167,8 +2250,10 @@ function buildCollarGeometry(_ref) {
|
|
|
2167
2250
|
uvs[_i * 2] = (_x * cos - _z * sin) / scale;
|
|
2168
2251
|
uvs[_i * 2 + 1] = (_x * sin + _z * cos) / scale;
|
|
2169
2252
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2253
|
+
// ONE attribute on both slots: two attribute objects over the same array upload two GL buffers.
|
|
2254
|
+
var uvAttribute = new BufferAttribute(uvs, 2);
|
|
2255
|
+
geo.setAttribute('uv', uvAttribute);
|
|
2256
|
+
geo.setAttribute('uv1', uvAttribute);
|
|
2172
2257
|
} else if (deck.triangles) {
|
|
2173
2258
|
// Continue the deck's own mapping. One fitted mapping when the deck's
|
|
2174
2259
|
// unwrap is a single plane — it cannot shear, whereas deciding per vertex
|
|
@@ -2196,8 +2281,10 @@ function buildCollarGeometry(_ref) {
|
|
|
2196
2281
|
_uvs[_i2 * 2] = sampled[0];
|
|
2197
2282
|
_uvs[_i2 * 2 + 1] = sampled[1];
|
|
2198
2283
|
}
|
|
2199
|
-
|
|
2200
|
-
|
|
2284
|
+
// See above — one attribute, one GL buffer, both slots.
|
|
2285
|
+
var _uvAttribute = new BufferAttribute(_uvs, 2);
|
|
2286
|
+
geo.setAttribute('uv', _uvAttribute);
|
|
2287
|
+
geo.setAttribute('uv1', _uvAttribute);
|
|
2201
2288
|
}
|
|
2202
2289
|
return {
|
|
2203
2290
|
geometry: geo,
|
|
@@ -2319,12 +2406,9 @@ function DeckCutoutCollar() {
|
|
|
2319
2406
|
var scene = useThree(function (s) {
|
|
2320
2407
|
return s.scene;
|
|
2321
2408
|
});
|
|
2322
|
-
var
|
|
2323
|
-
return
|
|
2409
|
+
var deform = useStableEnvSlice(function (env) {
|
|
2410
|
+
return env.scene.deckCutout;
|
|
2324
2411
|
});
|
|
2325
|
-
var deform = useMemo(function () {
|
|
2326
|
-
return JSON.parse(deckCutoutJson);
|
|
2327
|
-
}, [deckCutoutJson]);
|
|
2328
2412
|
var footprint = useRTVStore(function (s) {
|
|
2329
2413
|
return s.deckCutoutFootprintOverride;
|
|
2330
2414
|
});
|