@ifc-lite/pointcloud 0.2.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.
Files changed (87) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +26 -0
  3. package/dist/formats/e57.d.ts +129 -0
  4. package/dist/formats/e57.d.ts.map +1 -0
  5. package/dist/formats/e57.js +495 -0
  6. package/dist/formats/e57.js.map +1 -0
  7. package/dist/formats/ifcx-points.d.ts +26 -0
  8. package/dist/formats/ifcx-points.d.ts.map +1 -0
  9. package/dist/formats/ifcx-points.js +134 -0
  10. package/dist/formats/ifcx-points.js.map +1 -0
  11. package/dist/formats/las.d.ts +54 -0
  12. package/dist/formats/las.d.ts.map +1 -0
  13. package/dist/formats/las.js +203 -0
  14. package/dist/formats/las.js.map +1 -0
  15. package/dist/formats/pcd.d.ts +3 -0
  16. package/dist/formats/pcd.d.ts.map +1 -0
  17. package/dist/formats/pcd.js +302 -0
  18. package/dist/formats/pcd.js.map +1 -0
  19. package/dist/formats/ply.d.ts +40 -0
  20. package/dist/formats/ply.d.ts.map +1 -0
  21. package/dist/formats/ply.js +250 -0
  22. package/dist/formats/ply.js.map +1 -0
  23. package/dist/from-ifcx-attributes.d.ts +10 -0
  24. package/dist/from-ifcx-attributes.d.ts.map +1 -0
  25. package/dist/from-ifcx-attributes.js +49 -0
  26. package/dist/from-ifcx-attributes.js.map +1 -0
  27. package/dist/index.d.ts +26 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +21 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/lzf.d.ts +10 -0
  32. package/dist/lzf.d.ts.map +1 -0
  33. package/dist/lzf.js +64 -0
  34. package/dist/lzf.js.map +1 -0
  35. package/dist/streaming/blob-source.d.ts +15 -0
  36. package/dist/streaming/blob-source.d.ts.map +1 -0
  37. package/dist/streaming/blob-source.js +30 -0
  38. package/dist/streaming/blob-source.js.map +1 -0
  39. package/dist/streaming/decode-worker.d.ts +2 -0
  40. package/dist/streaming/decode-worker.d.ts.map +1 -0
  41. package/dist/streaming/decode-worker.js +131 -0
  42. package/dist/streaming/decode-worker.js.map +1 -0
  43. package/dist/streaming/e57-source.d.ts +17 -0
  44. package/dist/streaming/e57-source.d.ts.map +1 -0
  45. package/dist/streaming/e57-source.js +83 -0
  46. package/dist/streaming/e57-source.js.map +1 -0
  47. package/dist/streaming/host.d.ts +54 -0
  48. package/dist/streaming/host.d.ts.map +1 -0
  49. package/dist/streaming/host.js +120 -0
  50. package/dist/streaming/host.js.map +1 -0
  51. package/dist/streaming/las-source.d.ts +28 -0
  52. package/dist/streaming/las-source.d.ts.map +1 -0
  53. package/dist/streaming/las-source.js +117 -0
  54. package/dist/streaming/las-source.js.map +1 -0
  55. package/dist/streaming/laz-source.d.ts +35 -0
  56. package/dist/streaming/laz-source.d.ts.map +1 -0
  57. package/dist/streaming/laz-source.js +205 -0
  58. package/dist/streaming/laz-source.js.map +1 -0
  59. package/dist/streaming/pcd-source.d.ts +25 -0
  60. package/dist/streaming/pcd-source.d.ts.map +1 -0
  61. package/dist/streaming/pcd-source.js +86 -0
  62. package/dist/streaming/pcd-source.js.map +1 -0
  63. package/dist/streaming/ply-source.d.ts +26 -0
  64. package/dist/streaming/ply-source.d.ts.map +1 -0
  65. package/dist/streaming/ply-source.js +98 -0
  66. package/dist/streaming/ply-source.js.map +1 -0
  67. package/dist/streaming/protocol.d.ts +62 -0
  68. package/dist/streaming/protocol.d.ts.map +1 -0
  69. package/dist/streaming/protocol.js +45 -0
  70. package/dist/streaming/protocol.js.map +1 -0
  71. package/dist/streaming/types.d.ts +41 -0
  72. package/dist/streaming/types.d.ts.map +1 -0
  73. package/dist/streaming/types.js +5 -0
  74. package/dist/streaming/types.js.map +1 -0
  75. package/dist/streaming/worker-client.d.ts +20 -0
  76. package/dist/streaming/worker-client.d.ts.map +1 -0
  77. package/dist/streaming/worker-client.js +152 -0
  78. package/dist/streaming/worker-client.js.map +1 -0
  79. package/dist/types.d.ts +36 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +5 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/xml-mini.d.ts +29 -0
  84. package/dist/xml-mini.d.ts.map +1 -0
  85. package/dist/xml-mini.js +181 -0
  86. package/dist/xml-mini.js.map +1 -0
  87. package/package.json +51 -0
