@loaders.gl/las 4.4.0-alpha.1 → 4.4.0-alpha.11

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 (89) hide show
  1. package/dist/dist.dev.js +1022 -77
  2. package/dist/dist.min.js +21 -21
  3. package/dist/index.cjs +1024 -79
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +4 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +7 -1
  8. package/dist/index.js.map +1 -0
  9. package/dist/las-arrow-loader.d.ts +10 -8
  10. package/dist/las-arrow-loader.d.ts.map +1 -1
  11. package/dist/las-arrow-loader.js +5 -4
  12. package/dist/las-arrow-loader.js.map +1 -0
  13. package/dist/las-format.d.ts +2 -2
  14. package/dist/las-format.js +3 -2
  15. package/dist/las-format.js.map +1 -0
  16. package/dist/las-loader.d.ts +2 -31
  17. package/dist/las-loader.d.ts.map +1 -1
  18. package/dist/las-loader.js +2 -20
  19. package/dist/las-loader.js.map +1 -0
  20. package/dist/las-worker.js +65 -71
  21. package/dist/laz-rs-loader.d.ts +29 -0
  22. package/dist/laz-rs-loader.d.ts.map +1 -0
  23. package/dist/laz-rs-loader.js +17 -0
  24. package/dist/laz-rs-loader.js.map +1 -0
  25. package/dist/lazperf-loader.d.ts +31 -0
  26. package/dist/lazperf-loader.d.ts.map +1 -0
  27. package/dist/lazperf-loader.js +15 -0
  28. package/dist/lazperf-loader.js.map +1 -0
  29. package/dist/lib/get-las-schema.d.ts +1 -1
  30. package/dist/lib/get-las-schema.js +2 -1
  31. package/dist/lib/get-las-schema.js.map +1 -0
  32. package/dist/lib/las-types.d.ts +1 -0
  33. package/dist/lib/las-types.d.ts.map +1 -1
  34. package/dist/lib/las-types.js +1 -0
  35. package/dist/lib/las-types.js.map +1 -0
  36. package/dist/lib/{laslaz-decoder.d.ts → laz-perf/laslaz-decoder.d.ts} +1 -1
  37. package/dist/lib/laz-perf/laslaz-decoder.d.ts.map +1 -0
  38. package/dist/lib/{laslaz-decoder.js → laz-perf/laslaz-decoder.js} +4 -2
  39. package/dist/lib/laz-perf/laslaz-decoder.js.map +1 -0
  40. package/dist/lib/{parse-las.d.ts → laz-perf/parse-las.d.ts} +3 -3
  41. package/dist/lib/laz-perf/parse-las.d.ts.map +1 -0
  42. package/dist/lib/{parse-las.js → laz-perf/parse-las.js} +6 -6
  43. package/dist/lib/laz-perf/parse-las.js.map +1 -0
  44. package/dist/lib/laz-rs-wasm/laslaz-decoder.d.ts +134 -0
  45. package/dist/lib/laz-rs-wasm/laslaz-decoder.d.ts.map +1 -0
  46. package/dist/lib/laz-rs-wasm/laslaz-decoder.js +446 -0
  47. package/dist/lib/laz-rs-wasm/laslaz-decoder.js.map +1 -0
  48. package/dist/lib/laz-rs-wasm/parse-las.d.ts +18 -0
  49. package/dist/lib/laz-rs-wasm/parse-las.d.ts.map +1 -0
  50. package/dist/lib/laz-rs-wasm/parse-las.js +188 -0
  51. package/dist/lib/laz-rs-wasm/parse-las.js.map +1 -0
  52. package/dist/libs/laz-perf/laz-perf.d.ts.map +1 -0
  53. package/dist/{lib/libs → libs/laz-perf}/laz-perf.js +1 -0
  54. package/dist/libs/laz-perf/laz-perf.js.map +1 -0
  55. package/dist/libs/laz-rs-wasm/laz_rs_wasm.d.ts +95 -0
  56. package/dist/libs/laz-rs-wasm/laz_rs_wasm.d.ts.map +1 -0
  57. package/dist/libs/laz-rs-wasm/laz_rs_wasm.js +425 -0
  58. package/dist/libs/laz-rs-wasm/laz_rs_wasm.js.map +1 -0
  59. package/dist/libs/libs/laz-rs-wasm/laz_rs_wasm.d.ts +80 -0
  60. package/dist/libs/libs/laz-rs-wasm/laz_rs_wasm.js +477 -0
  61. package/dist/libs/libs/laz-rs-wasm/laz_rs_wasm_bg.wasm +0 -0
  62. package/dist/libs/libs/laz-rs-wasm/laz_rs_wasm_bg.wasm.d.ts +31 -0
  63. package/dist/libs/libs/laz-rs-wasm/package.json +19 -0
  64. package/dist/workers/las-worker.js +1 -0
  65. package/dist/workers/las-worker.js.map +1 -0
  66. package/package.json +11 -7
  67. package/src/index.ts +8 -1
  68. package/src/las-arrow-loader.ts +6 -5
  69. package/src/las-format.ts +2 -2
  70. package/src/las-loader.ts +1 -23
  71. package/src/laz-rs-loader.ts +22 -0
  72. package/src/lazperf-loader.ts +22 -0
  73. package/src/lib/get-las-schema.ts +1 -1
  74. package/src/lib/las-types.ts +1 -0
  75. package/src/lib/{laslaz-decoder.ts → laz-perf/laslaz-decoder.ts} +4 -3
  76. package/src/lib/{parse-las.ts → laz-perf/parse-las.ts} +7 -10
  77. package/src/lib/laz-rs-wasm/laslaz-decoder.ts +528 -0
  78. package/src/lib/laz-rs-wasm/parse-las.ts +232 -0
  79. package/src/libs/laz-perf/laz-perf.ts +20616 -0
  80. package/src/libs/laz-rs-wasm/laz_rs_wasm.d.ts +80 -0
  81. package/src/libs/laz-rs-wasm/laz_rs_wasm.js +477 -0
  82. package/src/libs/laz-rs-wasm/laz_rs_wasm_bg.wasm +0 -0
  83. package/src/libs/laz-rs-wasm/laz_rs_wasm_bg.wasm.d.ts +31 -0
  84. package/src/libs/laz-rs-wasm/package.json +19 -0
  85. package/dist/lib/laslaz-decoder.d.ts.map +0 -1
  86. package/dist/lib/libs/laz-perf.d.ts.map +0 -1
  87. package/dist/lib/parse-las.d.ts.map +0 -1
  88. /package/dist/{lib/libs → libs/laz-perf}/laz-perf.d.ts +0 -0
  89. /package/{src/lib/libs → dist/libs/libs/laz-perf}/laz-perf.ts +0 -0
