@ifc-lite/renderer 1.38.1 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/deviation/deviation-pipeline.d.ts +8 -0
- package/dist/deviation/deviation-pipeline.d.ts.map +1 -1
- package/dist/deviation/deviation-pipeline.js +20 -9
- package/dist/deviation/deviation-pipeline.js.map +1 -1
- package/dist/deviation/deviation-shader.wgsl.d.ts +1 -1
- package/dist/deviation/deviation-shader.wgsl.d.ts.map +1 -1
- package/dist/deviation/deviation-shader.wgsl.js +11 -3
- package/dist/deviation/deviation-shader.wgsl.js.map +1 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +78 -3
- package/dist/index.js.map +1 -1
- package/dist/picker.d.ts +9 -0
- package/dist/picker.d.ts.map +1 -1
- package/dist/picker.js +84 -2
- package/dist/picker.js.map +1 -1
- package/dist/pointcloud/point-cloud-node.d.ts +46 -0
- package/dist/pointcloud/point-cloud-node.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-node.js +71 -0
- package/dist/pointcloud/point-cloud-node.js.map +1 -1
- package/dist/pointcloud/point-cloud-ray-transform.d.ts +66 -0
- package/dist/pointcloud/point-cloud-ray-transform.d.ts.map +1 -0
- package/dist/pointcloud/point-cloud-ray-transform.js +172 -0
- package/dist/pointcloud/point-cloud-ray-transform.js.map +1 -0
- package/dist/pointcloud/point-cloud-renderer.d.ts +39 -6
- package/dist/pointcloud/point-cloud-renderer.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-renderer.js +53 -17
- package/dist/pointcloud/point-cloud-renderer.js.map +1 -1
- package/dist/pointcloud/point-cloud-spatial-index.d.ts +188 -0
- package/dist/pointcloud/point-cloud-spatial-index.d.ts.map +1 -0
- package/dist/pointcloud/point-cloud-spatial-index.js +536 -0
- package/dist/pointcloud/point-cloud-spatial-index.js.map +1 -0
- package/dist/pointcloud/point-cloud-uniforms.d.ts +14 -2
- package/dist/pointcloud/point-cloud-uniforms.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-uniforms.js +49 -8
- package/dist/pointcloud/point-cloud-uniforms.js.map +1 -1
- package/dist/pointcloud/point-pipeline.d.ts +3 -2
- package/dist/pointcloud/point-pipeline.d.ts.map +1 -1
- package/dist/pointcloud/point-pipeline.js +8 -5
- package/dist/pointcloud/point-pipeline.js.map +1 -1
- package/dist/pointcloud/point-shader.wgsl.d.ts +1 -1
- package/dist/pointcloud/point-shader.wgsl.d.ts.map +1 -1
- package/dist/pointcloud/point-shader.wgsl.js +20 -17
- package/dist/pointcloud/point-shader.wgsl.js.map +1 -1
- package/dist/raycast-engine.d.ts +8 -0
- package/dist/raycast-engine.d.ts.map +1 -1
- package/dist/raycast-engine.js +68 -23
- package/dist/raycast-engine.js.map +1 -1
- package/dist/raycast-point-cloud-query.d.ts +122 -0
- package/dist/raycast-point-cloud-query.d.ts.map +1 -0
- package/dist/raycast-point-cloud-query.js +145 -0
- package/dist/raycast-point-cloud-query.js.map +1 -0
- package/dist/scene.d.ts +18 -0
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +166 -63
- package/dist/scene.js.map +1 -1
- package/dist/snap-detector.d.ts +12 -1
- package/dist/snap-detector.d.ts.map +1 -1
- package/dist/snap-detector.js +9 -1
- package/dist/snap-detector.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Default cell edge, metres. Coarse relative to typical scan spacing
|
|
6
|
+
* (millimetres to a few centimetres) so a query rarely visits more than
|
|
7
|
+
* a handful of cells, while small enough that a query near building
|
|
8
|
+
* scale doesn't degenerate into "search almost everything".
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_POINTCLOUD_INDEX_CELL_SIZE = 0.5;
|
|
11
|
+
/**
|
|
12
|
+
* Hard cap on how many points a single index will hold. Beyond this,
|
|
13
|
+
* further inserted points still upload to the GPU normally (rendering
|
|
14
|
+
* is unaffected) but are simply not indexed, so the measure tool can't
|
|
15
|
+
* snap to them. This is the "last resort" from the design brief: full,
|
|
16
|
+
* uncapped indexing is strongly preferred (snapping wants real points),
|
|
17
|
+
* so this only bites on genuinely extreme clouds — at ~20 bytes/point
|
|
18
|
+
* of CPU overhead (12 bytes retained positions + ~8 bytes grid), 30M
|
|
19
|
+
* points is already ~600 MB of additional retained memory.
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_MAX_INDEXED_POINTS = 30_000_000;
|
|
22
|
+
/**
|
|
23
|
+
* Cap on the per-visited-cell neighborhood dilation radius, in cells
|
|
24
|
+
* (issue #1860 review finding 1). `toleranceAt(t)` GROWS with depth
|
|
25
|
+
* (it's a screen-space pixel tolerance projected to world units), so a
|
|
26
|
+
* fixed +-1 cell dilation (~0.5 * cellSize of perpendicular coverage)
|
|
27
|
+
* silently stops covering the true tolerance once
|
|
28
|
+
* `toleranceAt(t) > cellSize` — which for the measure tool's ~8px
|
|
29
|
+
* tolerance happens around t = 60-130 m depending on canvas/fov, i.e.
|
|
30
|
+
* exactly the zoomed-out site-scale scans where this matters most.
|
|
31
|
+
* `queryRay` instead computes `r = clamp(ceil(toleranceAt(t)/cellSize),
|
|
32
|
+
* 1, MAX_DILATION_RADIUS_CELLS)` at every visited cell and dilates by
|
|
33
|
+
* that many cells. Capped so a single visited cell never tests more
|
|
34
|
+
* than `(2*4+1)^3 = 729` cells worst case; beyond the cap the
|
|
35
|
+
* *effective* snap radius clamps at `MAX_DILATION_RADIUS_CELLS *
|
|
36
|
+
* cellSize` (2 m at the default 0.5 m cell size) instead of growing
|
|
37
|
+
* unbounded with depth.
|
|
38
|
+
*/
|
|
39
|
+
export const MAX_DILATION_RADIUS_CELLS = 4;
|
|
40
|
+
/**
|
|
41
|
+
* Cell coordinates are packed RELATIVE to the first indexed point's cell
|
|
42
|
+
* (`cellOrigin*` below), clamped to ±`CELL_KEY_BIAS` cells per axis. The
|
|
43
|
+
* relative range must be small enough that the packed triple stays an
|
|
44
|
+
* EXACT f64 integer: with a per-axis range of 2^17 the maximum key is
|
|
45
|
+
* (2^17)^3 = 2^51 < 2^53, so distinct cells always get distinct keys.
|
|
46
|
+
* (The previous absolute-coordinate packing used a 2^21 range whose keys
|
|
47
|
+
* reached ~2^62 — beyond f64's 53-bit integer precision, silently
|
|
48
|
+
* merging every z-column of cells within ~1024 cells into one bucket,
|
|
49
|
+
* and additionally aliasing outright for georeferenced clouds beyond
|
|
50
|
+
* ±524 km. Merged buckets stayed *correct* — `testPoint` re-checks real
|
|
51
|
+
* positions — but degraded the query from O(cells) toward O(points).)
|
|
52
|
+
*
|
|
53
|
+
* ±2^16 relative cells at the default 0.5 m cell size covers ±32.7 km
|
|
54
|
+
* around the first point — beyond any physically plausible single scan.
|
|
55
|
+
* Points outside that window clamp onto the boundary cells (they merge
|
|
56
|
+
* buckets there, degrading gracefully instead of breaking).
|
|
57
|
+
*/
|
|
58
|
+
const CELL_KEY_BIAS = 1 << 16; // 65,536 cells = ±32.7 km at 0.5 m cells
|
|
59
|
+
const CELL_KEY_RANGE = CELL_KEY_BIAS * 2; // 2^17 per axis → max key 2^51, f64-exact
|
|
60
|
+
/**
|
|
61
|
+
* Absolute cap on DDA march steps per query (CodeRabbit CLI review,
|
|
62
|
+
* PR #1875). `maxSteps` otherwise scales with the ray's traversal of the
|
|
63
|
+
* cloud's bounding box, and `maxDistance` is `Infinity` whenever the
|
|
64
|
+
* cursor has no mesh under it — so a total-miss march across an
|
|
65
|
+
* un-rebased site-scale aerial cloud (50 km box) walked ~200k cells with
|
|
66
|
+
* up-to-729-cell neighborhoods on EVERY pointer move (measured 0.2-4.4 s
|
|
67
|
+
* per query). 8192 steps cover ≥2.4 km of ray travel from the box entry
|
|
68
|
+
* (≥ cellSize/√3 of t per step; ~4 km axis-aligned at 0.5 m cells) —
|
|
69
|
+
* far beyond snapping's useful range: the effective snap radius already
|
|
70
|
+
* clamps at `MAX_DILATION_RADIUS_CELLS * cellSize` (2 m), which is
|
|
71
|
+
* sub-pixel past ~1 km at any practical zoom, so points beyond the cap
|
|
72
|
+
* were unsnappable in practice anyway. Bounds worst-case query work
|
|
73
|
+
* independent of the cloud's geographic extent.
|
|
74
|
+
*/
|
|
75
|
+
const MAX_MARCH_CELLS = 8192;
|
|
76
|
+
/** √3 — a cube cell's diagonal in units of its edge length. */
|
|
77
|
+
const CELL_DIAGONAL = Math.sqrt(3);
|
|
78
|
+
/** Clamp a relative cell coordinate into the packable per-axis window. */
|
|
79
|
+
function clampRelCell(c) {
|
|
80
|
+
return c < -CELL_KEY_BIAS ? -CELL_KEY_BIAS : c >= CELL_KEY_BIAS ? CELL_KEY_BIAS - 1 : c;
|
|
81
|
+
}
|
|
82
|
+
/** Is `classId` visible under a normalized 8-word class bitmask?
|
|
83
|
+
* (`undefined`/missing words default to visible, matching
|
|
84
|
+
* `normalizeClassMask`.) */
|
|
85
|
+
function classVisible(classMask, classId) {
|
|
86
|
+
if (!classMask)
|
|
87
|
+
return true;
|
|
88
|
+
const word = classMask[classId >> 5];
|
|
89
|
+
if (word === undefined)
|
|
90
|
+
return true;
|
|
91
|
+
return ((word >>> (classId & 31)) & 1) === 1;
|
|
92
|
+
}
|
|
93
|
+
/** Axis-aligned ray/box entry+exit distances, or null on a miss. */
|
|
94
|
+
function rayBoxEntryExit(origin, dir, box) {
|
|
95
|
+
let tMin = -Infinity;
|
|
96
|
+
let tMax = Infinity;
|
|
97
|
+
const axes = ['x', 'y', 'z'];
|
|
98
|
+
for (const ax of axes) {
|
|
99
|
+
const o = origin[ax];
|
|
100
|
+
const d = dir[ax];
|
|
101
|
+
if (Math.abs(d) < 1e-12) {
|
|
102
|
+
if (o < box.min[ax] || o > box.max[ax])
|
|
103
|
+
return null;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
let t1 = (box.min[ax] - o) / d;
|
|
107
|
+
let t2 = (box.max[ax] - o) / d;
|
|
108
|
+
if (t1 > t2) {
|
|
109
|
+
const tmp = t1;
|
|
110
|
+
t1 = t2;
|
|
111
|
+
t2 = tmp;
|
|
112
|
+
}
|
|
113
|
+
if (t1 > tMin)
|
|
114
|
+
tMin = t1;
|
|
115
|
+
if (t2 < tMax)
|
|
116
|
+
tMax = t2;
|
|
117
|
+
if (tMin > tMax)
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
if (tMax < 0)
|
|
121
|
+
return null;
|
|
122
|
+
return { tMin, tMax };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* CPU spatial index for one point-cloud asset. Insert incrementally via
|
|
126
|
+
* `insertRange` as chunks stream in; query via `queryRay`. Not thread
|
|
127
|
+
* safe (single-threaded main-thread structure, matching the renderer).
|
|
128
|
+
*/
|
|
129
|
+
export class PointCloudSpatialIndex {
|
|
130
|
+
cellSize;
|
|
131
|
+
maxIndexedPoints;
|
|
132
|
+
cells = new Map();
|
|
133
|
+
chunks = [];
|
|
134
|
+
total = 0;
|
|
135
|
+
minX = Infinity;
|
|
136
|
+
minY = Infinity;
|
|
137
|
+
minZ = Infinity;
|
|
138
|
+
maxX = -Infinity;
|
|
139
|
+
maxY = -Infinity;
|
|
140
|
+
maxZ = -Infinity;
|
|
141
|
+
/**
|
|
142
|
+
* Cell coordinates of the first indexed point — the origin every packed
|
|
143
|
+
* cell key is relative to (see `CELL_KEY_BIAS`). Rebasing per index keeps
|
|
144
|
+
* keys f64-exact even for un-rebased georeferenced clouds (e.g. Swiss
|
|
145
|
+
* LV95 eastings ~2.6e6 m → absolute cell ~5.2e6, far outside any
|
|
146
|
+
* absolute packing window, but within ±2^16 cells of the cloud's own
|
|
147
|
+
* first point).
|
|
148
|
+
*/
|
|
149
|
+
cellOriginX = 0;
|
|
150
|
+
cellOriginY = 0;
|
|
151
|
+
cellOriginZ = 0;
|
|
152
|
+
hasCellOrigin = false;
|
|
153
|
+
/** Pack ABSOLUTE cell coordinates into one exact-integer key. */
|
|
154
|
+
packKey(cx, cy, cz) {
|
|
155
|
+
const ux = clampRelCell(cx - this.cellOriginX) + CELL_KEY_BIAS;
|
|
156
|
+
const uy = clampRelCell(cy - this.cellOriginY) + CELL_KEY_BIAS;
|
|
157
|
+
const uz = clampRelCell(cz - this.cellOriginZ) + CELL_KEY_BIAS;
|
|
158
|
+
return (ux * CELL_KEY_RANGE + uy) * CELL_KEY_RANGE + uz;
|
|
159
|
+
}
|
|
160
|
+
constructor(cellSize = DEFAULT_POINTCLOUD_INDEX_CELL_SIZE, maxIndexedPoints = DEFAULT_MAX_INDEXED_POINTS) {
|
|
161
|
+
this.cellSize = cellSize > 0 && Number.isFinite(cellSize) ? cellSize : DEFAULT_POINTCLOUD_INDEX_CELL_SIZE;
|
|
162
|
+
this.maxIndexedPoints =
|
|
163
|
+
maxIndexedPoints > 0 && Number.isFinite(maxIndexedPoints)
|
|
164
|
+
? Math.floor(maxIndexedPoints)
|
|
165
|
+
: DEFAULT_MAX_INDEXED_POINTS;
|
|
166
|
+
}
|
|
167
|
+
/** Total number of points currently indexed (may be less than the
|
|
168
|
+
* asset's true point count once `maxIndexedPoints` is hit). */
|
|
169
|
+
get pointCount() {
|
|
170
|
+
return this.total;
|
|
171
|
+
}
|
|
172
|
+
/** True once further inserts are silently dropped (memory safety valve). */
|
|
173
|
+
get isCapped() {
|
|
174
|
+
return this.total >= this.maxIndexedPoints;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Insert the first `count` xyz triples of `positions` (renderer/world
|
|
178
|
+
* space — the same frame `queryRay` expects). Keeps `positions` (and
|
|
179
|
+
* `classifications`, when given) BY REFERENCE; the caller must not
|
|
180
|
+
* mutate them afterwards. A no-op past `maxIndexedPoints` (see class
|
|
181
|
+
* docs) — points beyond the cap render normally but are not indexed
|
|
182
|
+
* for picking. When a chunk CROSSES the cap, only the accepted prefix
|
|
183
|
+
* is retained (copied) so the cap genuinely bounds retained memory —
|
|
184
|
+
* keeping the whole source array by reference would retain e.g. a
|
|
185
|
+
* 100M-point one-shot chunk's full 1.2 GB for a 30M-point cap.
|
|
186
|
+
*/
|
|
187
|
+
insertRange(positions, count, classifications) {
|
|
188
|
+
if (count <= 0 || this.total >= this.maxIndexedPoints)
|
|
189
|
+
return;
|
|
190
|
+
const usable = Math.min(count, this.maxIndexedPoints - this.total);
|
|
191
|
+
const startId = this.total;
|
|
192
|
+
const retainedPositions = usable < count ? positions.slice(0, usable * 3) : positions;
|
|
193
|
+
const retainedClasses = classifications
|
|
194
|
+
? (usable < count ? classifications.slice(0, usable) : classifications)
|
|
195
|
+
: null;
|
|
196
|
+
this.chunks.push({ positions: retainedPositions, classifications: retainedClasses, count: usable, startId });
|
|
197
|
+
for (let i = 0; i < usable; i++) {
|
|
198
|
+
const o = i * 3;
|
|
199
|
+
const x = positions[o];
|
|
200
|
+
const y = positions[o + 1];
|
|
201
|
+
const z = positions[o + 2];
|
|
202
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z))
|
|
203
|
+
continue;
|
|
204
|
+
if (x < this.minX)
|
|
205
|
+
this.minX = x;
|
|
206
|
+
if (x > this.maxX)
|
|
207
|
+
this.maxX = x;
|
|
208
|
+
if (y < this.minY)
|
|
209
|
+
this.minY = y;
|
|
210
|
+
if (y > this.maxY)
|
|
211
|
+
this.maxY = y;
|
|
212
|
+
if (z < this.minZ)
|
|
213
|
+
this.minZ = z;
|
|
214
|
+
if (z > this.maxZ)
|
|
215
|
+
this.maxZ = z;
|
|
216
|
+
const cx = Math.floor(x / this.cellSize);
|
|
217
|
+
const cy = Math.floor(y / this.cellSize);
|
|
218
|
+
const cz = Math.floor(z / this.cellSize);
|
|
219
|
+
if (!this.hasCellOrigin) {
|
|
220
|
+
this.cellOriginX = cx;
|
|
221
|
+
this.cellOriginY = cy;
|
|
222
|
+
this.cellOriginZ = cz;
|
|
223
|
+
this.hasCellOrigin = true;
|
|
224
|
+
}
|
|
225
|
+
const key = this.packKey(cx, cy, cz);
|
|
226
|
+
let bucket = this.cells.get(key);
|
|
227
|
+
if (!bucket) {
|
|
228
|
+
bucket = [];
|
|
229
|
+
this.cells.set(key, bucket);
|
|
230
|
+
}
|
|
231
|
+
bucket.push(startId + i);
|
|
232
|
+
}
|
|
233
|
+
this.total += usable;
|
|
234
|
+
}
|
|
235
|
+
/** World-space bounds of every indexed point, or null when empty. */
|
|
236
|
+
getBounds() {
|
|
237
|
+
if (this.total === 0 || !Number.isFinite(this.minX))
|
|
238
|
+
return null;
|
|
239
|
+
return {
|
|
240
|
+
min: { x: this.minX, y: this.minY, z: this.minZ },
|
|
241
|
+
max: { x: this.maxX, y: this.maxY, z: this.maxZ },
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/** Resolve a global point id to its owning chunk, or null. */
|
|
245
|
+
chunkFor(globalId) {
|
|
246
|
+
// Chunks are appended in id order, so `startId` is sorted ascending —
|
|
247
|
+
// binary search for the owning chunk (dense buckets can resolve
|
|
248
|
+
// thousands of ids per query; a linear chunk scan would multiply
|
|
249
|
+
// that by the chunk count, ~150 for a 30M-point stream).
|
|
250
|
+
const chunks = this.chunks;
|
|
251
|
+
let lo = 0;
|
|
252
|
+
let hi = chunks.length - 1;
|
|
253
|
+
while (lo < hi) {
|
|
254
|
+
const mid = (lo + hi + 1) >> 1;
|
|
255
|
+
if (chunks[mid].startId <= globalId)
|
|
256
|
+
lo = mid;
|
|
257
|
+
else
|
|
258
|
+
hi = mid - 1;
|
|
259
|
+
}
|
|
260
|
+
const c = chunks[lo];
|
|
261
|
+
if (c && globalId >= c.startId && globalId < c.startId + c.count)
|
|
262
|
+
return c;
|
|
263
|
+
// Unreachable: every id in `cells` was handed out by this instance.
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
testPoint(p, origin, dir, maxDistance, toleranceAt) {
|
|
267
|
+
const vx = p.x - origin.x;
|
|
268
|
+
const vy = p.y - origin.y;
|
|
269
|
+
const vz = p.z - origin.z;
|
|
270
|
+
// t = distance along the ray to the closest approach point (dir is
|
|
271
|
+
// assumed unit length — true for every ray this module receives,
|
|
272
|
+
// see raycast-engine.ts / camera-projection.ts unprojectToRay).
|
|
273
|
+
const t = vx * dir.x + vy * dir.y + vz * dir.z;
|
|
274
|
+
if (t < 0 || t > maxDistance)
|
|
275
|
+
return null; // behind camera, or past the caller's bound
|
|
276
|
+
const px = origin.x + dir.x * t;
|
|
277
|
+
const py = origin.y + dir.y * t;
|
|
278
|
+
const pz = origin.z + dir.z * t;
|
|
279
|
+
const dx = p.x - px;
|
|
280
|
+
const dy = p.y - py;
|
|
281
|
+
const dz = p.z - pz;
|
|
282
|
+
const perp = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
283
|
+
if (perp > toleranceAt(t))
|
|
284
|
+
return null;
|
|
285
|
+
return { position: p, distance: t };
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Test points in the dilated cell block around (cx,cy,cz), skipping
|
|
289
|
+
* cells already visited by an earlier step of the same query.
|
|
290
|
+
* `radiusCells` must cover `toleranceAt(t)` at the depth this cell is
|
|
291
|
+
* visited at — see `queryRay`'s per-step radius computation (#1860
|
|
292
|
+
* review finding 1: a fixed +-1 dilation under-covers tolerance at
|
|
293
|
+
* long range).
|
|
294
|
+
*
|
|
295
|
+
* When `slabAxis` is 0/1/2 the scan is restricted to the LEADING SLAB
|
|
296
|
+
* of the block along that axis (offset `slabDir * radiusCells`, the
|
|
297
|
+
* `(2r+1)^2` cells newly uncovered by a one-cell DDA advance) instead
|
|
298
|
+
* of the full `(2r+1)^3` block (hosted CodeRabbit review, PR #1875):
|
|
299
|
+
* consecutive DDA steps overlap ~90% of their blocks, and while the
|
|
300
|
+
* `visited` set kept the overlap from re-scanning buckets, every probe
|
|
301
|
+
* still paid `packKey` + `Set.has` — ~6M map operations for a capped
|
|
302
|
+
* worst-case march at radius 4. Since the DDA advances exactly one
|
|
303
|
+
* axis by exactly one cell per step, `block(new) \ block(old)` IS that
|
|
304
|
+
* leading slab whenever the radius is unchanged; `queryRay` passes
|
|
305
|
+
* `slabAxis: -1` (full block) for the first cell and whenever the
|
|
306
|
+
* radius changed between steps.
|
|
307
|
+
*/
|
|
308
|
+
testCellNeighborhood(cx, cy, cz, radiusCells, origin, dir, maxDistance, toleranceAt, classMask, visited, best, slabAxis = -1, slabDir = 1) {
|
|
309
|
+
const r = radiusCells;
|
|
310
|
+
const lead = slabDir * r;
|
|
311
|
+
const xLo = slabAxis === 0 ? lead : -r;
|
|
312
|
+
const xHi = slabAxis === 0 ? lead : r;
|
|
313
|
+
const yLo = slabAxis === 1 ? lead : -r;
|
|
314
|
+
const yHi = slabAxis === 1 ? lead : r;
|
|
315
|
+
const zLo = slabAxis === 2 ? lead : -r;
|
|
316
|
+
const zHi = slabAxis === 2 ? lead : r;
|
|
317
|
+
for (let dx = xLo; dx <= xHi; dx++) {
|
|
318
|
+
for (let dy = yLo; dy <= yHi; dy++) {
|
|
319
|
+
for (let dz = zLo; dz <= zHi; dz++) {
|
|
320
|
+
const key = this.packKey(cx + dx, cy + dy, cz + dz);
|
|
321
|
+
// The `visited` dedup is only worth paying for FULL-block scans
|
|
322
|
+
// (first cell / radius changes): a leading slab is disjoint from
|
|
323
|
+
// every earlier block by construction — each block-centre axis
|
|
324
|
+
// coordinate is monotone along the march, so the slab's fixed
|
|
325
|
+
// coordinate `c + slabDir * r` lies strictly beyond every prior
|
|
326
|
+
// block's extent (for the production monotone-radius case; a
|
|
327
|
+
// non-monotone `toleranceAt` can at worst re-test a bucket,
|
|
328
|
+
// which is idempotent — `testPoint` recomputes and `best` takes
|
|
329
|
+
// the min). Skipping the Set here removes two hash operations
|
|
330
|
+
// per probed cell — the dominant cost of long marches.
|
|
331
|
+
if (slabAxis === -1) {
|
|
332
|
+
if (visited.has(key))
|
|
333
|
+
continue;
|
|
334
|
+
visited.add(key);
|
|
335
|
+
}
|
|
336
|
+
const bucket = this.cells.get(key);
|
|
337
|
+
if (!bucket)
|
|
338
|
+
continue;
|
|
339
|
+
for (const globalId of bucket) {
|
|
340
|
+
const chunk = this.chunkFor(globalId);
|
|
341
|
+
if (!chunk)
|
|
342
|
+
continue;
|
|
343
|
+
const local = globalId - chunk.startId;
|
|
344
|
+
// Skip points the splat shader currently hides via the LAS
|
|
345
|
+
// class visibility mask (#1783) — the measure tool must not
|
|
346
|
+
// snap to invisible scan data. Classification-free chunks
|
|
347
|
+
// are class 0, mirroring the GPU vertex packing.
|
|
348
|
+
const classId = chunk.classifications ? chunk.classifications[local] : 0;
|
|
349
|
+
if (!classVisible(classMask, classId))
|
|
350
|
+
continue;
|
|
351
|
+
const o = local * 3;
|
|
352
|
+
const p = { x: chunk.positions[o], y: chunk.positions[o + 1], z: chunk.positions[o + 2] };
|
|
353
|
+
const hit = this.testPoint(p, origin, dir, maxDistance, toleranceAt);
|
|
354
|
+
if (hit && (!best.hit || hit.distance < best.hit.distance))
|
|
355
|
+
best.hit = hit;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Nearest indexed point to `ray` (origin + unit `dir`) within
|
|
363
|
+
* `toleranceAt(t)` world units of the ray axis at depth `t`,
|
|
364
|
+
* restricted to `[0, maxDistance]`. Returns the candidate with the
|
|
365
|
+
* SMALLEST `t` (nearest along the ray) among everything within
|
|
366
|
+
* tolerance — not necessarily the one closest to the ray's infinite
|
|
367
|
+
* line — matching how a real surface point would occlude anything
|
|
368
|
+
* behind it.
|
|
369
|
+
*
|
|
370
|
+
* O(cells touched) via an Amanatides & Woo DDA march from the ray's
|
|
371
|
+
* entry into the index's bounding box. `toleranceAt(t)` grows with
|
|
372
|
+
* depth, so each visited cell's neighborhood dilation radius is
|
|
373
|
+
* recomputed from `toleranceAt` at that cell's ray parameter —
|
|
374
|
+
* `clamp(ceil(toleranceAt(t)/cellSize), 1, MAX_DILATION_RADIUS_CELLS)`
|
|
375
|
+
* — instead of a fixed +-1 cell, so a point within the true
|
|
376
|
+
* screen-space tolerance is never missed just because it's more than
|
|
377
|
+
* half a cell off the ray's exact cell path at long range (#1860
|
|
378
|
+
* review finding 1). Marching stops one cell past the first
|
|
379
|
+
* tolerance hit (using the largest radius seen so far, conservative),
|
|
380
|
+
* since DDA visits cells in non-decreasing ray-parameter order.
|
|
381
|
+
*/
|
|
382
|
+
queryRay(origin, dir, maxDistance, toleranceAt,
|
|
383
|
+
/** Normalized 8-word LAS class visibility bitmask (#1783); points of
|
|
384
|
+
* hidden classes are skipped. Omit/null for "everything visible". */
|
|
385
|
+
classMask) {
|
|
386
|
+
if (this.total === 0 || maxDistance <= 0)
|
|
387
|
+
return null;
|
|
388
|
+
const bounds = this.getBounds();
|
|
389
|
+
if (!bounds)
|
|
390
|
+
return null;
|
|
391
|
+
const cs = this.cellSize;
|
|
392
|
+
// Pad the coarse bounding-box cull by the MAX possible dilation
|
|
393
|
+
// radius (not just one cell): `bounds` is the exact (often
|
|
394
|
+
// near-zero-thickness, e.g. a flat wall scan) extent of the indexed
|
|
395
|
+
// points, so an UNPADDED box/ray test would reject a ray that
|
|
396
|
+
// passes close to — but not exactly through — the box, even though
|
|
397
|
+
// a point within tolerance sits just past its face. Since the
|
|
398
|
+
// per-cell dilation radius below can grow up to
|
|
399
|
+
// `MAX_DILATION_RADIUS_CELLS` cells at long range, the outer cull
|
|
400
|
+
// must be padded by the same amount or a ray whose only near-miss
|
|
401
|
+
// is right at the cloud's edge could be rejected before the march
|
|
402
|
+
// even starts.
|
|
403
|
+
const maxPad = MAX_DILATION_RADIUS_CELLS * cs;
|
|
404
|
+
const paddedBounds = {
|
|
405
|
+
min: { x: bounds.min.x - maxPad, y: bounds.min.y - maxPad, z: bounds.min.z - maxPad },
|
|
406
|
+
max: { x: bounds.max.x + maxPad, y: bounds.max.y + maxPad, z: bounds.max.z + maxPad },
|
|
407
|
+
};
|
|
408
|
+
const entry = rayBoxEntryExit(origin, dir, paddedBounds);
|
|
409
|
+
if (!entry)
|
|
410
|
+
return null;
|
|
411
|
+
const tMin = Math.max(0, entry.tMin);
|
|
412
|
+
const tMax = Math.min(maxDistance, entry.tMax);
|
|
413
|
+
if (tMax < tMin)
|
|
414
|
+
return null;
|
|
415
|
+
const startX = origin.x + dir.x * tMin;
|
|
416
|
+
const startY = origin.y + dir.y * tMin;
|
|
417
|
+
const startZ = origin.z + dir.z * tMin;
|
|
418
|
+
let cx = Math.floor(startX / cs);
|
|
419
|
+
let cy = Math.floor(startY / cs);
|
|
420
|
+
let cz = Math.floor(startZ / cs);
|
|
421
|
+
const stepX = dir.x > 0 ? 1 : dir.x < 0 ? -1 : 0;
|
|
422
|
+
const stepY = dir.y > 0 ? 1 : dir.y < 0 ? -1 : 0;
|
|
423
|
+
const stepZ = dir.z > 0 ? 1 : dir.z < 0 ? -1 : 0;
|
|
424
|
+
const axisTMax = (o, d, cell) => {
|
|
425
|
+
if (d === 0)
|
|
426
|
+
return Infinity;
|
|
427
|
+
const boundary = d > 0 ? (cell + 1) * cs : cell * cs;
|
|
428
|
+
return (boundary - o) / d;
|
|
429
|
+
};
|
|
430
|
+
const axisTDelta = (d) => (d === 0 ? Infinity : Math.abs(cs / d));
|
|
431
|
+
let tMaxX = axisTMax(origin.x, dir.x, cx);
|
|
432
|
+
let tMaxY = axisTMax(origin.y, dir.y, cy);
|
|
433
|
+
let tMaxZ = axisTMax(origin.z, dir.z, cz);
|
|
434
|
+
const tDeltaX = axisTDelta(dir.x);
|
|
435
|
+
const tDeltaY = axisTDelta(dir.y);
|
|
436
|
+
const tDeltaZ = axisTDelta(dir.z);
|
|
437
|
+
const best = { hit: null };
|
|
438
|
+
const visited = new Set();
|
|
439
|
+
let t = tMin;
|
|
440
|
+
// Largest dilation radius (in cells) used by any step so far — the
|
|
441
|
+
// early-break margin below must use this, not a fixed 1, since a
|
|
442
|
+
// hit found under a wide (long-range) radius could still have a
|
|
443
|
+
// nearer neighbor one radius-worth of cells further along the ray.
|
|
444
|
+
let maxRadiusUsed = 1;
|
|
445
|
+
// Safety cap: bounds the loop even if DDA step math misbehaves at a
|
|
446
|
+
// grazing angle (near-zero direction components with fp error), AND
|
|
447
|
+
// bounds worst-case work per query via the absolute `MAX_MARCH_CELLS`
|
|
448
|
+
// ceiling — without it a total-miss march across a site-scale cloud
|
|
449
|
+
// with `maxDistance = Infinity` (no mesh under the cursor) walked the
|
|
450
|
+
// whole bounding box on every pointer move (see MAX_MARCH_CELLS docs).
|
|
451
|
+
const maxSteps = Math.min(MAX_MARCH_CELLS, 8 + Math.ceil((tMax - tMin) / cs) * 3);
|
|
452
|
+
// Which axis (and direction) the DDA advanced to REACH the current
|
|
453
|
+
// cell, so the neighborhood scan can restrict itself to the block's
|
|
454
|
+
// newly uncovered leading slab (see `testCellNeighborhood`). -1 for
|
|
455
|
+
// the first cell (no previous block) and after a radius change
|
|
456
|
+
// (block shape changed, rescan it whole; `visited` dedups overlap).
|
|
457
|
+
// `toleranceAt` is monotone in production (constant in ortho, linear
|
|
458
|
+
// in perspective), so the radius changes at most 3 times per query.
|
|
459
|
+
let steppedAxis = -1;
|
|
460
|
+
let steppedDir = 1;
|
|
461
|
+
let prevRadius = 0;
|
|
462
|
+
for (let step = 0; step < maxSteps && t <= tMax; step++) {
|
|
463
|
+
// Dilation radius covering toleranceAt(t) at THIS cell's ray
|
|
464
|
+
// parameter — toleranceAt grows with depth, so a fixed +-1 cell
|
|
465
|
+
// (as before #1860 finding 1) silently under-covers tolerance
|
|
466
|
+
// once toleranceAt(t) exceeds one cell size.
|
|
467
|
+
const tolWorld = toleranceAt(Math.max(0, t));
|
|
468
|
+
const radius = Math.min(MAX_DILATION_RADIUS_CELLS, Math.max(1, Math.ceil(tolWorld / cs)));
|
|
469
|
+
if (radius > maxRadiusUsed)
|
|
470
|
+
maxRadiusUsed = radius;
|
|
471
|
+
const slabAxis = radius === prevRadius ? steppedAxis : -1;
|
|
472
|
+
this.testCellNeighborhood(cx, cy, cz, radius, origin, dir, tMax, toleranceAt, classMask, visited, best, slabAxis, steppedDir);
|
|
473
|
+
prevRadius = radius;
|
|
474
|
+
// DDA visits cells in non-decreasing t order, so once we have a
|
|
475
|
+
// hit and have advanced well past it, no later cell can hold a
|
|
476
|
+
// nearer point — stop early instead of walking to tMax. Using the
|
|
477
|
+
// largest radius seen so far (rather than the current step's) is
|
|
478
|
+
// conservative: a hit found under a wide dilation could still have
|
|
479
|
+
// a nearer point just beyond a narrower later step's smaller
|
|
480
|
+
// neighborhood. The margin accounts for the dilated block's full
|
|
481
|
+
// diagonal (CodeRabbit CLI review, PR #1875): a cell at offset
|
|
482
|
+
// (±r,±r,±r) is never on the march path itself, so a point inside
|
|
483
|
+
// it can project onto the ray up to (r + 1) * cs * √3 BEHIND this
|
|
484
|
+
// step's `t` — a straight `maxRadiusUsed * cs` margin could break
|
|
485
|
+
// before the off-axis corner cell holding the true nearest point
|
|
486
|
+
// was ever dilated into view.
|
|
487
|
+
const breakMargin = (maxRadiusUsed + 1) * cs * CELL_DIAGONAL;
|
|
488
|
+
if (best.hit && t > best.hit.distance + breakMargin)
|
|
489
|
+
break;
|
|
490
|
+
if (tMaxX < tMaxY) {
|
|
491
|
+
if (tMaxX < tMaxZ) {
|
|
492
|
+
t = tMaxX;
|
|
493
|
+
cx += stepX;
|
|
494
|
+
tMaxX += tDeltaX;
|
|
495
|
+
steppedAxis = 0;
|
|
496
|
+
steppedDir = stepX < 0 ? -1 : 1;
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
t = tMaxZ;
|
|
500
|
+
cz += stepZ;
|
|
501
|
+
tMaxZ += tDeltaZ;
|
|
502
|
+
steppedAxis = 2;
|
|
503
|
+
steppedDir = stepZ < 0 ? -1 : 1;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
else if (tMaxY < tMaxZ) {
|
|
507
|
+
t = tMaxY;
|
|
508
|
+
cy += stepY;
|
|
509
|
+
tMaxY += tDeltaY;
|
|
510
|
+
steppedAxis = 1;
|
|
511
|
+
steppedDir = stepY < 0 ? -1 : 1;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
t = tMaxZ;
|
|
515
|
+
cz += stepZ;
|
|
516
|
+
tMaxZ += tDeltaZ;
|
|
517
|
+
steppedAxis = 2;
|
|
518
|
+
steppedDir = stepZ < 0 ? -1 : 1;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return best.hit;
|
|
522
|
+
}
|
|
523
|
+
/** Drop every retained position array and grid bucket. Call when the
|
|
524
|
+
* owning PointCloudNode is destroyed so nothing outlives its GPU
|
|
525
|
+
* resources (see `destroyNode` in point-cloud-node.ts). */
|
|
526
|
+
dispose() {
|
|
527
|
+
this.cells.clear();
|
|
528
|
+
this.chunks = [];
|
|
529
|
+
this.total = 0;
|
|
530
|
+
this.minX = this.minY = this.minZ = Infinity;
|
|
531
|
+
this.maxX = this.maxY = this.maxZ = -Infinity;
|
|
532
|
+
this.cellOriginX = this.cellOriginY = this.cellOriginZ = 0;
|
|
533
|
+
this.hasCellOrigin = false;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
//# sourceMappingURL=point-cloud-spatial-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-cloud-spatial-index.js","sourceRoot":"","sources":["../../src/pointcloud/point-cloud-spatial-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { PointCloudNode } from './point-cloud-node.js';
|
|
2
2
|
export type PointColorMode = 'rgb' | 'classification' | 'intensity' | 'height' | 'fixed' | 'deviation';
|
|
3
3
|
export type PointSizeMode = 'fixed-px' | 'adaptive-world' | 'attenuated';
|
|
4
|
+
/** Number of u32 words in the 256-bit LAS class-visibility mask. */
|
|
5
|
+
export declare const CLASS_MASK_WORDS = 8;
|
|
6
|
+
/**
|
|
7
|
+
* Normalize the public `classMask` option into the 8-word (256-bit)
|
|
8
|
+
* uniform layout. Accepts:
|
|
9
|
+
* - `undefined` → all classes visible
|
|
10
|
+
* - `number` (legacy) → bits 0..31 as given; classes 32..255 stay
|
|
11
|
+
* visible, matching the old 32-bit semantics
|
|
12
|
+
* - `ArrayLike<number>` → up to 8 words, LSB-first; missing or
|
|
13
|
+
* non-finite words default to all-visible
|
|
14
|
+
*/
|
|
15
|
+
export declare function normalizeClassMask(mask: number | ArrayLike<number> | undefined): Uint32Array;
|
|
4
16
|
export declare const COLOR_MODE_INDEX: Record<PointColorMode, number>;
|
|
5
17
|
export declare const SIZE_MODE_INDEX: Record<PointSizeMode, number>;
|
|
6
18
|
export interface PointUniformInputs {
|
|
@@ -18,8 +30,8 @@ export interface PointUniformInputs {
|
|
|
18
30
|
heightMax: number;
|
|
19
31
|
viewportW: number;
|
|
20
32
|
viewportH: number;
|
|
21
|
-
/**
|
|
22
|
-
classMask:
|
|
33
|
+
/** 256-bit LAS class-visibility mask, 8 u32 words LSB-first (#1783). */
|
|
34
|
+
classMask: Uint32Array;
|
|
23
35
|
/** Preview stride — 1 = full density, N = render every Nth point. */
|
|
24
36
|
previewStride: number;
|
|
25
37
|
/** BIM ↔ scan deviation heatmap range (metres). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"point-cloud-uniforms.d.ts","sourceRoot":"","sources":["../../src/pointcloud/point-cloud-uniforms.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"point-cloud-uniforms.d.ts","sourceRoot":"","sources":["../../src/pointcloud/point-cloud-uniforms.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,MAAM,MAAM,cAAc,GACtB,KAAK,GACL,gBAAgB,GAChB,WAAW,GACX,QAAQ,GACR,OAAO,GACP,WAAW,CAAC;AAEhB,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAEzE,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,SAAS,GAC3C,WAAW,CAYb;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAO3D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAIzD,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,WAAW,CAAC;IACvB,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,WAAW,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,kBAAkB,GACzB,IAAI,CAqEN"}
|