@ifc-lite/pointcloud 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/formats/ascii-points.d.ts.map +1 -1
- package/dist/formats/ascii-points.js +1 -0
- package/dist/formats/ascii-points.js.map +1 -1
- package/dist/formats/e57-decode.js +1 -1
- package/dist/formats/e57-decode.js.map +1 -1
- package/dist/formats/e57.d.ts.map +1 -1
- package/dist/formats/e57.js +1 -0
- package/dist/formats/e57.js.map +1 -1
- package/dist/formats/ifcx-points.d.ts.map +1 -1
- package/dist/formats/ifcx-points.js +2 -0
- package/dist/formats/ifcx-points.js.map +1 -1
- package/dist/formats/las.d.ts.map +1 -1
- package/dist/formats/las.js +43 -12
- package/dist/formats/las.js.map +1 -1
- package/dist/formats/pcd.js +1 -1
- package/dist/formats/pcd.js.map +1 -1
- package/dist/formats/ply-color.d.ts +2 -0
- package/dist/formats/ply-color.d.ts.map +1 -1
- package/dist/formats/ply-color.js +6 -1
- package/dist/formats/ply-color.js.map +1 -1
- package/dist/formats/ply-fixed-binary.d.ts +9 -0
- package/dist/formats/ply-fixed-binary.d.ts.map +1 -0
- package/dist/formats/ply-fixed-binary.js +60 -0
- package/dist/formats/ply-fixed-binary.js.map +1 -0
- package/dist/formats/ply-scalar.d.ts +6 -0
- package/dist/formats/ply-scalar.d.ts.map +1 -0
- package/dist/formats/ply-scalar.js +25 -0
- package/dist/formats/ply-scalar.js.map +1 -0
- package/dist/formats/ply-variable-row.d.ts +15 -0
- package/dist/formats/ply-variable-row.d.ts.map +1 -0
- package/dist/formats/ply-variable-row.js +66 -0
- package/dist/formats/ply-variable-row.js.map +1 -0
- package/dist/formats/ply.d.ts +36 -10
- package/dist/formats/ply.d.ts.map +1 -1
- package/dist/formats/ply.js +83 -83
- package/dist/formats/ply.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/streaming/ascii-points-source.js +1 -0
- package/dist/streaming/ascii-points-source.js.map +1 -1
- package/dist/streaming/decode-worker.js +2 -1
- package/dist/streaming/decode-worker.js.map +1 -1
- package/dist/streaming/e57-source.js +1 -1
- package/dist/streaming/e57-source.js.map +1 -1
- package/dist/streaming/host.d.ts +3 -0
- package/dist/streaming/host.d.ts.map +1 -1
- package/dist/streaming/host.js +25 -10
- package/dist/streaming/host.js.map +1 -1
- package/dist/streaming/inline-worker.js +1 -1
- package/dist/streaming/pcd-source.js +1 -0
- package/dist/streaming/pcd-source.js.map +1 -1
- package/dist/streaming/ply-source.d.ts +9 -17
- package/dist/streaming/ply-source.d.ts.map +1 -1
- package/dist/streaming/ply-source.js +39 -69
- package/dist/streaming/ply-source.js.map +1 -1
- package/dist/streaming/ply-stream-decode.d.ts +32 -0
- package/dist/streaming/ply-stream-decode.d.ts.map +1 -0
- package/dist/streaming/ply-stream-decode.js +363 -0
- package/dist/streaming/ply-stream-decode.js.map +1 -0
- package/dist/streaming/ply-variable-stream.d.ts +15 -0
- package/dist/streaming/ply-variable-stream.d.ts.map +1 -0
- package/dist/streaming/ply-variable-stream.js +73 -0
- package/dist/streaming/ply-variable-stream.js.map +1 -0
- package/dist/streaming/protocol.d.ts +3 -1
- package/dist/streaming/protocol.d.ts.map +1 -1
- package/dist/streaming/protocol.js +18 -4
- package/dist/streaming/protocol.js.map +1 -1
- package/dist/streaming/stride.d.ts +3 -0
- package/dist/streaming/stride.d.ts.map +1 -0
- package/dist/streaming/stride.js +9 -0
- package/dist/streaming/stride.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pcd-source.js","sourceRoot":"","sources":["../../src/streaming/pcd-source.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pcd-source.js","sourceRoot":"","sources":["../../src/streaming/pcd-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PLY streaming source — whole-file decode, single chunk.
|
|
3
|
-
*
|
|
4
|
-
* PLY isn't an octree format, so we don't get incremental visibility
|
|
5
|
-
* benefits from chunked decode. Reading the whole file once and emitting
|
|
6
|
-
* one chunk is simpler and correct. Memory is still bounded by
|
|
7
|
-
* `streamPointCloud`'s 25M-point cap — for files past that, the stride
|
|
8
|
-
* downsample applies on the way out.
|
|
9
|
-
*/
|
|
10
1
|
import type { DecodedPointChunk } from '../types.js';
|
|
2
|
+
import { type PlyStreamInstrumentation } from './ply-stream-decode.js';
|
|
11
3
|
import type { DownsampleHint, PointSourceInfo, StreamingPointSource } from './types.js';
|
|
12
4
|
export declare class PlyStreamingSource implements StreamingPointSource {
|
|
13
|
-
private blob;
|
|
14
|
-
private downsample;
|
|
15
|
-
private label?;
|
|
16
|
-
private
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
* pattern). */
|
|
20
|
-
private originOffset?;
|
|
5
|
+
private readonly blob;
|
|
6
|
+
private readonly downsample;
|
|
7
|
+
private readonly label?;
|
|
8
|
+
private readonly originOffset?;
|
|
9
|
+
private readonly instrumentation?;
|
|
10
|
+
private reader;
|
|
21
11
|
constructor(blob: Blob, options?: {
|
|
22
12
|
label?: string;
|
|
23
13
|
downsample?: DownsampleHint;
|
|
24
14
|
originOffset?: readonly [number, number, number];
|
|
15
|
+
/** @internal Regression instrumentation; production callers omit it. */
|
|
16
|
+
instrumentation?: PlyStreamInstrumentation;
|
|
25
17
|
});
|
|
26
18
|
open(signal?: AbortSignal): Promise<PointSourceInfo>;
|
|
27
19
|
next(maxPoints: number, signal?: AbortSignal): Promise<DecodedPointChunk | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ply-source.d.ts","sourceRoot":"","sources":["../../src/streaming/ply-source.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ply-source.d.ts","sourceRoot":"","sources":["../../src/streaming/ply-source.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAiC,KAAK,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEtG,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKxF,qBAAa,kBAAmB,YAAW,oBAAoB;IAQ3D,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAoC;IAClE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAA2B;IAC5D,OAAO,CAAC,MAAM,CAA+B;gBAG1B,IAAI,EAAE,IAAI,EAC3B,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,cAAc,CAAC;QAC5B,YAAY,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACjD,wEAAwE;QACxE,eAAe,CAAC,EAAE,wBAAwB,CAAC;KACvC;IAQF,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IA0BpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAKtF,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -1,102 +1,72 @@
|
|
|
1
1
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* PLY streaming source.
|
|
6
|
+
*
|
|
7
|
+
* `open()` scans header and bounds in fixed-size byte windows without
|
|
8
|
+
* allocating point channels. `next()` decodes directly into a bounded output
|
|
9
|
+
* chunk and skips unretained stride rows before allocation. A cap probe and
|
|
10
|
+
* its downsampled reopen therefore never materialise full-count XYZ/RGB/normal
|
|
11
|
+
* arrays.
|
|
12
|
+
*/
|
|
13
|
+
import { inspectPlyVertex, parsePlyHeader } from '../formats/ply.js';
|
|
14
|
+
import { PlyChunkReader, scanPlyBounds } from './ply-stream-decode.js';
|
|
15
|
+
import { normalizePointStride } from './stride.js';
|
|
16
|
+
const HEADER_BYTES = 65_536;
|
|
17
|
+
const HEADER_DECODER = new TextDecoder();
|
|
5
18
|
export class PlyStreamingSource {
|
|
6
19
|
blob;
|
|
7
20
|
downsample;
|
|
8
21
|
label;
|
|
9
|
-
chunk = null;
|
|
10
|
-
served = false;
|
|
11
|
-
/** See `decodePly`'s `originOffset` param (extends #1804's LAS/LAZ
|
|
12
|
-
* pattern). */
|
|
13
22
|
originOffset;
|
|
23
|
+
instrumentation;
|
|
24
|
+
reader = null;
|
|
14
25
|
constructor(blob, options = {}) {
|
|
15
26
|
this.blob = blob;
|
|
16
27
|
this.downsample = options.downsample ?? { stride: 1 };
|
|
17
28
|
this.label = options.label;
|
|
18
29
|
this.originOffset = options.originOffset;
|
|
30
|
+
this.instrumentation = options.instrumentation;
|
|
19
31
|
}
|
|
20
32
|
async open(signal) {
|
|
33
|
+
this.close();
|
|
21
34
|
abortIfAborted(signal);
|
|
22
|
-
const
|
|
35
|
+
const headerBytes = new Uint8Array(await this.blob.slice(0, Math.min(HEADER_BYTES, this.blob.size)).arrayBuffer());
|
|
23
36
|
abortIfAborted(signal);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const header = parsePlyHeader(
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const hasIntensity = !!vertex.properties.find((p) => p.name === 'intensity' || p.name === 'scalar_Intensity');
|
|
35
|
-
// Decode now (we already have all bytes). The cost is amortised over
|
|
36
|
-
// the next() call — caller perceives no extra latency.
|
|
37
|
-
const fullChunk = decodePly(bytes, this.originOffset);
|
|
38
|
-
this.chunk = applyStride(fullChunk, this.downsample.stride);
|
|
37
|
+
if (headerBytes.byteLength === HEADER_BYTES && !hasCompleteHeader(headerBytes)) {
|
|
38
|
+
throw new Error(`PLY: header exceeds the bounded ${HEADER_BYTES}-byte streaming limit`);
|
|
39
|
+
}
|
|
40
|
+
const header = parsePlyHeader(headerBytes);
|
|
41
|
+
const layout = inspectPlyVertex(header);
|
|
42
|
+
const scan = await scanPlyBounds(this.blob, header, layout, this.originOffset, signal);
|
|
43
|
+
const stride = normalizePointStride(this.downsample.stride);
|
|
44
|
+
this.reader = new PlyChunkReader(this.blob, header, layout, stride, this.originOffset, scan.normalState, scan.floatColorsUseByteRange, this.instrumentation);
|
|
45
|
+
const properties = layout.vertex.properties;
|
|
46
|
+
const has = (...names) => properties.some((property) => names.includes(property.name));
|
|
39
47
|
return {
|
|
40
|
-
totalPointCount:
|
|
41
|
-
bbox:
|
|
42
|
-
hasColor:
|
|
48
|
+
totalPointCount: Math.ceil(layout.vertex.count / stride),
|
|
49
|
+
bbox: scan.bbox,
|
|
50
|
+
hasColor: has('red', 'r') && has('green', 'g') && has('blue', 'b'),
|
|
43
51
|
hasClassification: false,
|
|
44
|
-
hasIntensity,
|
|
52
|
+
hasIntensity: has('intensity', 'scalar_Intensity'),
|
|
45
53
|
label: this.label,
|
|
46
54
|
};
|
|
47
55
|
}
|
|
48
56
|
async next(maxPoints, signal) {
|
|
49
|
-
|
|
50
|
-
if (!this.chunk || this.served)
|
|
57
|
+
if (!this.reader)
|
|
51
58
|
return null;
|
|
52
|
-
|
|
53
|
-
this.served = true;
|
|
54
|
-
return this.chunk;
|
|
59
|
+
return this.reader.next(maxPoints, signal);
|
|
55
60
|
}
|
|
56
61
|
close() {
|
|
57
|
-
this.
|
|
58
|
-
this.served = false;
|
|
62
|
+
this.reader = null;
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
if (s === 1)
|
|
64
|
-
return chunk;
|
|
65
|
-
const newCount = Math.ceil(chunk.pointCount / s);
|
|
66
|
-
const positions = new Float32Array(newCount * 3);
|
|
67
|
-
const colors = chunk.colors ? new Float32Array(newCount * 3) : undefined;
|
|
68
|
-
const classifications = chunk.classifications ? new Uint8Array(newCount) : undefined;
|
|
69
|
-
const intensities = chunk.intensities ? new Uint16Array(newCount) : undefined;
|
|
70
|
-
let dst = 0;
|
|
71
|
-
for (let i = 0; i < chunk.pointCount; i += s) {
|
|
72
|
-
positions[dst * 3] = chunk.positions[i * 3];
|
|
73
|
-
positions[dst * 3 + 1] = chunk.positions[i * 3 + 1];
|
|
74
|
-
positions[dst * 3 + 2] = chunk.positions[i * 3 + 2];
|
|
75
|
-
if (colors && chunk.colors) {
|
|
76
|
-
colors[dst * 3] = chunk.colors[i * 3];
|
|
77
|
-
colors[dst * 3 + 1] = chunk.colors[i * 3 + 1];
|
|
78
|
-
colors[dst * 3 + 2] = chunk.colors[i * 3 + 2];
|
|
79
|
-
}
|
|
80
|
-
if (classifications && chunk.classifications) {
|
|
81
|
-
classifications[dst] = chunk.classifications[i];
|
|
82
|
-
}
|
|
83
|
-
if (intensities && chunk.intensities) {
|
|
84
|
-
intensities[dst] = chunk.intensities[i];
|
|
85
|
-
}
|
|
86
|
-
dst++;
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
positions,
|
|
90
|
-
colors,
|
|
91
|
-
classifications,
|
|
92
|
-
intensities,
|
|
93
|
-
pointCount: newCount,
|
|
94
|
-
bbox: chunk.bbox,
|
|
95
|
-
};
|
|
65
|
+
function hasCompleteHeader(bytes) {
|
|
66
|
+
return /(?:^|\n)[\t ]*end_header[\t ]*\r?\n/.test(HEADER_DECODER.decode(bytes));
|
|
96
67
|
}
|
|
97
68
|
function abortIfAborted(signal) {
|
|
98
|
-
if (signal?.aborted)
|
|
69
|
+
if (signal?.aborted)
|
|
99
70
|
throw new DOMException('Aborted', 'AbortError');
|
|
100
|
-
}
|
|
101
71
|
}
|
|
102
72
|
//# sourceMappingURL=ply-source.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ply-source.js","sourceRoot":"","sources":["../../src/streaming/ply-source.ts"],"names":[],"mappings":"AAAA;;+DAE+D;
|
|
1
|
+
{"version":3,"file":"ply-source.js","sourceRoot":"","sources":["../../src/streaming/ply-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DecodedPointChunk, PointCloudBBox, PointNormalState } from '../types.js';
|
|
2
|
+
import type { PlyHeader, PlyVertexLayout } from '../formats/ply.js';
|
|
3
|
+
export declare const PLY_STREAM_READ_BYTES: number;
|
|
4
|
+
export interface PlyStreamInstrumentation {
|
|
5
|
+
/** Test-only observation of output channel capacity; no source-count buffer is allocated. */
|
|
6
|
+
onOutputAllocation?: (pointCapacity: number) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function scanPlyBounds(blob: Blob, header: PlyHeader, layout: PlyVertexLayout, origin: readonly [number, number, number] | undefined, signal?: AbortSignal): Promise<{
|
|
9
|
+
bbox: PointCloudBBox;
|
|
10
|
+
normalState: PointNormalState;
|
|
11
|
+
floatColorsUseByteRange: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
export declare class PlyChunkReader {
|
|
14
|
+
private readonly blob;
|
|
15
|
+
private readonly header;
|
|
16
|
+
private readonly layout;
|
|
17
|
+
private readonly stride;
|
|
18
|
+
private readonly origin;
|
|
19
|
+
private readonly normalState;
|
|
20
|
+
private readonly floatColorsUseByteRange;
|
|
21
|
+
private readonly instrumentation?;
|
|
22
|
+
private sourceRow;
|
|
23
|
+
private readonly ascii;
|
|
24
|
+
private readonly channels;
|
|
25
|
+
private readonly variableBinary;
|
|
26
|
+
constructor(blob: Blob, header: PlyHeader, layout: PlyVertexLayout, stride: number, origin: readonly [number, number, number] | undefined, normalState: PointNormalState, floatColorsUseByteRange: boolean, instrumentation?: PlyStreamInstrumentation | undefined);
|
|
27
|
+
next(maxPoints: number, signal?: AbortSignal): Promise<DecodedPointChunk | null>;
|
|
28
|
+
private readBinary;
|
|
29
|
+
private readVariableBinary;
|
|
30
|
+
private readAscii;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ply-stream-decode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ply-stream-decode.d.ts","sourceRoot":"","sources":["../../src/streaming/ply-stream-decode.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,KAAK,EAAE,SAAS,EAAmB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGrF,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAQrD,MAAM,WAAW,wBAAwB;IACvC,6FAA6F;IAC7F,kBAAkB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACrD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,gBAAgB,CAAC;IAAC,uBAAuB,EAAE,OAAO,CAAA;CAAE,CAAC,CA2DpG;AAED,qBAAa,cAAc;IAOvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IAbnC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;gBAGxC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACrD,WAAW,EAAE,gBAAgB,EAC7B,uBAAuB,EAAE,OAAO,EAChC,eAAe,CAAC,EAAE,wBAAwB,YAAA;IAQvD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAexE,UAAU;YA2BV,kBAAkB;YAUlB,SAAS;CAkBxB"}
|
|
@@ -0,0 +1,363 @@
|
|
|
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 { floatColorSelectsByteRange, normalizeColorChannel } from '../formats/ply-color.js';
|
|
5
|
+
import { readPlyScalar } from '../formats/ply-scalar.js';
|
|
6
|
+
import { parseAsciiVariableRow, writeVariablePlyRow } from '../formats/ply-variable-row.js';
|
|
7
|
+
import { BinaryPlyRowCursor } from './ply-variable-stream.js';
|
|
8
|
+
export const PLY_STREAM_READ_BYTES = 4 * 1024 * 1024;
|
|
9
|
+
const TEXT_DECODER = new TextDecoder();
|
|
10
|
+
export async function scanPlyBounds(blob, header, layout, origin, signal) {
|
|
11
|
+
if (!Number.isSafeInteger(layout.vertex.count) || layout.vertex.count < 0) {
|
|
12
|
+
throw new Error(`PLY: invalid vertex count ${layout.vertex.count}`);
|
|
13
|
+
}
|
|
14
|
+
const bounds = emptyBounds();
|
|
15
|
+
let normalState = layout.normalState;
|
|
16
|
+
let floatColorsUseByteRange = false;
|
|
17
|
+
const channels = findChannels(layout);
|
|
18
|
+
if (header.format === 'ascii') {
|
|
19
|
+
const cursor = new AsciiLineCursor(blob, header.bodyOffset);
|
|
20
|
+
const indices = positionColumns(layout);
|
|
21
|
+
for (let row = 0; row < layout.vertex.count; row++) {
|
|
22
|
+
abortIfAborted(signal);
|
|
23
|
+
const line = await cursor.next(signal);
|
|
24
|
+
if (line === null)
|
|
25
|
+
throw new Error(`PLY ascii: expected ${layout.vertex.count} vertex lines, got ${row}`);
|
|
26
|
+
const parts = line.split(/\s+/);
|
|
27
|
+
if (layout.vertex.hasListProperty) {
|
|
28
|
+
const values = parseAsciiVariableRow(parts, layout.vertex.propertyOrder, row);
|
|
29
|
+
extendBounds(bounds, (values.get('x') ?? Number.NaN) - (origin?.[0] ?? 0), (values.get('y') ?? Number.NaN) - (origin?.[1] ?? 0), (values.get('z') ?? Number.NaN) - (origin?.[2] ?? 0));
|
|
30
|
+
normalState = observeValues(values, normalState);
|
|
31
|
+
floatColorsUseByteRange ||= valuesUseByteColors(values, channels);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
requireColumns(parts, layout.vertex.properties.length, row);
|
|
35
|
+
extendBounds(bounds, Number(parts[indices[0]]) - (origin?.[0] ?? 0), Number(parts[indices[1]]) - (origin?.[1] ?? 0), Number(parts[indices[2]]) - (origin?.[2] ?? 0));
|
|
36
|
+
normalState = observeAsciiRow(parts, layout, channels, normalState);
|
|
37
|
+
floatColorsUseByteRange ||= asciiUsesByteColors(parts, layout, channels);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
if (layout.vertex.hasListProperty) {
|
|
43
|
+
const cursor = new BinaryPlyRowCursor(blob, header.bodyOffset, header.format === 'binary_little_endian');
|
|
44
|
+
for (let row = 0; row < layout.vertex.count; row++) {
|
|
45
|
+
const values = await cursor.row(layout.vertex.propertyOrder, row, signal);
|
|
46
|
+
extendBounds(bounds, (values.get('x') ?? Number.NaN) - (origin?.[0] ?? 0), (values.get('y') ?? Number.NaN) - (origin?.[1] ?? 0), (values.get('z') ?? Number.NaN) - (origin?.[2] ?? 0));
|
|
47
|
+
normalState = observeValues(values, normalState);
|
|
48
|
+
floatColorsUseByteRange ||= valuesUseByteColors(values, channels);
|
|
49
|
+
}
|
|
50
|
+
return { bbox: bounds, normalState, floatColorsUseByteRange };
|
|
51
|
+
}
|
|
52
|
+
const recordSize = layout.vertex.recordSize;
|
|
53
|
+
const bodyBytes = layout.vertex.count * recordSize;
|
|
54
|
+
const requiredEnd = header.bodyOffset + bodyBytes;
|
|
55
|
+
if (!Number.isSafeInteger(bodyBytes) || !Number.isSafeInteger(requiredEnd))
|
|
56
|
+
throw new Error('PLY: binary vertex byte span exceeds the safe integer range');
|
|
57
|
+
if (blob.size < requiredEnd)
|
|
58
|
+
throw new Error(`PLY binary: expected ${layout.vertex.count * recordSize} body bytes, got ${blob.size - header.bodyOffset}`);
|
|
59
|
+
const recordsPerRead = Math.max(1, Math.floor(PLY_STREAM_READ_BYTES / recordSize));
|
|
60
|
+
for (let first = 0; first < layout.vertex.count; first += recordsPerRead) {
|
|
61
|
+
abortIfAborted(signal);
|
|
62
|
+
const count = Math.min(recordsPerRead, layout.vertex.count - first);
|
|
63
|
+
const bytes = await readSlice(blob, header.bodyOffset + first * recordSize, count * recordSize, signal);
|
|
64
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
65
|
+
for (let row = 0; row < count; row++) {
|
|
66
|
+
const base = row * recordSize;
|
|
67
|
+
extendBinaryBounds(bounds, view, base, layout, header, origin);
|
|
68
|
+
normalState = observeBinaryRow(view, base, layout, header, normalState);
|
|
69
|
+
floatColorsUseByteRange ||= binaryUsesByteColors(view, base, layout, channels, header);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { bbox: bounds, normalState, floatColorsUseByteRange };
|
|
74
|
+
}
|
|
75
|
+
export class PlyChunkReader {
|
|
76
|
+
blob;
|
|
77
|
+
header;
|
|
78
|
+
layout;
|
|
79
|
+
stride;
|
|
80
|
+
origin;
|
|
81
|
+
normalState;
|
|
82
|
+
floatColorsUseByteRange;
|
|
83
|
+
instrumentation;
|
|
84
|
+
sourceRow = 0;
|
|
85
|
+
ascii;
|
|
86
|
+
channels;
|
|
87
|
+
variableBinary;
|
|
88
|
+
constructor(blob, header, layout, stride, origin, normalState, floatColorsUseByteRange, instrumentation) {
|
|
89
|
+
this.blob = blob;
|
|
90
|
+
this.header = header;
|
|
91
|
+
this.layout = layout;
|
|
92
|
+
this.stride = stride;
|
|
93
|
+
this.origin = origin;
|
|
94
|
+
this.normalState = normalState;
|
|
95
|
+
this.floatColorsUseByteRange = floatColorsUseByteRange;
|
|
96
|
+
this.instrumentation = instrumentation;
|
|
97
|
+
this.ascii = header.format === 'ascii' ? new AsciiLineCursor(blob, header.bodyOffset) : null;
|
|
98
|
+
this.variableBinary = header.format !== 'ascii' && layout.vertex.hasListProperty
|
|
99
|
+
? new BinaryPlyRowCursor(blob, header.bodyOffset, header.format === 'binary_little_endian') : null;
|
|
100
|
+
this.channels = findChannels(layout);
|
|
101
|
+
}
|
|
102
|
+
async next(maxPoints, signal) {
|
|
103
|
+
abortIfAborted(signal);
|
|
104
|
+
if (this.sourceRow >= this.layout.vertex.count)
|
|
105
|
+
return null;
|
|
106
|
+
const limit = Math.max(1, Math.floor(maxPoints));
|
|
107
|
+
const remainingOutput = countRetainedRows(this.sourceRow, this.layout.vertex.count, this.stride);
|
|
108
|
+
if (remainingOutput === 0)
|
|
109
|
+
return null;
|
|
110
|
+
const capacity = Math.min(limit, remainingOutput);
|
|
111
|
+
this.instrumentation?.onOutputAllocation?.(capacity);
|
|
112
|
+
const output = allocateChunk(capacity, this.layout, this.channels, this.normalState);
|
|
113
|
+
const written = this.ascii
|
|
114
|
+
? await this.readAscii(output, capacity, signal)
|
|
115
|
+
: await this.readBinary(output, capacity, signal);
|
|
116
|
+
return finishChunk(output, written, this.channels, this.floatColorsUseByteRange);
|
|
117
|
+
}
|
|
118
|
+
async readBinary(output, capacity, signal) {
|
|
119
|
+
if (this.variableBinary)
|
|
120
|
+
return this.readVariableBinary(output, capacity, signal);
|
|
121
|
+
const recordSize = this.layout.vertex.recordSize;
|
|
122
|
+
const recordsPerRead = Math.max(1, Math.floor(PLY_STREAM_READ_BYTES / recordSize));
|
|
123
|
+
let written = 0;
|
|
124
|
+
while (written < capacity && this.sourceRow < this.layout.vertex.count) {
|
|
125
|
+
this.sourceRow += (this.stride - (this.sourceRow % this.stride)) % this.stride;
|
|
126
|
+
if (this.sourceRow >= this.layout.vertex.count)
|
|
127
|
+
break;
|
|
128
|
+
const sourceTake = Math.min(recordsPerRead, this.layout.vertex.count - this.sourceRow);
|
|
129
|
+
const bytes = await readSlice(this.blob, this.header.bodyOffset + this.sourceRow * recordSize, sourceTake * recordSize, signal);
|
|
130
|
+
if (bytes.byteLength !== sourceTake * recordSize) {
|
|
131
|
+
throw new Error(`PLY binary: expected ${sourceTake * recordSize} body bytes, got ${bytes.byteLength}`);
|
|
132
|
+
}
|
|
133
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
134
|
+
let processed = 0;
|
|
135
|
+
while (processed < sourceTake && written < capacity) {
|
|
136
|
+
const globalRow = this.sourceRow + processed;
|
|
137
|
+
if (globalRow % this.stride === 0) {
|
|
138
|
+
writeBinaryRow(output, written++, view, processed * recordSize, this.layout, this.channels, this.header, this.origin);
|
|
139
|
+
}
|
|
140
|
+
processed++;
|
|
141
|
+
}
|
|
142
|
+
this.sourceRow += processed;
|
|
143
|
+
}
|
|
144
|
+
return written;
|
|
145
|
+
}
|
|
146
|
+
async readVariableBinary(output, capacity, signal) {
|
|
147
|
+
let written = 0;
|
|
148
|
+
while (written < capacity && this.sourceRow < this.layout.vertex.count) {
|
|
149
|
+
const values = await this.variableBinary.row(this.layout.vertex.propertyOrder, this.sourceRow, signal);
|
|
150
|
+
if (this.sourceRow % this.stride === 0)
|
|
151
|
+
writeVariablePlyRow(values, written++, { ...output, originOffset: this.origin });
|
|
152
|
+
this.sourceRow++;
|
|
153
|
+
}
|
|
154
|
+
return written;
|
|
155
|
+
}
|
|
156
|
+
async readAscii(output, capacity, signal) {
|
|
157
|
+
const columns = asciiColumns(this.layout, this.channels);
|
|
158
|
+
let written = 0;
|
|
159
|
+
while (written < capacity && this.sourceRow < this.layout.vertex.count) {
|
|
160
|
+
const line = await this.ascii.next(signal);
|
|
161
|
+
if (line === null)
|
|
162
|
+
throw new Error(`PLY ascii: expected ${this.layout.vertex.count} vertex lines, got ${this.sourceRow}`);
|
|
163
|
+
const parts = line.split(/\s+/);
|
|
164
|
+
if (this.layout.vertex.hasListProperty) {
|
|
165
|
+
const values = parseAsciiVariableRow(parts, this.layout.vertex.propertyOrder, this.sourceRow);
|
|
166
|
+
if (this.sourceRow % this.stride === 0)
|
|
167
|
+
writeVariablePlyRow(values, written++, { ...output, originOffset: this.origin });
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
requireColumns(parts, this.layout.vertex.properties.length, this.sourceRow);
|
|
171
|
+
if (this.sourceRow % this.stride === 0)
|
|
172
|
+
writeAsciiRow(output, written++, parts, columns, this.origin);
|
|
173
|
+
}
|
|
174
|
+
this.sourceRow++;
|
|
175
|
+
}
|
|
176
|
+
return written;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
class AsciiLineCursor {
|
|
180
|
+
blob;
|
|
181
|
+
byteOffset;
|
|
182
|
+
pending = '';
|
|
183
|
+
pendingOffset = 0;
|
|
184
|
+
eof = false;
|
|
185
|
+
constructor(blob, bodyOffset) {
|
|
186
|
+
this.blob = blob;
|
|
187
|
+
this.byteOffset = bodyOffset;
|
|
188
|
+
}
|
|
189
|
+
async next(signal) {
|
|
190
|
+
while (true) {
|
|
191
|
+
const newline = this.pending.indexOf('\n', this.pendingOffset);
|
|
192
|
+
if (newline >= 0) {
|
|
193
|
+
const line = this.pending.slice(this.pendingOffset, newline).trim();
|
|
194
|
+
this.pendingOffset = newline + 1;
|
|
195
|
+
this.compact();
|
|
196
|
+
if (line)
|
|
197
|
+
return line;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (this.eof) {
|
|
201
|
+
const line = this.pending.slice(this.pendingOffset).trim();
|
|
202
|
+
this.pendingOffset = this.pending.length;
|
|
203
|
+
return line || null;
|
|
204
|
+
}
|
|
205
|
+
if (this.pending.length - this.pendingOffset >= PLY_STREAM_READ_BYTES * 2) {
|
|
206
|
+
throw new Error('PLY ascii: vertex row exceeds the bounded 8 MiB line limit');
|
|
207
|
+
}
|
|
208
|
+
abortIfAborted(signal);
|
|
209
|
+
const end = Math.min(this.blob.size, this.byteOffset + PLY_STREAM_READ_BYTES);
|
|
210
|
+
const bytes = await readSlice(this.blob, this.byteOffset, end - this.byteOffset, signal);
|
|
211
|
+
this.byteOffset = end;
|
|
212
|
+
this.pending += TEXT_DECODER.decode(bytes);
|
|
213
|
+
this.eof = end >= this.blob.size;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
compact() {
|
|
217
|
+
if (this.pendingOffset < PLY_STREAM_READ_BYTES)
|
|
218
|
+
return;
|
|
219
|
+
this.pending = this.pending.slice(this.pendingOffset);
|
|
220
|
+
this.pendingOffset = 0;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function allocateChunk(capacity, layout, channels, normalState) {
|
|
224
|
+
return {
|
|
225
|
+
positions: new Float32Array(capacity * 3),
|
|
226
|
+
colors: channels.r && channels.g && channels.b ? new Float32Array(capacity * 3) : undefined,
|
|
227
|
+
normals: layout.nxProp && layout.nyProp && layout.nzProp ? new Float32Array(capacity * 3) : undefined,
|
|
228
|
+
normalState,
|
|
229
|
+
intensities: channels.intensity ? new Uint16Array(capacity) : undefined,
|
|
230
|
+
pointCount: capacity,
|
|
231
|
+
bbox: emptyBounds(),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function finishChunk(output, written, channels, floatColorsUseByteRange) {
|
|
235
|
+
if (output.colors && channels.r && channels.g && channels.b) {
|
|
236
|
+
const types = [channels.r.type, channels.g.type, channels.b.type];
|
|
237
|
+
for (let i = 0; i < output.colors.length; i++)
|
|
238
|
+
output.colors[i] = normalizeColorChannel(output.colors[i], types[i % 3], floatColorsUseByteRange);
|
|
239
|
+
}
|
|
240
|
+
output.pointCount = written;
|
|
241
|
+
output.bbox = computeBounds(output.positions, written);
|
|
242
|
+
if (written === output.positions.length / 3)
|
|
243
|
+
return output;
|
|
244
|
+
output.positions = output.positions.slice(0, written * 3);
|
|
245
|
+
if (output.colors)
|
|
246
|
+
output.colors = output.colors.slice(0, written * 3);
|
|
247
|
+
if (output.normals)
|
|
248
|
+
output.normals = output.normals.slice(0, written * 3);
|
|
249
|
+
if (output.intensities)
|
|
250
|
+
output.intensities = output.intensities.slice(0, written);
|
|
251
|
+
return output;
|
|
252
|
+
}
|
|
253
|
+
function writeBinaryRow(output, dst, view, base, layout, channels, header, origin) {
|
|
254
|
+
const le = header.format === 'binary_little_endian';
|
|
255
|
+
output.positions[dst * 3] = scalar(view, base, layout.xProp, le) - (origin?.[0] ?? 0);
|
|
256
|
+
output.positions[dst * 3 + 1] = scalar(view, base, layout.yProp, le) - (origin?.[1] ?? 0);
|
|
257
|
+
output.positions[dst * 3 + 2] = scalar(view, base, layout.zProp, le) - (origin?.[2] ?? 0);
|
|
258
|
+
if (output.colors && channels.r && channels.g && channels.b) {
|
|
259
|
+
output.colors[dst * 3] = scalar(view, base, channels.r, le);
|
|
260
|
+
output.colors[dst * 3 + 1] = scalar(view, base, channels.g, le);
|
|
261
|
+
output.colors[dst * 3 + 2] = scalar(view, base, channels.b, le);
|
|
262
|
+
}
|
|
263
|
+
if (output.normals && layout.nxProp && layout.nyProp && layout.nzProp) {
|
|
264
|
+
output.normals[dst * 3] = scalar(view, base, layout.nxProp, le);
|
|
265
|
+
output.normals[dst * 3 + 1] = scalar(view, base, layout.nyProp, le);
|
|
266
|
+
output.normals[dst * 3 + 2] = scalar(view, base, layout.nzProp, le);
|
|
267
|
+
}
|
|
268
|
+
if (output.intensities && channels.intensity)
|
|
269
|
+
output.intensities[dst] = clampIntensity(scalar(view, base, channels.intensity, le));
|
|
270
|
+
}
|
|
271
|
+
function writeAsciiRow(output, dst, parts, columns, origin) {
|
|
272
|
+
output.positions[dst * 3] = Number(parts[columns.x]) - (origin?.[0] ?? 0);
|
|
273
|
+
output.positions[dst * 3 + 1] = Number(parts[columns.y]) - (origin?.[1] ?? 0);
|
|
274
|
+
output.positions[dst * 3 + 2] = Number(parts[columns.z]) - (origin?.[2] ?? 0);
|
|
275
|
+
if (output.colors) {
|
|
276
|
+
output.colors[dst * 3] = Number(parts[columns.r]);
|
|
277
|
+
output.colors[dst * 3 + 1] = Number(parts[columns.g]);
|
|
278
|
+
output.colors[dst * 3 + 2] = Number(parts[columns.b]);
|
|
279
|
+
}
|
|
280
|
+
if (output.normals) {
|
|
281
|
+
output.normals[dst * 3] = Number(parts[columns.nx]);
|
|
282
|
+
output.normals[dst * 3 + 1] = Number(parts[columns.ny]);
|
|
283
|
+
output.normals[dst * 3 + 2] = Number(parts[columns.nz]);
|
|
284
|
+
}
|
|
285
|
+
if (output.intensities)
|
|
286
|
+
output.intensities[dst] = clampIntensity(Number(parts[columns.intensity]));
|
|
287
|
+
}
|
|
288
|
+
function extendBinaryBounds(bounds, view, base, layout, header, origin) {
|
|
289
|
+
const le = header.format === 'binary_little_endian';
|
|
290
|
+
extendBounds(bounds, readPlyScalar(view, base + layout.xProp.offset, layout.xProp, le) - (origin?.[0] ?? 0), readPlyScalar(view, base + layout.yProp.offset, layout.yProp, le) - (origin?.[1] ?? 0), readPlyScalar(view, base + layout.zProp.offset, layout.zProp, le) - (origin?.[2] ?? 0));
|
|
291
|
+
}
|
|
292
|
+
function findChannels(layout) {
|
|
293
|
+
const find = (...names) => layout.vertex.properties.find((property) => names.includes(property.name));
|
|
294
|
+
return { r: find('red', 'r'), g: find('green', 'g'), b: find('blue', 'b'), intensity: find('intensity', 'scalar_Intensity') };
|
|
295
|
+
}
|
|
296
|
+
function usableNormal(x, y, z) {
|
|
297
|
+
const stored = [Math.fround(x), Math.fround(y), Math.fround(z)];
|
|
298
|
+
return stored.every(Number.isFinite) && stored.some(value => value !== 0);
|
|
299
|
+
}
|
|
300
|
+
function observeValues(values, state) {
|
|
301
|
+
if (state !== 'supplied')
|
|
302
|
+
return state;
|
|
303
|
+
return usableNormal(values.get('nx') ?? Number.NaN, values.get('ny') ?? Number.NaN, values.get('nz') ?? Number.NaN) ? state : 'invalid';
|
|
304
|
+
}
|
|
305
|
+
function valuesUseByteColors(values, channels) {
|
|
306
|
+
return [channels.r, channels.g, channels.b].some(property => property
|
|
307
|
+
&& floatColorSelectsByteRange(values.get(property.name) ?? Number.NaN, property.type));
|
|
308
|
+
}
|
|
309
|
+
function observeAsciiRow(parts, layout, _channels, state) {
|
|
310
|
+
if (state !== 'supplied' || !layout.nxProp || !layout.nyProp || !layout.nzProp)
|
|
311
|
+
return state;
|
|
312
|
+
const index = (property) => layout.vertex.properties.indexOf(property);
|
|
313
|
+
return usableNormal(Number(parts[index(layout.nxProp)]), Number(parts[index(layout.nyProp)]), Number(parts[index(layout.nzProp)])) ? state : 'invalid';
|
|
314
|
+
}
|
|
315
|
+
function observeBinaryRow(view, base, layout, header, state) {
|
|
316
|
+
if (state !== 'supplied' || !layout.nxProp || !layout.nyProp || !layout.nzProp)
|
|
317
|
+
return state;
|
|
318
|
+
const le = header.format === 'binary_little_endian';
|
|
319
|
+
return usableNormal(scalar(view, base, layout.nxProp, le), scalar(view, base, layout.nyProp, le), scalar(view, base, layout.nzProp, le)) ? state : 'invalid';
|
|
320
|
+
}
|
|
321
|
+
function asciiUsesByteColors(parts, layout, channels) {
|
|
322
|
+
return [channels.r, channels.g, channels.b].some((property) => property
|
|
323
|
+
&& floatColorSelectsByteRange(Number(parts[layout.vertex.properties.indexOf(property)]), property.type));
|
|
324
|
+
}
|
|
325
|
+
function binaryUsesByteColors(view, base, layout, channels, header) {
|
|
326
|
+
const le = header.format === 'binary_little_endian';
|
|
327
|
+
return [channels.r, channels.g, channels.b].some((property) => property
|
|
328
|
+
&& floatColorSelectsByteRange(scalar(view, base, property, le), property.type));
|
|
329
|
+
}
|
|
330
|
+
function positionColumns(layout) { return [layout.vertex.properties.indexOf(layout.xProp), layout.vertex.properties.indexOf(layout.yProp), layout.vertex.properties.indexOf(layout.zProp)]; }
|
|
331
|
+
function asciiColumns(layout, channels) {
|
|
332
|
+
const index = (property) => property ? layout.vertex.properties.indexOf(property) : -1;
|
|
333
|
+
return { x: index(layout.xProp), y: index(layout.yProp), z: index(layout.zProp), r: index(channels.r), g: index(channels.g), b: index(channels.b), nx: index(layout.nxProp), ny: index(layout.nyProp), nz: index(layout.nzProp), intensity: index(channels.intensity) };
|
|
334
|
+
}
|
|
335
|
+
function requireColumns(parts, count, row) { if (parts.length < count)
|
|
336
|
+
throw new Error(`PLY ascii: vertex row ${row + 1} has ${parts.length} values; expected ${count}`); }
|
|
337
|
+
function clampIntensity(value) { return Math.min(65535, Math.max(0, value | 0)); }
|
|
338
|
+
function scalar(view, base, property, le) { return readPlyScalar(view, base + property.offset, property, le); }
|
|
339
|
+
function countRetainedRows(first, count, stride) {
|
|
340
|
+
const aligned = first + ((stride - (first % stride)) % stride);
|
|
341
|
+
return aligned >= count ? 0 : Math.floor((count - 1 - aligned) / stride) + 1;
|
|
342
|
+
}
|
|
343
|
+
function emptyBounds() { return { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] }; }
|
|
344
|
+
function extendBounds(bounds, x, y, z) {
|
|
345
|
+
if (x < bounds.min[0])
|
|
346
|
+
bounds.min[0] = x;
|
|
347
|
+
if (x > bounds.max[0])
|
|
348
|
+
bounds.max[0] = x;
|
|
349
|
+
if (y < bounds.min[1])
|
|
350
|
+
bounds.min[1] = y;
|
|
351
|
+
if (y > bounds.max[1])
|
|
352
|
+
bounds.max[1] = y;
|
|
353
|
+
if (z < bounds.min[2])
|
|
354
|
+
bounds.min[2] = z;
|
|
355
|
+
if (z > bounds.max[2])
|
|
356
|
+
bounds.max[2] = z;
|
|
357
|
+
}
|
|
358
|
+
function computeBounds(positions, count) { const bounds = emptyBounds(); for (let i = 0; i < count; i++)
|
|
359
|
+
extendBounds(bounds, positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]); return bounds; }
|
|
360
|
+
async function readSlice(blob, offset, length, signal) { abortIfAborted(signal); const bytes = new Uint8Array(await blob.slice(offset, offset + length).arrayBuffer()); abortIfAborted(signal); return bytes; }
|
|
361
|
+
function abortIfAborted(signal) { if (signal?.aborted)
|
|
362
|
+
throw new DOMException('Aborted', 'AbortError'); }
|
|
363
|
+
//# sourceMappingURL=ply-stream-decode.js.map
|