maplibre-gl-lidar 0.3.1 → 0.4.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 +45 -0
- package/dist/{LidarLayerAdapter-Cefl4jQL.js → LidarLayerAdapter-CWBS2ItS.js} +95 -15
- package/dist/{LidarLayerAdapter-Cefl4jQL.js.map → LidarLayerAdapter-CWBS2ItS.js.map} +1 -1
- package/dist/{LidarLayerAdapter-BFhI93Is.cjs → LidarLayerAdapter-DTOIC9jR.cjs} +95 -15
- package/dist/{LidarLayerAdapter-BFhI93Is.cjs.map → LidarLayerAdapter-DTOIC9jR.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react.cjs +1 -1
- package/dist/react.mjs +2 -2
- package/dist/types/lib/core/LidarControl.d.ts.map +1 -1
- package/dist/types/lib/core/types.d.ts +9 -0
- package/dist/types/lib/core/types.d.ts.map +1 -1
- package/dist/types/lib/gui/PanelBuilder.d.ts.map +1 -1
- package/dist/types/lib/gui/RangeSlider.d.ts +7 -0
- package/dist/types/lib/gui/RangeSlider.d.ts.map +1 -1
- package/dist/types/lib/layers/PointCloudManager.d.ts +2 -1
- package/dist/types/lib/layers/PointCloudManager.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,6 +28,16 @@ Try the [live demo](https://opengeos.org/maplibre-gl-lidar).
|
|
|
28
28
|
|
|
29
29
|

|
|
30
30
|
|
|
31
|
+
## Online Viewer
|
|
32
|
+
|
|
33
|
+
Use the [Online Viewer](https://opengeos.org/maplibre-gl-lidar/viewer/) to load and visualize any COPC point cloud by entering a URL. You can also use URL parameters for direct linking:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
https://opengeos.org/maplibre-gl-lidar/viewer/?url=https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This allows you to share links that automatically load specific point clouds.
|
|
40
|
+
|
|
31
41
|
## Installation
|
|
32
42
|
|
|
33
43
|
```bash
|
|
@@ -446,6 +456,41 @@ Point clouds are automatically transformed to WGS84 (EPSG:4326) for display on t
|
|
|
446
456
|
- Compound coordinate systems (horizontal + vertical)
|
|
447
457
|
- Automatic unit conversion (feet to meters for elevation)
|
|
448
458
|
|
|
459
|
+
## Docker
|
|
460
|
+
|
|
461
|
+
The examples can be run using Docker. The image is automatically built and published to GitHub Container Registry.
|
|
462
|
+
|
|
463
|
+
### Pull and Run
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
# Pull the latest image
|
|
467
|
+
docker pull ghcr.io/opengeos/maplibre-gl-lidar:latest
|
|
468
|
+
|
|
469
|
+
# Run the container
|
|
470
|
+
docker run -p 8080:80 ghcr.io/opengeos/maplibre-gl-lidar:latest
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
Then open http://localhost:8080/maplibre-gl-lidar/ in your browser to view the examples.
|
|
474
|
+
|
|
475
|
+
### Build Locally
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
# Build the image
|
|
479
|
+
docker build -t maplibre-gl-lidar .
|
|
480
|
+
|
|
481
|
+
# Run the container
|
|
482
|
+
docker run -p 8080:80 maplibre-gl-lidar
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Available Tags
|
|
486
|
+
|
|
487
|
+
| Tag | Description |
|
|
488
|
+
|-----|-------------|
|
|
489
|
+
| `latest` | Latest release |
|
|
490
|
+
| `x.y.z` | Specific version (e.g., `1.0.0`) |
|
|
491
|
+
| `x.y` | Minor version (e.g., `1.0`) |
|
|
492
|
+
|
|
493
|
+
|
|
449
494
|
## Dependencies
|
|
450
495
|
|
|
451
496
|
- [deck.gl](https://deck.gl/) - WebGL visualization layers
|
|
@@ -35461,11 +35461,17 @@ class PointCloudManager {
|
|
|
35461
35461
|
this.updateStyle({ pointSize: size });
|
|
35462
35462
|
}
|
|
35463
35463
|
/**
|
|
35464
|
-
* Sets the opacity.
|
|
35464
|
+
* Sets the global opacity for all point clouds.
|
|
35465
|
+
* This also clears any per-layer opacity overrides so the global value takes effect.
|
|
35465
35466
|
*
|
|
35466
35467
|
* @param opacity - Opacity value (0-1)
|
|
35467
35468
|
*/
|
|
35468
35469
|
setOpacity(opacity) {
|
|
35470
|
+
for (const [id, pc] of this._pointClouds) {
|
|
35471
|
+
if (pc.opacityOverride !== null) {
|
|
35472
|
+
this._pointClouds.set(id, { ...pc, opacityOverride: null });
|
|
35473
|
+
}
|
|
35474
|
+
}
|
|
35469
35475
|
this.updateStyle({ opacity });
|
|
35470
35476
|
}
|
|
35471
35477
|
/**
|
|
@@ -36040,6 +36046,20 @@ class RangeSlider {
|
|
|
36040
36046
|
this._slider.disabled = !enabled;
|
|
36041
36047
|
}
|
|
36042
36048
|
}
|
|
36049
|
+
/**
|
|
36050
|
+
* Sets the slider min and max bounds.
|
|
36051
|
+
*
|
|
36052
|
+
* @param min - New minimum value
|
|
36053
|
+
* @param max - New maximum value
|
|
36054
|
+
*/
|
|
36055
|
+
setBounds(min, max) {
|
|
36056
|
+
this._options.min = min;
|
|
36057
|
+
this._options.max = max;
|
|
36058
|
+
if (this._slider) {
|
|
36059
|
+
this._slider.min = String(min);
|
|
36060
|
+
this._slider.max = String(max);
|
|
36061
|
+
}
|
|
36062
|
+
}
|
|
36043
36063
|
/**
|
|
36044
36064
|
* Formats the value for display.
|
|
36045
36065
|
*/
|
|
@@ -36484,6 +36504,12 @@ class PanelBuilder {
|
|
|
36484
36504
|
this._zOffsetSliderContainer.style.display = state.zOffsetEnabled ? "block" : "none";
|
|
36485
36505
|
}
|
|
36486
36506
|
if (this._zOffsetSlider) {
|
|
36507
|
+
if (state.zOffsetBase !== void 0) {
|
|
36508
|
+
const defaultOffset = -state.zOffsetBase;
|
|
36509
|
+
const sliderMin = defaultOffset - 100;
|
|
36510
|
+
const sliderMax = defaultOffset + 100;
|
|
36511
|
+
this._zOffsetSlider.setBounds(sliderMin, sliderMax);
|
|
36512
|
+
}
|
|
36487
36513
|
this._zOffsetSlider.setValue(state.zOffset ?? 0);
|
|
36488
36514
|
}
|
|
36489
36515
|
if (this._elevationSlider && state.pointClouds.length > 0) {
|
|
@@ -36715,15 +36741,16 @@ class PanelBuilder {
|
|
|
36715
36741
|
sliderContainer.style.display = this._state.zOffsetEnabled ? "block" : "none";
|
|
36716
36742
|
sliderContainer.style.marginTop = "8px";
|
|
36717
36743
|
this._zOffsetSliderContainer = sliderContainer;
|
|
36718
|
-
const
|
|
36719
|
-
const
|
|
36720
|
-
const
|
|
36744
|
+
const zOffsetBase = this._state.zOffsetBase ?? 0;
|
|
36745
|
+
const defaultOffset = -zOffsetBase;
|
|
36746
|
+
const sliderMin = defaultOffset - 100;
|
|
36747
|
+
const sliderMax = defaultOffset + 100;
|
|
36721
36748
|
this._zOffsetSlider = new RangeSlider({
|
|
36722
36749
|
label: "Offset (m)",
|
|
36723
|
-
min:
|
|
36724
|
-
max:
|
|
36750
|
+
min: sliderMin,
|
|
36751
|
+
max: sliderMax,
|
|
36725
36752
|
step: 1,
|
|
36726
|
-
value: this._state.zOffset ??
|
|
36753
|
+
value: this._state.zOffset ?? defaultOffset,
|
|
36727
36754
|
onChange: (v) => this._callbacks.onZOffsetChange(v)
|
|
36728
36755
|
});
|
|
36729
36756
|
sliderContainer.appendChild(this._zOffsetSlider.render());
|
|
@@ -36968,6 +36995,8 @@ const DEFAULT_OPTIONS = {
|
|
|
36968
36995
|
// Show all fields by default
|
|
36969
36996
|
zOffsetEnabled: false,
|
|
36970
36997
|
zOffset: 0,
|
|
36998
|
+
autoZOffset: true,
|
|
36999
|
+
// Automatically calculate Z offset from 2nd percentile
|
|
36971
37000
|
copcLoadingMode: void 0,
|
|
36972
37001
|
// Auto-detect: 'dynamic' for COPC URLs, 'full' otherwise
|
|
36973
37002
|
streamingPointBudget: 5e6,
|
|
@@ -37202,7 +37231,7 @@ class LidarControl {
|
|
|
37202
37231
|
* @returns Promise resolving to the point cloud info
|
|
37203
37232
|
*/
|
|
37204
37233
|
async loadPointCloud(source, options) {
|
|
37205
|
-
var _a, _b;
|
|
37234
|
+
var _a, _b, _c;
|
|
37206
37235
|
const isCopcUrl = typeof source === "string" && (source.startsWith("http://") || source.startsWith("https://")) && /\.copc\./i.test(source);
|
|
37207
37236
|
const isCopcFile = source instanceof File && /\.copc\./i.test(source.name);
|
|
37208
37237
|
const isCopc = isCopcUrl || isCopcFile;
|
|
@@ -37229,6 +37258,23 @@ class LidarControl {
|
|
|
37229
37258
|
const data = await this._loader.load(source, onProgress);
|
|
37230
37259
|
onProgress(95, "Creating visualization layers...");
|
|
37231
37260
|
(_a = this._pointCloudManager) == null ? void 0 : _a.addPointCloud(id, data);
|
|
37261
|
+
let zOffsetBase;
|
|
37262
|
+
let zOffset;
|
|
37263
|
+
let zOffsetEnabled = this._state.zOffsetEnabled;
|
|
37264
|
+
if (this._options.autoZOffset && data.positions && data.pointCount > 0) {
|
|
37265
|
+
const zValues = new Float32Array(data.pointCount);
|
|
37266
|
+
for (let i = 0; i < data.pointCount; i++) {
|
|
37267
|
+
zValues[i] = data.positions[i * 3 + 2] ?? 0;
|
|
37268
|
+
}
|
|
37269
|
+
const percentileBounds = computePercentileBounds(zValues, 2, 98);
|
|
37270
|
+
zOffsetBase = percentileBounds.min;
|
|
37271
|
+
zOffset = -zOffsetBase;
|
|
37272
|
+
zOffsetEnabled = true;
|
|
37273
|
+
(_b = this._pointCloudManager) == null ? void 0 : _b.setZOffset(zOffset);
|
|
37274
|
+
console.log(`Auto Z offset applied: zOffsetBase=${zOffsetBase.toFixed(1)}, zOffset=${zOffset.toFixed(1)}, enabled=${zOffsetEnabled}`);
|
|
37275
|
+
} else {
|
|
37276
|
+
console.log("Auto Z offset skipped - conditions not met");
|
|
37277
|
+
}
|
|
37232
37278
|
onProgress(100, "Complete!");
|
|
37233
37279
|
const info2 = {
|
|
37234
37280
|
id,
|
|
@@ -37251,7 +37297,10 @@ class LidarControl {
|
|
|
37251
37297
|
loading: false,
|
|
37252
37298
|
pointClouds,
|
|
37253
37299
|
activePointCloudId: id,
|
|
37254
|
-
availableClassifications: mergedClassifications
|
|
37300
|
+
availableClassifications: mergedClassifications,
|
|
37301
|
+
zOffsetBase,
|
|
37302
|
+
zOffset: zOffset ?? this._state.zOffset,
|
|
37303
|
+
zOffsetEnabled
|
|
37255
37304
|
});
|
|
37256
37305
|
this._emitWithData("load", { pointCloud: info2 });
|
|
37257
37306
|
if (this._options.autoZoom) {
|
|
@@ -37266,7 +37315,7 @@ class LidarControl {
|
|
|
37266
37315
|
console.warn(
|
|
37267
37316
|
`CORS error detected for ${source}. Falling back to download mode...`
|
|
37268
37317
|
);
|
|
37269
|
-
(
|
|
37318
|
+
(_c = this._panelBuilder) == null ? void 0 : _c.updateLoadingProgress(5, "CORS blocked - downloading file...");
|
|
37270
37319
|
return this._loadPointCloudFullDownload(source);
|
|
37271
37320
|
}
|
|
37272
37321
|
this.setState({
|
|
@@ -37345,9 +37394,22 @@ class LidarControl {
|
|
|
37345
37394
|
(_a = this._panelBuilder) == null ? void 0 : _a.updateLoadingProgress(10, "Initializing COPC file...");
|
|
37346
37395
|
const { bounds: bounds2, totalPoints, hasRGB, spacing } = await streamingLoader.initialize();
|
|
37347
37396
|
(_b = this._panelBuilder) == null ? void 0 : _b.updateLoadingProgress(20, "Setting up streaming...");
|
|
37397
|
+
let autoZOffsetApplied = false;
|
|
37348
37398
|
streamingLoader.setOnPointsLoaded((data) => {
|
|
37349
|
-
var _a2;
|
|
37399
|
+
var _a2, _b2;
|
|
37350
37400
|
(_a2 = this._pointCloudManager) == null ? void 0 : _a2.updatePointCloud(id, data);
|
|
37401
|
+
if (this._options.autoZOffset && !autoZOffsetApplied && data.bounds) {
|
|
37402
|
+
const zOffsetBase = data.bounds.minZ;
|
|
37403
|
+
const zOffset = -zOffsetBase;
|
|
37404
|
+
(_b2 = this._pointCloudManager) == null ? void 0 : _b2.setZOffset(zOffset);
|
|
37405
|
+
console.log(`Auto Z offset applied (streaming): ${zOffset.toFixed(1)}m (ground level from bounds: ${zOffsetBase.toFixed(1)}m)`);
|
|
37406
|
+
this.setState({
|
|
37407
|
+
zOffsetBase,
|
|
37408
|
+
zOffset,
|
|
37409
|
+
zOffsetEnabled: true
|
|
37410
|
+
});
|
|
37411
|
+
autoZOffsetApplied = true;
|
|
37412
|
+
}
|
|
37351
37413
|
const newClassifications = getAvailableClassifications(data);
|
|
37352
37414
|
if (newClassifications.size > 0) {
|
|
37353
37415
|
const mergedClassifications = /* @__PURE__ */ new Set([
|
|
@@ -37471,7 +37533,7 @@ class LidarControl {
|
|
|
37471
37533
|
* Used as fallback when streaming fails due to CORS.
|
|
37472
37534
|
*/
|
|
37473
37535
|
async _loadPointCloudFullDownload(url) {
|
|
37474
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
37536
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
37475
37537
|
const id = generateId("pc");
|
|
37476
37538
|
const name = getFilename(url);
|
|
37477
37539
|
try {
|
|
@@ -37516,7 +37578,22 @@ class LidarControl {
|
|
|
37516
37578
|
const data = await this._loader.load(buffer.buffer, onProgress);
|
|
37517
37579
|
(_e = this._panelBuilder) == null ? void 0 : _e.updateLoadingProgress(95, "Creating visualization layers...");
|
|
37518
37580
|
(_f = this._pointCloudManager) == null ? void 0 : _f.addPointCloud(id, data);
|
|
37519
|
-
|
|
37581
|
+
let zOffsetBase;
|
|
37582
|
+
let zOffset;
|
|
37583
|
+
let zOffsetEnabled = this._state.zOffsetEnabled;
|
|
37584
|
+
if (this._options.autoZOffset && data.positions && data.pointCount > 0) {
|
|
37585
|
+
const zValues = new Float32Array(data.pointCount);
|
|
37586
|
+
for (let i = 0; i < data.pointCount; i++) {
|
|
37587
|
+
zValues[i] = data.positions[i * 3 + 2] ?? 0;
|
|
37588
|
+
}
|
|
37589
|
+
const percentileBounds = computePercentileBounds(zValues, 2, 98);
|
|
37590
|
+
zOffsetBase = percentileBounds.min;
|
|
37591
|
+
zOffset = -zOffsetBase;
|
|
37592
|
+
zOffsetEnabled = true;
|
|
37593
|
+
(_g = this._pointCloudManager) == null ? void 0 : _g.setZOffset(zOffset);
|
|
37594
|
+
console.log(`Auto Z offset applied (download): ${zOffset.toFixed(1)}m (ground level: ${zOffsetBase.toFixed(1)}m)`);
|
|
37595
|
+
}
|
|
37596
|
+
(_h = this._panelBuilder) == null ? void 0 : _h.updateLoadingProgress(100, "Complete!");
|
|
37520
37597
|
const info2 = {
|
|
37521
37598
|
id,
|
|
37522
37599
|
name,
|
|
@@ -37538,7 +37615,10 @@ class LidarControl {
|
|
|
37538
37615
|
loading: false,
|
|
37539
37616
|
pointClouds,
|
|
37540
37617
|
activePointCloudId: id,
|
|
37541
|
-
availableClassifications: mergedClassifications
|
|
37618
|
+
availableClassifications: mergedClassifications,
|
|
37619
|
+
zOffsetBase,
|
|
37620
|
+
zOffset: zOffset ?? this._state.zOffset,
|
|
37621
|
+
zOffsetEnabled
|
|
37542
37622
|
});
|
|
37543
37623
|
this._emitWithData("load", { pointCloud: info2 });
|
|
37544
37624
|
if (this._options.autoZoom) {
|
|
@@ -38436,4 +38516,4 @@ export {
|
|
|
38436
38516
|
getFilename as l,
|
|
38437
38517
|
throttle as t
|
|
38438
38518
|
};
|
|
38439
|
-
//# sourceMappingURL=LidarLayerAdapter-
|
|
38519
|
+
//# sourceMappingURL=LidarLayerAdapter-CWBS2ItS.js.map
|