@@ -0,0 +1,22 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // LASER (LAS) FILE FORMAT
6
+ import type {LoaderWithParser} from '@loaders.gl/loader-utils';
7
+ import type {LASLoaderOptions} from './las-loader';
8
+ import {LASWorkerLoader} from './las-loader';
9
+ import type {LASMesh} from './lib/las-types';
10
+ import {parseLAS} from './lib/laz-rs-wasm/parse-las';
11
+ import initLazRsWasm from './libs/laz-rs-wasm/laz_rs_wasm';
12
+
13
+ /**
14
+ * Loader for the LAS (LASer) point cloud format
15
+ */
16
+ export const LAZRsLoader = {
17
+ ...LASWorkerLoader,
18
+ parse: async (arrayBuffer: ArrayBuffer, options?: LASLoaderOptions) => {
19
+ await initLazRsWasm();
20
+ return parseLAS(arrayBuffer, {...options});
21
+ }
22
+ } as const satisfies LoaderWithParser<LASMesh, never, LASLoaderOptions>;
@@ -0,0 +1,22 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // LASER (LAS) FILE FORMAT
6
+ import type {LoaderWithParser} from '@loaders.gl/loader-utils';
7
+ import type {LASLoaderOptions} from './las-loader';
8
+ import {LASWorkerLoader} from './las-loader';
9
+ import type {LASMesh} from './lib/las-types';
10
+ import {parseLAS} from './lib/laz-perf/parse-las';
11
+
12
+ /**
13
+ * Loader for the LAS (LASer) point cloud format
14
+ * @note Does not support LAS v1.4
15
+ */
16
+ export const LAZPerfLoader = {
17
+ ...LASWorkerLoader,
18
+ parse: async (arrayBuffer: ArrayBuffer, options?: LASLoaderOptions) =>
19
+ parseLAS(arrayBuffer, options),
20
+ parseSync: (arrayBuffer: ArrayBuffer, options?: LASLoaderOptions) =>
21
+ parseLAS(arrayBuffer, options)
22
+ } as const satisfies LoaderWithParser<LASMesh, never, LASLoaderOptions>;
@@ -7,7 +7,7 @@ import {deduceMeshSchema} from '@loaders.gl/schema-utils';
7
7
  import type {LASHeader} from './las-types';