@@ -0,0 +1,120 @@
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
+ import { createDecodeWorkerSource, } from './worker-client.js';
5
+ const DEFAULT_MAX_POINTS = 25_000_000;
6
+ const DEFAULT_MAX_FILE = 4 * 1024 * 1024 * 1024; // 4 GB
7
+ const DEFAULT_CHUNK = 200_000;
8
+ export function streamPointCloud(opts) {
9
+ const maxPoints = opts.maxPointsInMemory ?? DEFAULT_MAX_POINTS;
10
+ const maxFile = opts.maxFileSize ?? DEFAULT_MAX_FILE;
11
+ const chunkSize = opts.chunkSize ?? DEFAULT_CHUNK;
12
+ // chunkSize <= 0 would let the source.next() loop emit empty chunks
13
+ // forever without advancing its cursor. Fail loudly so callers can't
14
+ // accidentally lock up the worker.
15
+ if (!Number.isFinite(chunkSize) || chunkSize <= 0) {
16
+ throw new Error(`streamPointCloud: chunkSize must be a positive finite number (got ${chunkSize})`);
17
+ }
18
+ const localAbort = new AbortController();
19
+ const composed = composeAbort(opts.signal, localAbort.signal);
20
+ const done = (async () => {
21
+ if (opts.blob.size > maxFile) {
22
+ throw new Error(`Point cloud rejected: file is ${(opts.blob.size / 1e6).toFixed(0)} MB, ` +
23
+ `exceeds maxFileSize ${(maxFile / 1e6).toFixed(0)} MB`);
24
+ }
25
+ const probeFactory = opts.createSource ?? createDecodeWorkerSource;
26
+ let source;
27
+ let totalEmitted = 0;
28
+ let bboxMin = [Infinity, Infinity, Infinity];
29
+ let bboxMax = [-Infinity, -Infinity, -Infinity];
30
+ let info = null;
31
+ try {
32
+ // First open with stride=1 to learn the true point count, then
33
+ // re-open with the right stride if we need to downsample.
34
+ let stride = 1;
35
+ source = probeFactory({
36
+ format: opts.format,
37
+ blob: opts.blob,
38
+ label: opts.label,
39
+ stride: 1,
40
+ });
41
+ info = await source.open(composed);
42
+ if (info.totalPointCount > maxPoints) {
43
+ stride = Math.ceil(info.totalPointCount / maxPoints);
44
+ source.close();
45
+ source = probeFactory({
46
+ format: opts.format,
47
+ blob: opts.blob,
48
+ label: opts.label,
49
+ stride,
50
+ });
51
+ info = await source.open(composed);
52
+ }
53
+ opts.onOpen?.({ ...info, stride });
54
+ while (true) {
55
+ if (composed.aborted)
56
+ break;
57
+ const chunk = await source.next(chunkSize, composed);
58
+ if (!chunk)
59
+ break;
60
+ opts.onChunk(chunk);
61
+ totalEmitted += chunk.pointCount;
62
+ if (chunk.bbox.min[0] < bboxMin[0])
63
+ bboxMin[0] = chunk.bbox.min[0];
64
+ if (chunk.bbox.min[1] < bboxMin[1])
65
+ bboxMin[1] = chunk.bbox.min[1];
66
+ if (chunk.bbox.min[2] < bboxMin[2])
67
+ bboxMin[2] = chunk.bbox.min[2];
68
+ if (chunk.bbox.max[0] > bboxMax[0])
69
+ bboxMax[0] = chunk.bbox.max[0];
70
+ if (chunk.bbox.max[1] > bboxMax[1])
71
+ bboxMax[1] = chunk.bbox.max[1];
72
+ if (chunk.bbox.max[2] > bboxMax[2])
73
+ bboxMax[2] = chunk.bbox.max[2];
74
+ opts.onProgress?.(totalEmitted, info.totalPointCount);
75
+ }
76
+ }
77
+ finally {
78
+ // Catches probe + open + onOpen + decode failures uniformly so
79
+ // worker-backed sources don't leak the decoder on bad files.
80
+ source?.close();
81
+ }
82
+ if (!composed.aborted && info) {
83
+ const bbox = Number.isFinite(bboxMin[0])
84
+ ? { min: bboxMin, max: bboxMax }
85
+ : info.bbox;
86
+ opts.onComplete?.(bbox, totalEmitted);
87
+ }
88
+ })().catch((err) => {
89
+ if (composed.aborted)
90
+ return; // expected on cancel
91
+ opts.onError?.(err instanceof Error ? err : new Error(String(err)));
92
+ throw err;
93
+ });
94
+ return {
95
+ cancel: () => localAbort.abort(),
96
+ done,
97
+ };
98
+ }
99
+ function composeAbort(...signals) {
100
+ // Native AbortSignal.any was added in widely-shipping browsers in 2024.
101
+ // Use the polyfilled fallback so tests in older Node still work.
102
+ const filtered = signals.filter((s) => s !== undefined);
103
+ if (filtered.length === 0)
104
+ return new AbortController().signal;
105
+ if (filtered.length === 1)
106
+ return filtered[0];
107
+ const anyApi = AbortSignal.any;
108
+ if (typeof anyApi === 'function')
109
+ return anyApi(filtered);
110
+ const ctrl = new AbortController();
111
+ for (const s of filtered) {
112
+ if (s.aborted) {
113
+ ctrl.abort(s.reason);
114
+ break;
115
+ }
116
+ s.addEventListener('abort', () => ctrl.abort(s.reason), { once: true });
117
+ }
118
+ return ctrl.signal;
119
+ }
120
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/streaming/host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * LAS streaming source.
3
+ *
4
+ * Implements `StreamingPointSource` over a `BlobByteSource`. Reads the
5
+ * 227-byte public header on `open()`, then yields chunks of decoded
6
+ * points on each `next()`. Stride-based downsampling is supported
7
+ * natively: when `stride > 1`, the source advances by `stride * recordLen`
8
+ * bytes per emitted point.
9
+ */
10
+ import type { DecodedPointChunk } from '../types.js';
11
+ import type { DownsampleHint, PointSourceInfo, StreamingPointSource } from './types.js';
12
+ export declare class LasStreamingSource implements StreamingPointSource {
13
+ private bytes;
14
+ private header;
15
+ private cursor;
16
+ private rgbScale;
17
+ private downsample;
18
+ private label?;
19
+ constructor(blob: Blob, options?: {
20
+ label?: string;
21
+ downsample?: DownsampleHint;
22
+ });
23
+ open(signal?: AbortSignal): Promise<PointSourceInfo>;
24
+ next(maxPoints: number, signal?: AbortSignal): Promise<DecodedPointChunk | null>;
25
+ close(): void;
26
+ private toInfo;
27
+ }
28
+ //# sourceMappingURL=las-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"las-source.d.ts","sourceRoot":"","sources":["../../src/streaming/las-source.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAQrD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAMpB,qBAAa,kBAAmB,YAAW,oBAAoB;IAC7D,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,KAAK,CAAC,CAAS;gBAEX,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,cAAc,CAAA;KAAO;IAM/E,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IAsCpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAoDtF,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,MAAM;CAWf"}
@@ -0,0 +1,117 @@
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
+ import { decodeLasPoints, parseLasHeader, sampleMaxRgbChannel, } from '../formats/las.js';
5
+ import { BlobByteSource } from './blob-source.js';
6
+ const HEADER_PROBE_BYTES = 1024;
7
+ /** RGB-detection probe: read up to 256 KB worth of point records. */
8
+ const RGB_PROBE_RECORDS = 4096;
9
+ export class LasStreamingSource {
10
+ bytes;
11
+ header = null;
12
+ cursor = 0; // index of NEXT point to emit (0..header.pointCount)
13
+ rgbScale = 1;
14
+ downsample;
15
+ label;
16
+ constructor(blob, options = {}) {
17
+ this.bytes = new BlobByteSource(blob);
18
+ this.downsample = options.downsample ?? { stride: 1 };
19
+ this.label = options.label;
20
+ }
21
+ async open(signal) {
22
+ if (this.header) {
23
+ return this.toInfo(this.header);
24
+ }
25
+ abortIfAborted(signal);
26
+ const headerBytes = await this.bytes.read(0, HEADER_PROBE_BYTES);
27
+ abortIfAborted(signal);
28
+ // Use locals through the whole probe so a partial failure (abort
29
+ // mid-RGB-probe, parse error) doesn't leave `this.header` set —
30
+ // otherwise a retry returns the cached info without re-running the
31
+ // RGB-scale detection and silently uses the wrong scale.
32
+ const header = parseLasHeader(headerBytes);
33
+ let rgbScale = 1;
34
+ if (header.hasRgb) {
35
+ const probeSize = Math.min(RGB_PROBE_RECORDS * header.pointRecordLength, Math.max(0, this.bytes.size - header.pointDataOffset));
36
+ if (probeSize > 0) {
37
+ const probe = await this.bytes.read(header.pointDataOffset, header.pointDataOffset + probeSize);
38
+ abortIfAborted(signal);
39
+ const max = sampleMaxRgbChannel(probe, header);
40
+ // Threshold matches PDAL / cloudcompare behaviour: ≤ 255 → assume
41
+ // 8-bit-in-u16 and rescale on decode so values reach 0..1 in float.
42
+ rgbScale = max > 0 && max <= 255 ? 65535 / 255 : 1;
43
+ }
44
+ }
45
+ this.header = header;
46
+ this.rgbScale = rgbScale;
47
+ this.cursor = 0;
48
+ return this.toInfo(header);
49
+ }
50
+ async next(maxPoints, signal) {
51
+ abortIfAborted(signal);
52
+ if (!Number.isFinite(maxPoints) || maxPoints <= 0) {
53
+ // 0/negative would emit empty chunks without advancing the cursor,
54
+ // creating a non-terminating loop in the host.
55
+ throw new Error(`LasStreamingSource: maxPoints must be > 0 (got ${maxPoints})`);
56
+ }
57
+ if (!this.header) {
58
+ throw new Error('LasStreamingSource: open() must be awaited before next()');
59
+ }
60
+ const stride = Math.max(1, this.downsample.stride | 0);
61
+ if (this.cursor >= this.header.pointCount)
62
+ return null;
63
+ if (stride === 1) {
64
+ const remaining = this.header.pointCount - this.cursor;
65
+ const take = Math.min(maxPoints, remaining);
66
+ const startByte = this.header.pointDataOffset + this.cursor * this.header.pointRecordLength;
67
+ const endByte = startByte + take * this.header.pointRecordLength;
68
+ const slab = await this.bytes.read(startByte, endByte);
69
+ abortIfAborted(signal);
70
+ const chunk = decodeLasPoints(slab, this.header, take, this.header.pointRecordLength, this.rgbScale);
71
+ this.cursor += take;
72
+ return chunk;
73
+ }
74
+ // Strided reads: pull a packed slab covering `take * stride` source
75
+ // records, then decode every Nth record.
76
+ const remainingSource = this.header.pointCount - this.cursor;
77
+ const sourceTake = Math.min(maxPoints * stride, remainingSource);
78
+ const decodedCount = Math.ceil(sourceTake / stride);
79
+ const startByte = this.header.pointDataOffset + this.cursor * this.header.pointRecordLength;
80
+ const endByte = startByte + sourceTake * this.header.pointRecordLength;
81
+ const slab = await this.bytes.read(startByte, endByte);
82
+ abortIfAborted(signal);
83
+ // Build a compacted slab that contains only the records we want, then
84
+ // hand it to decodeLasPoints with stride === recordLen.
85
+ const compact = new Uint8Array(decodedCount * this.header.pointRecordLength);
86
+ let writeOff = 0;
87
+ for (let i = 0; i < decodedCount; i++) {
88
+ const srcOff = i * stride * this.header.pointRecordLength;
89
+ compact.set(slab.subarray(srcOff, srcOff + this.header.pointRecordLength), writeOff);
90
+ writeOff += this.header.pointRecordLength;
91
+ }
92
+ const chunk = decodeLasPoints(compact, this.header, decodedCount, this.header.pointRecordLength, this.rgbScale);
93
+ this.cursor += sourceTake;
94
+ return chunk;
95
+ }
96
+ close() {
97
+ this.header = null;
98
+ this.cursor = 0;
99
+ }
100
+ toInfo(header) {
101
+ const stride = Math.max(1, this.downsample.stride | 0);
102
+ return {
103
+ totalPointCount: stride === 1 ? header.pointCount : Math.ceil(header.pointCount / stride),
104
+ bbox: header.bbox,
105
+ hasColor: header.hasRgb,
106
+ hasClassification: true,
107
+ hasIntensity: true,
108
+ label: this.label,
109
+ };
110
+ }
111
+ }
112
+ function abortIfAborted(signal) {
113
+ if (signal?.aborted) {
114
+ throw new DOMException('Aborted', 'AbortError');
115
+ }
116
+ }
117
+ //# sourceMappingURL=las-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"las-source.js","sourceRoot":"","sources":["../../src/streaming/las-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * LAZ streaming source backed by `laz-perf` (Apache-2.0).
3
+ *
4
+ * Phase 2 v1: load the whole .laz file into memory, decompress through
5
+ * `LASZip`, and emit chunks of decoded points. Memory-bounded callers
6
+ * apply `streamPointCloud`'s downsampling cap before reaching here.
7
+ *
8
+ * The wasm module is loaded lazily on first `open()` so files that
9
+ * never need LAZ don't pay the wasm-instantiation cost.
10
+ */
11
+ import type { DecodedPointChunk } from '../types.js';
12
+ import type { DownsampleHint, PointSourceInfo, StreamingPointSource } from './types.js';
13
+ export declare class LazStreamingSource implements StreamingPointSource {
14
+ private blob;
15
+ private downsample;
16
+ private label?;
17
+ private mod;
18
+ private laszip;
19
+ private header;
20
+ private fileBytes;
21
+ private filePtr;
22
+ private pointPtr;
23
+ private pointBuffer;
24
+ private cursor;
25
+ private rgbScale;
26
+ constructor(blob: Blob, options?: {
27
+ label?: string;
28
+ downsample?: DownsampleHint;
29
+ });
30
+ open(signal?: AbortSignal): Promise<PointSourceInfo>;
31
+ next(maxPoints: number, signal?: AbortSignal): Promise<DecodedPointChunk | null>;
32
+ close(): void;
33
+ private toInfo;
34
+ }
35
+ //# sourceMappingURL=laz-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laz-source.d.ts","sourceRoot":"","sources":["../../src/streaming/laz-source.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAsDpB,qBAAa,kBAAmB,YAAW,oBAAoB;IAC7D,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,KAAK,CAAC,CAAS;IAGvB,OAAO,CAAC,GAAG,CAA8B;IACzC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAK;gBAET,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,cAAc,CAAA;KAAO;IAM/E,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IAwEpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAoCtF,KAAK,IAAI,IAAI;IAsBb,OAAO,CAAC,MAAM;CAWf"}
@@ -0,0 +1,205 @@
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
+ import { decodeLasPoints, parseLasHeader, sampleMaxRgbChannel, } from '../formats/las.js';
5
+ let modulePromise = null;
6
+ async function loadLazPerf() {
7
+ if (!modulePromise) {
8
+ modulePromise = (async () => {
9
+ // Dynamic import keeps `laz-perf` out of bundles that don't touch
10
+ // LAZ. The package is shipped as CommonJS (`lib/{node,web}/index.js`),
11
+ // and Vite/webpack wrap CJS imports under `.default` — but the way
12
+ // they do that varies, so probe every shape we might see:
13
+ // • { createLazPerf } — pure-ESM build
14
+ // • { default: { createLazPerf } } — Vite default-wrapper
15
+ // • { default: createLazPerf } — esModuleInterop on a fn
16
+ // • module-as-function (legacy UMD) — `lazPerf` IS the factory
17
+ const ns = (await import('laz-perf'));
18
+ const dflt = ns.default;
19
+ const candidates = [
20
+ ns.createLazPerf,
21
+ typeof dflt === 'object' && dflt !== null ? dflt.createLazPerf : undefined,
22
+ dflt,
23
+ // Some bundlers expose the CJS module as the namespace object itself.
24
+ ns,
25
+ ];
26
+ const factory = candidates.find((c) => typeof c === 'function');
27
+ if (!factory) {
28
+ const keys = Object.keys(ns).join(', ');
29
+ throw new Error(`laz-perf: could not find createLazPerf factory (saw keys: ${keys || '<empty>'})`);
30
+ }
31
+ return factory();
32
+ })();
33
+ }
34
+ return modulePromise;
35
+ }
36
+ export class LazStreamingSource {
37
+ blob;
38
+ downsample;
39
+ label;
40
+ // Populated by open()
41
+ mod = null;
42
+ laszip = null;
43
+ header = null;
44
+ fileBytes = null;
45
+ filePtr = 0;
46
+ pointPtr = 0;
47
+ pointBuffer = null;
48
+ cursor = 0;
49
+ rgbScale = 1;
50
+ constructor(blob, options = {}) {
51
+ this.blob = blob;
52
+ this.downsample = options.downsample ?? { stride: 1 };
53
+ this.label = options.label;
54
+ }
55
+ async open(signal) {
56
+ if (this.header)
57
+ return this.toInfo(this.header);
58
+ abortIfAborted(signal);
59
+ // All allocations happen against locals first; only commit them to
60
+ // `this.*` after every step succeeds. On failure (abort, parse,
61
+ // wasm load), the catch frees the partial state so a retry doesn't
62
+ // hit the early-return at line 1 with a half-open instance.
63
+ let mod;
64
+ let filePtr = 0;
65
+ let pointPtr = 0;
66
+ let laszip;
67
+ try {
68
+ const buf = await this.blob.arrayBuffer();
69
+ abortIfAborted(signal);
70
+ const bytes = new Uint8Array(buf);
71
+ const header = parseLasHeader(bytes);
72
+ mod = await loadLazPerf();
73
+ abortIfAborted(signal);
74
+ filePtr = mod._malloc(bytes.byteLength);
75
+ mod.HEAPU8.set(bytes, filePtr);
76
+ laszip = new mod.LASZip();
77
+ laszip.open(filePtr, bytes.byteLength);
78
+ const pointSize = laszip.getPointLength();
79
+ pointPtr = mod._malloc(pointSize);
80
+ const pointBuffer = new Uint8Array(pointSize);
81
+ let rgbScale = 1;
82
+ if (header.hasRgb) {
83
+ // Forward-only iterator: probe the first ~4096 points, then
84
+ // reset by recreating the LASZip handle.
85
+ const probe = Math.min(4096, header.pointCount);
86
+ const tempBuf = new Uint8Array(probe * pointSize);
87
+ for (let i = 0; i < probe; i++) {
88
+ laszip.getPoint(pointPtr);
89
+ tempBuf.set(mod.HEAPU8.subarray(pointPtr, pointPtr + pointSize), i * pointSize);
90
+ }
91
+ const max = sampleMaxRgbChannel(tempBuf, header);
92
+ rgbScale = max > 0 && max <= 255 ? 65535 / 255 : 1;
93
+ laszip.delete();
94
+ laszip = new mod.LASZip();
95
+ laszip.open(filePtr, bytes.byteLength);
96
+ }
97
+ // Commit — every allocation succeeded.
98
+ this.fileBytes = bytes;
99
+ this.mod = mod;
100
+ this.filePtr = filePtr;
101
+ this.laszip = laszip;
102
+ this.pointPtr = pointPtr;
103
+ this.pointBuffer = pointBuffer;
104
+ this.rgbScale = rgbScale;
105
+ this.header = header;
106
+ this.cursor = 0;
107
+ return this.toInfo(header);
108
+ }
109
+ catch (err) {
110
+ // Partial allocations — free what we got before throwing.
111
+ try {
112
+ laszip?.delete();
113
+ }
114
+ catch { /* cleanup — safe to ignore */ }
115
+ if (mod && pointPtr) {
116
+ try {
117
+ mod._free(pointPtr);
118
+ }
119
+ catch { /* cleanup — safe to ignore */ }
120
+ }
121
+ if (mod && filePtr) {
122
+ try {
123
+ mod._free(filePtr);
124
+ }
125
+ catch { /* cleanup — safe to ignore */ }
126
+ }
127
+ throw err;
128
+ }
129
+ }
130
+ async next(maxPoints, signal) {
131
+ abortIfAborted(signal);
132
+ if (!Number.isFinite(maxPoints) || maxPoints <= 0) {
133
+ throw new Error(`LazStreamingSource: maxPoints must be > 0 (got ${maxPoints})`);
134
+ }
135
+ if (!this.header || !this.mod || !this.laszip || !this.pointBuffer) {
136
+ throw new Error('LazStreamingSource: open() must be awaited before next()');
137
+ }
138
+ const stride = Math.max(1, this.downsample.stride | 0);
139
+ if (this.cursor >= this.header.pointCount)
140
+ return null;
141
+ const pointSize = this.pointBuffer.byteLength;
142
+ const remainingSource = this.header.pointCount - this.cursor;
143
+ const sourceTake = stride === 1
144
+ ? Math.min(maxPoints, remainingSource)
145
+ : Math.min(maxPoints * stride, remainingSource);
146
+ const decodedCount = stride === 1 ? sourceTake : Math.ceil(sourceTake / stride);
147
+ const slab = new Uint8Array(decodedCount * pointSize);
148
+ let writeIdx = 0;
149
+ for (let i = 0; i < sourceTake; i++) {
150
+ this.laszip.getPoint(this.pointPtr);
151
+ // For strided reads, only keep every Nth point.
152
+ if (stride === 1 || i % stride === 0) {
153
+ slab.set(this.mod.HEAPU8.subarray(this.pointPtr, this.pointPtr + pointSize), writeIdx * pointSize);
154
+ writeIdx++;
155
+ }
156
+ }
157
+ this.cursor += sourceTake;
158
+ return decodeLasPoints(slab, this.header, decodedCount, pointSize, this.rgbScale);
159
+ }
160
+ close() {
161
+ try {
162
+ this.laszip?.delete();
163
+ }
164
+ catch {
165
+ /* cleanup — safe to ignore */
166
+ }
167
+ if (this.mod && this.pointPtr) {
168
+ try {
169
+ this.mod._free(this.pointPtr);
170
+ }
171
+ catch { /* cleanup — safe to ignore */ }
172
+ }
173
+ if (this.mod && this.filePtr) {
174
+ try {
175
+ this.mod._free(this.filePtr);
176
+ }
177
+ catch { /* cleanup — safe to ignore */ }
178
+ }
179
+ this.laszip = null;
180
+ this.mod = null;
181
+ this.header = null;
182
+ this.fileBytes = null;
183
+ this.pointBuffer = null;
184
+ this.filePtr = 0;
185
+ this.pointPtr = 0;
186
+ this.cursor = 0;
187
+ }
188
+ toInfo(header) {
189
+ const stride = Math.max(1, this.downsample.stride | 0);
190
+ return {
191
+ totalPointCount: stride === 1 ? header.pointCount : Math.ceil(header.pointCount / stride),
192
+ bbox: header.bbox,
193
+ hasColor: header.hasRgb,
194
+ hasClassification: true,
195
+ hasIntensity: true,
196
+ label: this.label,
197
+ };
198
+ }
199
+ }
200
+ function abortIfAborted(signal) {
201
+ if (signal?.aborted) {
202
+ throw new DOMException('Aborted', 'AbortError');
203
+ }
204
+ }
205
+ //# sourceMappingURL=laz-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laz-source.js","sourceRoot":"","sources":["../../src/streaming/laz-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * PCD (PCL) streaming source — whole-file decode, single chunk.
3
+ *
4
+ * Like PLY, PCD isn't an octree format. The decoder lives in
5
+ * `formats/pcd.ts` and handles ASCII / binary / binary_compressed
6
+ * (LZF). For files past the 25M-point soft cap, `streamPointCloud`
7
+ * applies stride downsampling on the way out.
8
+ */
9
+ import type { DecodedPointChunk } from '../types.js';
10
+ import type { DownsampleHint, PointSourceInfo, StreamingPointSource } from './types.js';
11
+ export declare class PcdStreamingSource implements StreamingPointSource {
12
+ private blob;
13
+ private downsample;
14
+ private label?;
15
+ private chunk;
16
+ private served;
17
+ constructor(blob: Blob, options?: {
18
+ label?: string;
19
+ downsample?: DownsampleHint;
20
+ });
21
+ open(signal?: AbortSignal): Promise<PointSourceInfo>;
22
+ next(maxPoints: number, signal?: AbortSignal): Promise<DecodedPointChunk | null>;
23
+ close(): void;
24
+ }
25
+ //# sourceMappingURL=pcd-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pcd-source.d.ts","sourceRoot":"","sources":["../../src/streaming/pcd-source.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,qBAAa,kBAAmB,YAAW,oBAAoB;IAC7D,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,MAAM,CAAS;gBAEX,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,cAAc,CAAA;KAAO;IAM/E,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IAgBpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAQtF,KAAK,IAAI,IAAI;CAId"}