8
8
 
9
9
  /**
10
- * Gets schema from PLY header
10
+ * Gets schema from LAS header
11
11
  * @param lasHeader
12
12
  * @param metadata
13
13
  * @returns Schema
@@ -18,6 +18,7 @@ export type LASHeader = {
18
18
  mins?: number[];
19
19
  totalToRead: number;
20
20
  totalRead: number;
21
+ hasColor: boolean;
21
22
  versionAsString?: string;
22
23
  isCompressed?: boolean;
23
24
  };
@@ -8,8 +8,8 @@
8
8
  MIT License
9
9
  */
10
10
  // laslaz.js - treat as compiled code
11
- import type {LASHeader} from './las-types';
12
- import getModule from './libs/laz-perf';
11
+ import type {LASHeader} from '../las-types';
12
+ import getModule from '../../libs/laz-perf/laz-perf';
13
13
 
14
14
  let Module: any = null;
15
15
 
@@ -130,7 +130,8 @@ class LASLoader {
130
130
  totalToRead: 0,
131
131
  totalRead: 0,
132
132
  versionAsString: '',
133
- isCompressed: true
133
+ isCompressed: true,
134
+ hasColor: false
134
135
  };
135
136
 
136
137
  constructor(arraybuffer: ArrayBuffer) {
@@ -4,25 +4,23 @@
4
4
 
5
5
  // ported and es6-ified from https://github.com/verma/plasio/
6
6
  // import type {ArrowTable, ColumnarTable} from '@loaders.gl/schema';
7
- import type {LASLoaderOptions} from '../las-loader';
8
- import type {LASMesh, LASHeader} from './las-types';
7
+ import type {LASLoaderOptions} from '../../las-loader';
8
+ import type {LASMesh, LASHeader} from '../las-types';
9
9
  import {getMeshBoundingBox /* , convertMeshToTable */} from '@loaders.gl/schema-utils';
10
+ import {getLASSchema} from '../get-las-schema';
10
11
  import {LASFile} from './laslaz-decoder';
11
- import {getLASSchema} from './get-las-schema';
12
12
 
13
13
  type LASChunk = {
14
14
  count: number;
15
15
  buffer: ArrayBuffer;
16
16
  hasMoreData: boolean;
17
- versionAsString?: string;
18
- isCompressed?: boolean;
19
17
  };
20
18
 
21
19
  /**
22
20
  * Parsing of .las file
23
21
  * @param arrayBuffer
24
22
  * @param options
25
- * @returns LASHeader
23
+ * @returns LASMesh
26
24
  */
27
25
  export function parseLAS(arrayBuffer: ArrayBuffer, options?: LASLoaderOptions): LASMesh {
28
26
  return parseLASMesh(arrayBuffer, options);
@@ -73,7 +71,7 @@ function parseLASMesh(arrayBuffer: ArrayBuffer, options: LASLoaderOptions = {}):
73
71
  const PositionsType = options.las?.fp64 ? Float64Array : Float32Array;
74
72
  positions = new PositionsType(total * 3);
75
73
  // laslaz-decoder.js `pointFormatReaders`
76
- colors = lasHeader.pointsFormatId >= 2 ? new Uint8Array(total * 4) : null;
74
+ colors = lasHeader.hasColor ? new Uint8Array(total * 4) : null;
77
75
  intensities = new Uint16Array(total);
78
76
  classifications = new Uint8Array(total);
79
77
 
@@ -172,13 +170,12 @@ export function parseLASChunked(rawData: ArrayBuffer, skip: number, onParseData:
172
170
 
173
171
  /* eslint-disable no-constant-condition */
174
172
  while (true) {
175
- const chunk: LASChunk = dataHandler.readData(1000 * 100, 0, skip);
173
+ // @ts-ignore TODO - fix this, looks like we are not passing the right params?
174
+ const chunk: LASChunk = dataHandler.readData(1000 * 100, skip);
176
175
 
177
176
  totalRead += chunk.count;
178
177
 
179
178
  header.totalRead = totalRead;
180
- header.versionAsString = chunk.versionAsString;
181
- header.isCompressed = chunk.isCompressed;
182
179
 
183
180
  const unpacker = new Unpacker(chunk.buffer, chunk.count, header);
184
181
 
@@ -0,0 +1,528 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /*
6
+ Modified from Uday Verma and Howard Butler's plasio
7
+ https://github.com/verma/plasio/
8
+ MIT License
9
+ */
10
+ // laslaz.js - treat as compiled code
11
+ import type {LASHeader} from '../las-types';
12
+ import {WasmLasZipDecompressor} from '../../libs/laz-rs-wasm/laz_rs_wasm';
13
+
14
+ type LASPoint = {
15
+ position: [number, number, number];
16
+ intensity: number;
17
+ classification: number;
18
+ color?: [number, number, number];
19
+ };
20
+
21
+ type LASReader = (dv: DataView) => LASPoint;
22
+
23
+ type LASReaders = {
24
+ [key: number]: LASReader;
25
+ };
26
+
27
+ type LASData = {
28
+ buffer: ArrayBuffer;
29
+ count: number;
30
+ hasMoreData: boolean;
31
+ };
32
+
33
+ const POINT_FORMAT_READERS: LASReaders = {
34
+ 0: (dv) => {
35
+ return {
36
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
37
+ intensity: dv.getUint16(12, true),
38
+ classification: dv.getUint8(15)
39
+ };
40
+ },
41
+ 1: (dv) => {
42
+ return {
43
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
44
+ intensity: dv.getUint16(12, true),
45
+ classification: dv.getUint8(15)
46
+ };
47
+ },
48
+ 2: (dv) => {
49
+ return {
50
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
51
+ intensity: dv.getUint16(12, true),
52
+ classification: dv.getUint8(15),
53
+ color: [dv.getUint16(20, true), dv.getUint16(22, true), dv.getUint16(24, true)]
54
+ };
55
+ },
56
+ 3: (dv) => {
57
+ return {
58
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
59
+ intensity: dv.getUint16(12, true),
60
+ classification: dv.getUint8(15),
61
+ color: [dv.getUint16(28, true), dv.getUint16(30, true), dv.getUint16(32, true)]
62
+ };
63
+ },
64
+ 4: (dv) => {
65
+ return {
66
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
67
+ intensity: dv.getUint16(12, true),
68
+ classification: dv.getUint8(15)
69
+ };
70
+ },
71
+ 5: (dv) => {
72
+ return {
73
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
74
+ intensity: dv.getUint16(12, true),
75
+ classification: dv.getUint8(15),
76
+ color: [dv.getUint16(28, true), dv.getUint16(30, true), dv.getUint16(32, true)]
77
+ };
78
+ },
79
+ 6: (dv) => {
80
+ return {
81
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
82
+ intensity: dv.getUint16(12, true),
83
+ classification: dv.getUint8(16)
84
+ };
85
+ },
86
+ 7: (dv) => {
87
+ return {
88
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
89
+ intensity: dv.getUint16(12, true),
90
+ classification: dv.getUint8(16),
91
+ color: [dv.getUint16(30, true), dv.getUint16(32, true), dv.getUint16(34, true)]
92
+ };
93
+ },
94
+ 8: (dv) => {
95
+ return {
96
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
97
+ intensity: dv.getUint16(12, true),
98
+ classification: dv.getUint8(16),
99
+ color: [dv.getUint16(30, true), dv.getUint16(32, true), dv.getUint16(34, true)]
100
+ };
101
+ },
102
+ 9: (dv) => {
103
+ return {
104
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
105
+ intensity: dv.getUint16(12, true),
106
+ classification: dv.getUint8(16)
107
+ };
108
+ },
109
+ 10: (dv) => {
110
+ return {
111
+ position: [dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
112
+ intensity: dv.getUint16(12, true),
113
+ classification: dv.getUint8(16),
114
+ color: [dv.getUint16(30, true), dv.getUint16(32, true), dv.getUint16(34, true)]
115
+ };
116
+ }
117
+ };
118
+
119
+ /**
120
+ * Reads incoming binary data depends on the Type parameter
121
+ * @param buf
122
+ * @param Type
123
+ * @param offset
124
+ * @param count
125
+ * @returns number | number[] from incoming binary data
126
+ */
127
+ function readAs(buf: ArrayBuffer, Type: any = {}, offset: number, count?: number) {
128
+ count = count === undefined || count === 0 ? 1 : count;
129
+ const sub = buf.slice(offset, offset + Type.BYTES_PER_ELEMENT * count);
130
+
131
+ const r = new Type(sub);
132
+ if (count === 1) {
133
+ return r[0];
134
+ }
135
+
136
+ const ret: number[] = [];
137
+ for (let i = 0; i < count; i++) {
138
+ ret.push(r[i]);
139
+ }
140
+
141
+ return ret;
142
+ }
143
+
144
+ /**
145
+ * Parsing of header's attributes
146
+ * @param arraybuffer
147
+ * @returns header as LASHeader
148
+ */
149
+ function parseLASHeader(arraybuffer: ArrayBuffer): LASHeader {
150
+ const ver = new Uint8Array(arraybuffer, 24, 2);
151
+ const version = ver[0] * 10 + ver[1];
152
+ const versionAsString = `${ver[0]}.${ver[1]}`;
153
+
154
+ const rawPointsFormatId = readAs(arraybuffer, Uint8Array, 32 * 3 + 8);
155
+ const bit7 = (rawPointsFormatId & 0x80) >> 7;
156
+ const bit6 = (rawPointsFormatId & 0x40) >> 6;
157
+
158
+ const isCompressed = bit7 === 1 || bit6 === 1;
159
+ const pointsFormatId = rawPointsFormatId & 0x3f;
160
+ const o: Partial<LASHeader> = {
161
+ pointsOffset: readAs(arraybuffer, Uint32Array, 32 * 3),
162
+ pointsFormatId,
163
+ pointsStructSize: readAs(arraybuffer, Uint16Array, 32 * 3 + 8 + 1),
164
+ pointsCount: readAs(arraybuffer, Uint32Array, 32 * 3 + 11),
165
+ versionAsString,
166
+ isCompressed
167
+ };
168
+
169
+ let start = 32 * 3 + 35;
170
+
171
+ o.scale = readAs(arraybuffer, Float64Array, start, 3);
172
+ start += 24; // 8*3
173
+ o.offset = readAs(arraybuffer, Float64Array, start, 3);
174
+ start += 24;
175
+
176
+ const bounds = readAs(arraybuffer, Float64Array, start, 6);
177
+ start += 48; // 8*6
178
+ o.maxs = [bounds[0], bounds[2], bounds[4]];
179
+ o.mins = [bounds[1], bounds[3], bounds[5]];
180
+
181
+ start += 20; // 8*20
182
+
183
+ if (version === 14) {
184
+ o.pointsCount = Number(readAs(arraybuffer, BigUint64Array, start));
185
+ }
186
+
187
+ const colorPointFormats = new Set([2, 3, 5, 7, 8, 10]);
188
+ o.hasColor = colorPointFormats.has(pointsFormatId);
189
+ // @ts-expect-error Caused when restoring lazperf
190
+ return o;
191
+ }
192
+
193
+ // LAS Loader
194
+ // Loads uncompressed files
195
+ //
196
+ class LASLoader {
197
+ arraybuffer: ArrayBuffer;
198
+ readOffset: number = 0;
199
+ header: LASHeader | null = null;
200
+
201
+ constructor(arraybuffer: ArrayBuffer) {
202
+ this.arraybuffer = arraybuffer;
203
+ }
204
+
205
+ /**
206
+ * @returns boolean
207
+ */
208
+ open() {
209
+ // Nothing needs to be done to open this
210
+ return true;
211
+ }
212
+ /**
213
+ * Parsing of incoming binary
214
+ * @returns LASHeader
215
+ */
216
+ getHeader() {
217
+ this.header = parseLASHeader(this.arraybuffer);
218
+ return this.header;
219
+ }
220
+
221
+ /**
222
+ * Reading data
223
+ * @param count
224
+ * @param skip
225
+ * @returns LasData
226
+ */
227
+ readData(count: number, skip: number): LASData {
228
+ const {header, arraybuffer} = this;
229
+ if (!header) {
230
+ throw new Error('Cannot start reading data till a header request is issued');
231
+ }
232
+
233
+ let {readOffset} = this;
234
+ let start: number;
235
+
236
+ if (skip <= 1) {
237
+ count = Math.min(count, header.pointsCount - readOffset);
238
+ start = header.pointsOffset + readOffset * header.pointsStructSize;
239
+ const end = start + count * header.pointsStructSize;
240
+ readOffset += count;
241
+ this.readOffset = readOffset;
242
+ return {
243
+ buffer: arraybuffer.slice(start, end),
244
+ count,
245
+ hasMoreData: readOffset < header.pointsCount
246
+ };
247
+ }
248
+
249
+ const pointsToRead = Math.min(count * skip, header.pointsCount - readOffset);
250
+ const bufferSize = Math.ceil(pointsToRead / skip);
251
+ let pointsRead = 0;
252
+
253
+ const buf = new Uint8Array(bufferSize * header.pointsStructSize);
254
+ for (let i = 0; i < pointsToRead; i++) {
255
+ if (i % skip === 0) {
256
+ start = header.pointsOffset + readOffset * header.pointsStructSize;
257
+ const src = new Uint8Array(arraybuffer, start, header.pointsStructSize);
258
+
259
+ buf.set(src, pointsRead * header.pointsStructSize);
260
+ pointsRead++;
261
+ }
262
+
263
+ readOffset++;
264
+ }
265
+ this.readOffset = readOffset;
266
+
267
+ return {
268
+ buffer: buf.buffer,
269
+ count: pointsRead,
270
+ hasMoreData: readOffset < header.pointsCount
271
+ };
272
+ }
273
+ /**
274
+ * Method which brings data to null to close the file
275
+ * @returns
276
+ */
277
+ close() {
278
+ // @ts-ignore Possibly null
279
+ this.arraybuffer = null;
280
+ return true;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * LAZ Loader
286
+ * Uses NaCL module to load LAZ files
287
+ */
288
+ class LAZLoader {
289
+ arraybuffer: ArrayBuffer;
290
+ readOffset: number = 0;
291
+ instance: WasmLasZipDecompressor | null = null;
292
+ header: LASHeader | null = null;
293
+
294
+ constructor(arraybuffer: ArrayBuffer) {
295
+ this.arraybuffer = arraybuffer;
296
+ }
297
+
298
+ /**
299
+ * Opens the file
300
+ * @returns boolean
301
+ */
302
+ open(): boolean {
303
+ try {
304
+ const abInt = new Uint8Array(this.arraybuffer);
305
+ this.instance = new WasmLasZipDecompressor(abInt);
306
+
307
+ return true;
308
+ } catch (error) {
309
+ throw new Error(`Failed to open file: ${(error as Error).message}`);
310
+ }
311
+ }
312
+
313
+ getHeader(): LASHeader {
314
+ try {
315
+ this.header = parseLASHeader(this.arraybuffer);
316
+ return this.header;
317
+ } catch (error) {
318
+ throw new Error(`Failed to get header: ${(error as Error).message}`);
319
+ }
320
+ }
321
+
322
+ /**
323
+ * @param count
324
+ * @param offset
325
+ * @param skip
326
+ * @returns LASData
327
+ */
328
+ readData(count: number, skip: number): LASData {
329
+ if (!this.instance) {
330
+ throw new Error('You need to open the file before trying to read stuff');
331
+ }
332
+
333
+ const {header, instance} = this;
334
+
335
+ if (!header) {
336
+ throw new Error(
337
+ 'You need to query header before reading, I maintain state that way, sorry :('
338
+ );
339
+ }
340
+
341
+ try {
342
+ const pointsToRead = Math.min(count * skip, header.pointsCount - this.readOffset);
343
+ const bufferSize = Math.ceil(pointsToRead / skip);
344
+ let pointsRead = 0;
345
+
346
+ const buf = new Uint8Array(bufferSize * header.pointsStructSize);
347
+
348
+ const bufRead = new Uint8Array(header.pointsStructSize);
349
+ for (let i = 0; i < pointsToRead; i++) {
350
+ instance.decompress_many(bufRead);
351
+
352
+ if (i % skip === 0) {
353
+ buf.set(bufRead, pointsRead * header.pointsStructSize);
354
+ pointsRead++;
355
+ }
356
+
357
+ this.readOffset++;
358
+ }
359
+ return {
360
+ buffer: buf.buffer,
361
+ count: pointsRead,
362
+ hasMoreData: this.readOffset < header.pointsCount
363
+ };
364
+ } catch (error) {
365
+ throw new Error(`Failed to read data: ${(error as Error).message}`);
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Deletes the instance
371
+ * @returns boolean
372
+ */
373
+ close(): boolean {
374
+ try {
375
+ if (this.instance !== null) {
376
+ this.instance.free();
377
+ this.instance = null;
378
+ }
379
+ // @ts-ignore Possibly null
380
+ this.arraybuffer = null;
381
+ return true;
382
+ } catch (error) {
383
+ throw new Error(`Failed to close file: ${(error as Error).message}`);
384
+ }
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Helper class: Decodes LAS records into points
390
+ */
391
+ class LASDecoder {
392
+ arrayb: ArrayBuffer;
393
+ decoder: (dv: DataView) => LASPoint;
394
+ pointsCount: number;
395
+ pointSize: number;
396
+
397
+ constructor(buffer: ArrayBuffer, len: number, header: LASHeader) {
398
+ this.arrayb = buffer;
399
+ this.decoder = POINT_FORMAT_READERS[header.pointsFormatId];
400
+ this.pointsCount = len;
401
+ this.pointSize = header.pointsStructSize;
402
+ }
403
+
404
+ /**
405
+ * Decodes data depends on this point size
406
+ * @param index
407
+ * @returns New object
408
+ */
409
+ getPoint(index: number): LASPoint {
410
+ if (index < 0 || index >= this.pointsCount) {
411
+ throw new Error('Point index out of range');
412
+ }
413
+
414
+ const dv = new DataView(this.arrayb, index * this.pointSize, this.pointSize);
415
+ return this.decoder(dv);
416
+ }
417
+ }
418
+
419
+ /**
420
+ * A single consistent interface for loading LAS/LAZ files
421
+ */
422
+ export class LASFile {
423
+ arraybuffer: ArrayBuffer;
424
+ formatId: number = 0;
425
+ loader: LASLoader | LAZLoader;
426
+ isCompressed: boolean = true;
427
+ isOpen: boolean = false;
428
+ version: number = 0;
429
+ versionAsString: string = '';
430
+
431
+ constructor(arraybuffer: ArrayBuffer) {
432
+ this.arraybuffer = arraybuffer;
433
+
434
+ this.validate();
435
+
436
+ this.loader = this.isCompressed
437
+ ? new LAZLoader(this.arraybuffer)
438
+ : new LASLoader(this.arraybuffer);
439
+ }
440
+
441
+ validate(): void {
442
+ const signature = readAs(this.arraybuffer, Uint8Array, 0, 4);
443
+ const check = String.fromCharCode(...signature);
444
+ if (check !== 'LASF') {
445
+ throw new Error('Invalid LAS file');
446
+ }
447
+
448
+ if (this.determineVersion() > 14) {
449
+ throw new Error('Only file versions <= 1.4 are supported');
450
+ }
451
+
452
+ this.determineFormat();
453
+ if (POINT_FORMAT_READERS[this.formatId] === undefined) {
454
+ throw new Error('The point format ID is not supported');
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Determines format in parameters of LASHeader
460
+ */
461
+ determineFormat(): void {
462
+ const formatId = readAs(this.arraybuffer, Uint8Array, 32 * 3 + 8);
463
+ const bit7 = (formatId & 0x80) >> 7;
464
+ const bit6 = (formatId & 0x40) >> 6;
465
+
466
+ if (bit7 === 1 && bit6 === 1) {
467
+ throw new Error('Old style compression not supported');
468
+ }
469
+
470
+ this.formatId = formatId & 0x3f;
471
+ this.isCompressed = bit7 === 1 || bit6 === 1;
472
+ }
473
+
474
+ /**
475
+ * Determines version
476
+ * @returns version
477
+ */
478
+ determineVersion(): number {
479
+ const ver = new Uint8Array(this.arraybuffer, 24, 2);
480
+ this.version = ver[0] * 10 + ver[1];
481
+ this.versionAsString = `${ver[0]}.${ver[1]}`;
482
+ return this.version;
483
+ }
484
+
485
+ /**
486
+ * Reads if the file is open
487
+ * @returns boolean
488
+ */
489
+ open(): void {
490
+ if (this.loader.open()) {
491
+ this.isOpen = true;
492
+ }
493
+ }
494
+ /**
495
+ * Gets the header
496
+ * @returns Header
497
+ */
498
+ getHeader(): LASHeader {
499
+ return this.loader.getHeader();
500
+ }
501
+
502
+ /**
503
+ * @param count
504
+ * @param start
505
+ * @param skip
506
+ * @returns LASData
507
+ */
508
+ readData(count: number, skip: number): LASData {
509
+ return this.loader.readData(count, skip);
510
+ }
511
+
512
+ /**
513
+ * Closes the file
514
+ */
515
+ close(): void {
516
+ if (this.loader.close()) {
517
+ this.isOpen = false;
518
+ }
519
+ }
520
+ /**
521
+ */
522
+ getUnpacker(): typeof LASDecoder {
523
+ return LASDecoder;
524
+ }
525
+ }
526
+
527
+ /* eslint no-use-before-define: 2 */
528
+ // export const LASModuleWasLoaded = false;