maplibre-gl-lidar 0.6.0 → 0.6.2
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 +87 -68
- package/dist/{LidarLayerAdapter-CHu9adLN.cjs → LidarLayerAdapter-Sw_plY5a.cjs} +111 -18
- package/dist/{LidarLayerAdapter-CHu9adLN.cjs.map → LidarLayerAdapter-Sw_plY5a.cjs.map} +1 -1
- package/dist/{LidarLayerAdapter-_Y5U5uBB.js → LidarLayerAdapter-mP-0IyJm.js} +111 -18
- package/dist/{LidarLayerAdapter-_Y5U5uBB.js.map → LidarLayerAdapter-mP-0IyJm.js.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/loaders/CopcStreamingLoader.d.ts.map +1 -1
- package/dist/types/lib/loaders/EptStreamingLoader.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,51 +50,53 @@ npm install maplibre-gl-lidar
|
|
|
50
50
|
### Basic Usage (Vanilla JS/TypeScript)
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
|
-
import maplibregl from
|
|
54
|
-
import { LidarControl } from
|
|
55
|
-
import
|
|
56
|
-
import
|
|
53
|
+
import maplibregl from "maplibre-gl";
|
|
54
|
+
import { LidarControl } from "maplibre-gl-lidar";
|
|
55
|
+
import "maplibre-gl-lidar/style.css";
|
|
56
|
+
import "maplibre-gl/dist/maplibre-gl.css";
|
|
57
57
|
|
|
58
58
|
const map = new maplibregl.Map({
|
|
59
|
-
container:
|
|
60
|
-
style:
|
|
59
|
+
container: "map",
|
|
60
|
+
style: "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
|
|
61
61
|
center: [-122.4, 37.8],
|
|
62
62
|
zoom: 12,
|
|
63
63
|
pitch: 60,
|
|
64
64
|
maxPitch: 85, // Allow higher pitch for better 3D viewing
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
map.on(
|
|
67
|
+
map.on("load", () => {
|
|
68
68
|
// Add the LiDAR control
|
|
69
69
|
const lidarControl = new LidarControl({
|
|
70
|
-
title:
|
|
70
|
+
title: "LiDAR Viewer",
|
|
71
71
|
collapsed: true,
|
|
72
72
|
pointSize: 2,
|
|
73
|
-
colorScheme:
|
|
73
|
+
colorScheme: "elevation",
|
|
74
74
|
pickable: true, // Enable point picking for hover tooltips
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
map.addControl(lidarControl,
|
|
77
|
+
map.addControl(lidarControl, "top-right");
|
|
78
78
|
|
|
79
79
|
// Listen for events
|
|
80
|
-
lidarControl.on(
|
|
81
|
-
console.log(
|
|
80
|
+
lidarControl.on("load", (event) => {
|
|
81
|
+
console.log("Point cloud loaded:", event.pointCloud);
|
|
82
82
|
lidarControl.flyToPointCloud();
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
// Load a point cloud programmatically
|
|
86
|
-
lidarControl.loadPointCloud(
|
|
86
|
+
lidarControl.loadPointCloud(
|
|
87
|
+
"https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz"
|
|
88
|
+
);
|
|
87
89
|
});
|
|
88
90
|
```
|
|
89
91
|
|
|
90
92
|
### React Usage
|
|
91
93
|
|
|
92
94
|
```tsx
|
|
93
|
-
import { useEffect, useRef, useState } from
|
|
94
|
-
import maplibregl, { Map } from
|
|
95
|
-
import { LidarControlReact, useLidarState } from
|
|
96
|
-
import
|
|
97
|
-
import
|
|
95
|
+
import { useEffect, useRef, useState } from "react";
|
|
96
|
+
import maplibregl, { Map } from "maplibre-gl";
|
|
97
|
+
import { LidarControlReact, useLidarState } from "maplibre-gl-lidar/react";
|
|
98
|
+
import "maplibre-gl-lidar/style.css";
|
|
99
|
+
import "maplibre-gl/dist/maplibre-gl.css";
|
|
98
100
|
|
|
99
101
|
function App() {
|
|
100
102
|
const mapContainer = useRef<HTMLDivElement>(null);
|
|
@@ -106,28 +108,28 @@ function App() {
|
|
|
106
108
|
|
|
107
109
|
const mapInstance = new maplibregl.Map({
|
|
108
110
|
container: mapContainer.current,
|
|
109
|
-
style:
|
|
111
|
+
style: "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
|
|
110
112
|
center: [-122.4, 37.8],
|
|
111
113
|
zoom: 12,
|
|
112
114
|
pitch: 60,
|
|
113
115
|
maxPitch: 85, // Allow higher pitch for better 3D viewing
|
|
114
116
|
});
|
|
115
117
|
|
|
116
|
-
mapInstance.on(
|
|
118
|
+
mapInstance.on("load", () => setMap(mapInstance));
|
|
117
119
|
|
|
118
120
|
return () => mapInstance.remove();
|
|
119
121
|
}, []);
|
|
120
122
|
|
|
121
123
|
return (
|
|
122
|
-
<div style={{ width:
|
|
123
|
-
<div ref={mapContainer} style={{ width:
|
|
124
|
+
<div style={{ width: "100%", height: "100vh" }}>
|
|
125
|
+
<div ref={mapContainer} style={{ width: "100%", height: "100%" }} />
|
|
124
126
|
{map && (
|
|
125
127
|
<LidarControlReact
|
|
126
128
|
map={map}
|
|
127
129
|
title="LiDAR Viewer"
|
|
128
130
|
pointSize={state.pointSize}
|
|
129
131
|
colorScheme={state.colorScheme}
|
|
130
|
-
onLoad={(pc) => console.log(
|
|
132
|
+
onLoad={(pc) => console.log("Loaded:", pc)}
|
|
131
133
|
defaultUrl="https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz"
|
|
132
134
|
/>
|
|
133
135
|
)}
|
|
@@ -147,37 +149,37 @@ The main control class implementing MapLibre's `IControl` interface.
|
|
|
147
149
|
```typescript
|
|
148
150
|
interface LidarControlOptions {
|
|
149
151
|
// Panel settings
|
|
150
|
-
collapsed?: boolean;
|
|
151
|
-
position?: string;
|
|
152
|
-
title?: string;
|
|
153
|
-
panelWidth?: number;
|
|
154
|
-
panelMaxHeight?: number;
|
|
155
|
-
className?: string;
|
|
152
|
+
collapsed?: boolean; // Start collapsed (default: true)
|
|
153
|
+
position?: string; // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
|
154
|
+
title?: string; // Panel title (default: 'LiDAR Viewer')
|
|
155
|
+
panelWidth?: number; // Panel width in pixels (default: 365)
|
|
156
|
+
panelMaxHeight?: number; // Panel max height with scrollbar (default: 500)
|
|
157
|
+
className?: string; // Custom CSS class
|
|
156
158
|
|
|
157
159
|
// Point cloud styling
|
|
158
|
-
pointSize?: number;
|
|
159
|
-
opacity?: number;
|
|
160
|
-
colorScheme?: ColorScheme;
|
|
161
|
-
usePercentile?: boolean;
|
|
162
|
-
pointBudget?: number;
|
|
160
|
+
pointSize?: number; // Point size in pixels (default: 2)
|
|
161
|
+
opacity?: number; // Opacity 0-1 (default: 1.0)
|
|
162
|
+
colorScheme?: ColorScheme; // Color scheme (default: 'elevation')
|
|
163
|
+
usePercentile?: boolean; // Use 2-98% percentile for coloring (default: true)
|
|
164
|
+
pointBudget?: number; // Max points to display (default: 1000000)
|
|
163
165
|
|
|
164
166
|
// Filters and adjustments
|
|
165
|
-
elevationRange?: [number, number] | null;
|
|
166
|
-
zOffsetEnabled?: boolean;
|
|
167
|
-
zOffset?: number;
|
|
167
|
+
elevationRange?: [number, number] | null; // Elevation filter
|
|
168
|
+
zOffsetEnabled?: boolean; // Enable Z offset adjustment (default: false)
|
|
169
|
+
zOffset?: number; // Z offset in meters (default: 0)
|
|
168
170
|
|
|
169
171
|
// Interaction
|
|
170
|
-
pickable?: boolean;
|
|
171
|
-
pickInfoFields?: string[];
|
|
172
|
+
pickable?: boolean; // Enable point picking/hover tooltips (default: false)
|
|
173
|
+
pickInfoFields?: string[]; // Fields to show in tooltip (default: all)
|
|
172
174
|
|
|
173
175
|
// Behavior
|
|
174
|
-
autoZoom?: boolean;
|
|
176
|
+
autoZoom?: boolean; // Auto zoom to data after loading (default: true)
|
|
175
177
|
|
|
176
178
|
// COPC Streaming (dynamic loading)
|
|
177
|
-
copcLoadingMode?:
|
|
178
|
-
streamingPointBudget?: number;
|
|
179
|
+
copcLoadingMode?: "full" | "dynamic"; // Loading mode for COPC files (default: 'dynamic')
|
|
180
|
+
streamingPointBudget?: number; // Max points for streaming (default: 5000000)
|
|
179
181
|
streamingMaxConcurrentRequests?: number; // Concurrent node requests (default: 4)
|
|
180
|
-
streamingViewportDebounceMs?: number;
|
|
182
|
+
streamingViewportDebounceMs?: number; // Viewport change debounce (default: 150)
|
|
181
183
|
}
|
|
182
184
|
```
|
|
183
185
|
|
|
@@ -261,8 +263,8 @@ By default, elevation and intensity coloring uses the 2nd-98th percentile range
|
|
|
261
263
|
```typescript
|
|
262
264
|
// Percentile coloring is enabled by default
|
|
263
265
|
const control = new LidarControl({
|
|
264
|
-
colorScheme:
|
|
265
|
-
usePercentile: true,
|
|
266
|
+
colorScheme: "elevation",
|
|
267
|
+
usePercentile: true, // default
|
|
266
268
|
});
|
|
267
269
|
|
|
268
270
|
// Disable to use full value range (min-max)
|
|
@@ -298,7 +300,12 @@ const control = new LidarControl({ pickable: true });
|
|
|
298
300
|
control.setPickable(true);
|
|
299
301
|
|
|
300
302
|
// Optionally filter which fields to display
|
|
301
|
-
control.setPickInfoFields([
|
|
303
|
+
control.setPickInfoFields([
|
|
304
|
+
"Classification",
|
|
305
|
+
"Intensity",
|
|
306
|
+
"GpsTime",
|
|
307
|
+
"ReturnNumber",
|
|
308
|
+
]);
|
|
302
309
|
```
|
|
303
310
|
|
|
304
311
|
### Z Offset
|
|
@@ -331,6 +338,7 @@ When using the "Classification" color scheme, an interactive legend appears show
|
|
|
331
338
|
- A checkbox to toggle visibility
|
|
332
339
|
|
|
333
340
|
**Features:**
|
|
341
|
+
|
|
334
342
|
- **Show All / Hide All buttons** - Quickly toggle all classifications at once
|
|
335
343
|
- **Individual toggles** - Show or hide specific classification types
|
|
336
344
|
- **Auto-detection** - Classifications are automatically detected from loaded data
|
|
@@ -341,24 +349,24 @@ When using the "Classification" color scheme, an interactive legend appears show
|
|
|
341
349
|
// The legend automatically appears with checkboxes for each class
|
|
342
350
|
|
|
343
351
|
// Programmatically control visibility
|
|
344
|
-
control.setColorScheme(
|
|
352
|
+
control.setColorScheme("classification");
|
|
345
353
|
|
|
346
354
|
// Hide specific classifications (e.g., hide noise points)
|
|
347
|
-
control.setClassificationVisibility(7, false);
|
|
355
|
+
control.setClassificationVisibility(7, false); // Hide "Low Point (Noise)"
|
|
348
356
|
control.setClassificationVisibility(18, false); // Hide "High Noise"
|
|
349
357
|
|
|
350
358
|
// Show only ground and buildings
|
|
351
359
|
control.hideAllClassifications();
|
|
352
|
-
control.setClassificationVisibility(2, true);
|
|
353
|
-
control.setClassificationVisibility(6, true);
|
|
360
|
+
control.setClassificationVisibility(2, true); // Ground
|
|
361
|
+
control.setClassificationVisibility(6, true); // Building
|
|
354
362
|
|
|
355
363
|
// Get available classifications in the data
|
|
356
364
|
const available = control.getAvailableClassifications();
|
|
357
|
-
console.log(
|
|
365
|
+
console.log("Classifications:", available); // [2, 3, 4, 5, 6, ...]
|
|
358
366
|
|
|
359
367
|
// Get currently hidden classifications
|
|
360
368
|
const hidden = control.getHiddenClassifications();
|
|
361
|
-
console.log(
|
|
369
|
+
console.log("Hidden:", hidden); // [7, 18]
|
|
362
370
|
```
|
|
363
371
|
|
|
364
372
|
**ASPRS Classification Codes:**
|
|
@@ -378,12 +386,14 @@ console.log('Hidden:', hidden); // [7, 18]
|
|
|
378
386
|
For large COPC (Cloud Optimized Point Cloud) files, dynamic streaming loads only the points visible in the current viewport, dramatically reducing initial load time and memory usage.
|
|
379
387
|
|
|
380
388
|
**Key features:**
|
|
389
|
+
|
|
381
390
|
- **Viewport-based loading** - Only loads octree nodes visible in the current map view
|
|
382
391
|
- **Level-of-detail (LOD)** - Automatically selects appropriate detail level based on zoom
|
|
383
392
|
- **Center-first priority** - Points near the viewport center load first
|
|
384
393
|
- **Point budget** - Limits total points in memory (default: 5 million)
|
|
385
394
|
|
|
386
395
|
**How it works:**
|
|
396
|
+
|
|
387
397
|
1. When loading a COPC file (from URL or local file), dynamic mode is used by default
|
|
388
398
|
2. As you pan/zoom the map, new nodes are streamed based on viewport
|
|
389
399
|
3. Deeper octree levels (more detail) load as you zoom in
|
|
@@ -392,20 +402,21 @@ For large COPC (Cloud Optimized Point Cloud) files, dynamic streaming loads only
|
|
|
392
402
|
```typescript
|
|
393
403
|
// Dynamic loading is the default for COPC files
|
|
394
404
|
const control = new LidarControl();
|
|
395
|
-
control.loadPointCloud(
|
|
405
|
+
control.loadPointCloud("https://example.com/large-pointcloud.copc.laz");
|
|
396
406
|
|
|
397
407
|
// Explicitly set loading mode
|
|
398
408
|
const control = new LidarControl({
|
|
399
|
-
copcLoadingMode:
|
|
400
|
-
streamingPointBudget: 10_000_000,
|
|
409
|
+
copcLoadingMode: "dynamic", // or 'full' for complete load
|
|
410
|
+
streamingPointBudget: 10_000_000, // 10 million points max
|
|
401
411
|
});
|
|
402
412
|
|
|
403
413
|
// Override per-load
|
|
404
|
-
control.loadPointCloud(file, { loadingMode:
|
|
405
|
-
control.loadPointCloud(url, { loadingMode:
|
|
414
|
+
control.loadPointCloud(file, { loadingMode: "full" }); // Force full load
|
|
415
|
+
control.loadPointCloud(url, { loadingMode: "dynamic" }); // Force streaming
|
|
406
416
|
```
|
|
407
417
|
|
|
408
418
|
**Loading modes:**
|
|
419
|
+
|
|
409
420
|
- `'dynamic'` (default for COPC) - Stream nodes based on viewport, ideal for large files
|
|
410
421
|
- `'full'` - Load entire point cloud upfront, better for small files
|
|
411
422
|
|
|
@@ -416,6 +427,7 @@ control.loadPointCloud(url, { loadingMode: 'dynamic' }); // Force streaming
|
|
|
416
427
|
maplibre-gl-lidar supports [Entwine Point Tile (EPT)](https://entwine.io/en/latest/entwine-point-tile.html) datasets, a widely-used format for serving large point clouds over HTTP with viewport-based streaming.
|
|
417
428
|
|
|
418
429
|
**Key features:**
|
|
430
|
+
|
|
419
431
|
- **Directory-based format** - Metadata in ept.json, hierarchy in ept-hierarchy/, data in ept-data/
|
|
420
432
|
- **Viewport-based streaming** - Points load dynamically based on current map view
|
|
421
433
|
- **LAZ compression** - Efficient data transfer using LAZ compression
|
|
@@ -425,15 +437,19 @@ maplibre-gl-lidar supports [Entwine Point Tile (EPT)](https://entwine.io/en/late
|
|
|
425
437
|
|
|
426
438
|
```typescript
|
|
427
439
|
// Load EPT dataset by URL (automatically detected via ept.json)
|
|
428
|
-
lidarControl.loadPointCloud(
|
|
440
|
+
lidarControl.loadPointCloud("https://na-c.entwine.io/dublin/ept.json");
|
|
429
441
|
|
|
430
442
|
// Or load programmatically
|
|
431
|
-
lidarControl.loadPointCloudEptStreaming(
|
|
432
|
-
|
|
433
|
-
|
|
443
|
+
lidarControl.loadPointCloudEptStreaming(
|
|
444
|
+
"https://na-c.entwine.io/dublin/ept.json",
|
|
445
|
+
{
|
|
446
|
+
pointBudget: 5_000_000, // Max points in memory
|
|
447
|
+
}
|
|
448
|
+
);
|
|
434
449
|
```
|
|
435
450
|
|
|
436
451
|
**Sample EPT datasets:**
|
|
452
|
+
|
|
437
453
|
- Dublin, Ireland: `https://na-c.entwine.io/dublin/ept.json`
|
|
438
454
|
- New York City (4.7B points): `https://na-c.entwine.io/nyc/ept.json`
|
|
439
455
|
- Red Rocks: `https://na-c.entwine.io/red-rocks/ept.json`
|
|
@@ -515,12 +531,11 @@ docker run -p 8080:80 maplibre-gl-lidar
|
|
|
515
531
|
|
|
516
532
|
### Available Tags
|
|
517
533
|
|
|
518
|
-
| Tag
|
|
519
|
-
|
|
520
|
-
| `latest` | Latest release
|
|
521
|
-
| `x.y.z`
|
|
522
|
-
| `x.y`
|
|
523
|
-
|
|
534
|
+
| Tag | Description |
|
|
535
|
+
| -------- | -------------------------------- |
|
|
536
|
+
| `latest` | Latest release |
|
|
537
|
+
| `x.y.z` | Specific version (e.g., `1.0.0`) |
|
|
538
|
+
| `x.y` | Minor version (e.g., `1.0`) |
|
|
524
539
|
|
|
525
540
|
## Dependencies
|
|
526
541
|
|
|
@@ -537,4 +552,8 @@ MIT
|
|
|
537
552
|
|
|
538
553
|
## Credits
|
|
539
554
|
|
|
540
|
-
|
|
555
|
+
- Microsoft Planetary Computer: [USGS 3DEP Lidar Point Cloud Dataset](https://planetarycomputer.microsoft.com/dataset/usgs-3dep-lidar)
|
|
556
|
+
- AWS Open Data: [USGS 3DEP LiDAR Point Clouds](https://registry.opendata.aws/usgs-lidar)
|
|
557
|
+
- [Hobu, Inc.](https://hobu.co)
|
|
558
|
+
- [COPC.io](https://copc.io)
|
|
559
|
+
- [Entwine](https://entwine.io)
|
|
@@ -34221,6 +34221,7 @@ class PointCloudLoader {
|
|
|
34221
34221
|
};
|
|
34222
34222
|
}
|
|
34223
34223
|
}
|
|
34224
|
+
proj4.defs("EPSG:2180", "+proj=tmerc +lat_0=0 +lon_0=19 +k=0.9993 +x_0=500000 +y_0=-5300000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs");
|
|
34224
34225
|
function createBufferGetter(buffer) {
|
|
34225
34226
|
const uint8 = new Uint8Array(buffer);
|
|
34226
34227
|
return async (begin, end) => {
|
|
@@ -34332,6 +34333,32 @@ function getVerticalUnitConversionFactor$1(wkt2) {
|
|
|
34332
34333
|
}
|
|
34333
34334
|
return 1;
|
|
34334
34335
|
}
|
|
34336
|
+
function clampLatLng$1(lng, lat, context = "") {
|
|
34337
|
+
let clampedLng = lng;
|
|
34338
|
+
let clampedLat = lat;
|
|
34339
|
+
let wasClamped = false;
|
|
34340
|
+
if (lat > 90) {
|
|
34341
|
+
clampedLat = 90;
|
|
34342
|
+
wasClamped = true;
|
|
34343
|
+
} else if (lat < -90) {
|
|
34344
|
+
clampedLat = -90;
|
|
34345
|
+
wasClamped = true;
|
|
34346
|
+
}
|
|
34347
|
+
if (lng > 180) {
|
|
34348
|
+
clampedLng = 180;
|
|
34349
|
+
wasClamped = true;
|
|
34350
|
+
} else if (lng < -180) {
|
|
34351
|
+
clampedLng = -180;
|
|
34352
|
+
wasClamped = true;
|
|
34353
|
+
}
|
|
34354
|
+
if (wasClamped) {
|
|
34355
|
+
console.warn(
|
|
34356
|
+
`COPC: Clamped transformed coordinates to valid WGS84 range${context ? ` (${context})` : ""}:`,
|
|
34357
|
+
`[${lng.toFixed(6)}, ${lat.toFixed(6)}] -> [${clampedLng.toFixed(6)}, ${clampedLat.toFixed(6)}]`
|
|
34358
|
+
);
|
|
34359
|
+
}
|
|
34360
|
+
return [clampedLng, clampedLat];
|
|
34361
|
+
}
|
|
34335
34362
|
const DEFAULT_OPTIONS$2 = {
|
|
34336
34363
|
pointBudget: 5e6,
|
|
34337
34364
|
maxConcurrentRequests: 4,
|
|
@@ -34439,10 +34466,30 @@ class CopcStreamingLoader {
|
|
|
34439
34466
|
} catch (e) {
|
|
34440
34467
|
console.warn("Failed to setup coordinate transformation:", e);
|
|
34441
34468
|
}
|
|
34469
|
+
} else {
|
|
34470
|
+
const minX = header2.min[0];
|
|
34471
|
+
const minY = header2.min[1];
|
|
34472
|
+
const maxX = header2.max[0];
|
|
34473
|
+
const maxY = header2.max[1];
|
|
34474
|
+
let detectedEPSG = null;
|
|
34475
|
+
if (minX >= 1e5 && maxX <= 9e5 && minY >= 1e5 && maxY <= 8e5) {
|
|
34476
|
+
detectedEPSG = "EPSG:2180";
|
|
34477
|
+
}
|
|
34478
|
+
if (detectedEPSG) {
|
|
34479
|
+
try {
|
|
34480
|
+
const projConverter = proj4(detectedEPSG, "EPSG:4326");
|
|
34481
|
+
this._transformer = (coord) => projConverter.forward(coord);
|
|
34482
|
+
this._needsTransform = true;
|
|
34483
|
+
} catch (e) {
|
|
34484
|
+
console.warn(`Failed to setup coordinate transformation from ${detectedEPSG}:`, e);
|
|
34485
|
+
}
|
|
34486
|
+
}
|
|
34442
34487
|
}
|
|
34443
34488
|
if (this._needsTransform && this._transformer) {
|
|
34444
|
-
const [
|
|
34445
|
-
const [
|
|
34489
|
+
const [rawMinLng, rawMinLat] = this._transformer([header2.min[0], header2.min[1]]);
|
|
34490
|
+
const [rawMaxLng, rawMaxLat] = this._transformer([header2.max[0], header2.max[1]]);
|
|
34491
|
+
const [minLng, minLat] = clampLatLng$1(rawMinLng, rawMinLat, "header bounds min");
|
|
34492
|
+
const [maxLng, maxLat] = clampLatLng$1(rawMaxLng, rawMaxLat, "header bounds max");
|
|
34446
34493
|
this._bounds = {
|
|
34447
34494
|
minX: Math.min(minLng, maxLng),
|
|
34448
34495
|
minY: Math.min(minLat, maxLat),
|
|
@@ -34532,8 +34579,10 @@ class CopcStreamingLoader {
|
|
|
34532
34579
|
};
|
|
34533
34580
|
let boundsWgs84 = bounds2;
|
|
34534
34581
|
if (this._needsTransform && this._transformer) {
|
|
34535
|
-
const [
|
|
34536
|
-
const [
|
|
34582
|
+
const [rawSwLng, rawSwLat] = this._transformer([minX, minY]);
|
|
34583
|
+
const [rawNeLng, rawNeLat] = this._transformer([minX + nodeSize, minY + nodeSize]);
|
|
34584
|
+
const [sw_lng, sw_lat] = clampLatLng$1(rawSwLng, rawSwLat, "node bounds SW");
|
|
34585
|
+
const [ne_lng, ne_lat] = clampLatLng$1(rawNeLng, rawNeLat, "node bounds NE");
|
|
34537
34586
|
boundsWgs84 = {
|
|
34538
34587
|
minX: Math.min(sw_lng, ne_lng),
|
|
34539
34588
|
minY: Math.min(sw_lat, ne_lat),
|
|
@@ -34765,7 +34814,8 @@ class CopcStreamingLoader {
|
|
|
34765
34814
|
const y = yGetter(i);
|
|
34766
34815
|
const z = zGetter(i);
|
|
34767
34816
|
if (this._needsTransform && this._transformer) {
|
|
34768
|
-
const [
|
|
34817
|
+
const [rawLng, rawLat] = this._transformer([x, y]);
|
|
34818
|
+
const [lng, lat] = clampLatLng$1(rawLng, rawLat, "");
|
|
34769
34819
|
this._positions[pointIndex * 3] = lng - this._coordinateOrigin[0];
|
|
34770
34820
|
this._positions[pointIndex * 3 + 1] = lat - this._coordinateOrigin[1];
|
|
34771
34821
|
this._positions[pointIndex * 3 + 2] = z * this._verticalUnitFactor;
|
|
@@ -34986,6 +35036,32 @@ function createAttributeArray(type, length) {
|
|
|
34986
35036
|
return new Float32Array(length);
|
|
34987
35037
|
}
|
|
34988
35038
|
}
|
|
35039
|
+
function clampLatLng(lng, lat, context = "") {
|
|
35040
|
+
let clampedLng = lng;
|
|
35041
|
+
let clampedLat = lat;
|
|
35042
|
+
let wasClamped = false;
|
|
35043
|
+
if (lat > 90) {
|
|
35044
|
+
clampedLat = 90;
|
|
35045
|
+
wasClamped = true;
|
|
35046
|
+
} else if (lat < -90) {
|
|
35047
|
+
clampedLat = -90;
|
|
35048
|
+
wasClamped = true;
|
|
35049
|
+
}
|
|
35050
|
+
if (lng > 180) {
|
|
35051
|
+
clampedLng = 180;
|
|
35052
|
+
wasClamped = true;
|
|
35053
|
+
} else if (lng < -180) {
|
|
35054
|
+
clampedLng = -180;
|
|
35055
|
+
wasClamped = true;
|
|
35056
|
+
}
|
|
35057
|
+
if (wasClamped && context) {
|
|
35058
|
+
console.warn(
|
|
35059
|
+
`EPT: Clamped transformed coordinates to valid WGS84 range${context ? ` (${context})` : ""}:`,
|
|
35060
|
+
`[${lng.toFixed(6)}, ${lat.toFixed(6)}] -> [${clampedLng.toFixed(6)}, ${clampedLat.toFixed(6)}]`
|
|
35061
|
+
);
|
|
35062
|
+
}
|
|
35063
|
+
return [clampedLng, clampedLat];
|
|
35064
|
+
}
|
|
34989
35065
|
function extractProjcsFromWkt(wkt2) {
|
|
34990
35066
|
if (wkt2.startsWith("COMPD_CS[")) {
|
|
34991
35067
|
const projcsStart = wkt2.indexOf("PROJCS[");
|
|
@@ -35125,17 +35201,19 @@ class EptStreamingLoader {
|
|
|
35125
35201
|
}
|
|
35126
35202
|
const [minX, minY, minZ, maxX, maxY, maxZ] = this._metadata.boundsConforming;
|
|
35127
35203
|
if (this._needsTransform && this._transformer) {
|
|
35128
|
-
const [
|
|
35129
|
-
const [
|
|
35130
|
-
if (isNaN(
|
|
35204
|
+
const [rawMinLng, rawMinLat] = this._transformer([minX, minY]);
|
|
35205
|
+
const [rawMaxLng, rawMaxLat] = this._transformer([maxX, maxY]);
|
|
35206
|
+
if (isNaN(rawMinLng) || isNaN(rawMinLat) || isNaN(rawMaxLng) || isNaN(rawMaxLat) || !isFinite(rawMinLng) || !isFinite(rawMinLat) || !isFinite(rawMaxLng) || !isFinite(rawMaxLat)) {
|
|
35131
35207
|
console.error("EPT coordinate transformation produced invalid bounds:", {
|
|
35132
35208
|
input: { minX, minY, maxX, maxY },
|
|
35133
|
-
output: {
|
|
35209
|
+
output: { rawMinLng, rawMinLat, rawMaxLng, rawMaxLat }
|
|
35134
35210
|
});
|
|
35135
35211
|
this._bounds = { minX, minY, minZ, maxX, maxY, maxZ };
|
|
35136
35212
|
this._needsTransform = false;
|
|
35137
35213
|
this._transformer = null;
|
|
35138
35214
|
} else {
|
|
35215
|
+
const [minLng, minLat] = clampLatLng(rawMinLng, rawMinLat, "header bounds min");
|
|
35216
|
+
const [maxLng, maxLat] = clampLatLng(rawMaxLng, rawMaxLat, "header bounds max");
|
|
35139
35217
|
this._bounds = {
|
|
35140
35218
|
minX: Math.min(minLng, maxLng),
|
|
35141
35219
|
minY: Math.min(minLat, maxLat),
|
|
@@ -35286,8 +35364,10 @@ class EptStreamingLoader {
|
|
|
35286
35364
|
};
|
|
35287
35365
|
let boundsWgs84 = bounds2;
|
|
35288
35366
|
if (this._needsTransform && this._transformer) {
|
|
35289
|
-
const [
|
|
35290
|
-
const [
|
|
35367
|
+
const [rawSwLng, rawSwLat] = this._transformer([minX, minY]);
|
|
35368
|
+
const [rawNeLng, rawNeLat] = this._transformer([minX + nodeSize, minY + nodeSize]);
|
|
35369
|
+
const [sw_lng, sw_lat] = clampLatLng(rawSwLng, rawSwLat, "node bounds SW");
|
|
35370
|
+
const [ne_lng, ne_lat] = clampLatLng(rawNeLng, rawNeLat, "node bounds NE");
|
|
35291
35371
|
boundsWgs84 = {
|
|
35292
35372
|
minX: Math.min(sw_lng, ne_lng),
|
|
35293
35373
|
minY: Math.min(sw_lat, ne_lat),
|
|
@@ -35571,7 +35651,8 @@ class EptStreamingLoader {
|
|
|
35571
35651
|
const y = positions[i * 3 + 1];
|
|
35572
35652
|
const z = positions[i * 3 + 2];
|
|
35573
35653
|
if (this._needsTransform && this._transformer) {
|
|
35574
|
-
const [
|
|
35654
|
+
const [rawLng, rawLat] = this._transformer([x, y]);
|
|
35655
|
+
const [lng, lat] = clampLatLng(rawLng, rawLat, "");
|
|
35575
35656
|
this._positions[pointIndex * 3] = lng - this._coordinateOrigin[0];
|
|
35576
35657
|
this._positions[pointIndex * 3 + 1] = lat - this._coordinateOrigin[1];
|
|
35577
35658
|
this._positions[pointIndex * 3 + 2] = z * this._verticalUnitFactor;
|
|
@@ -35651,7 +35732,8 @@ class EptStreamingLoader {
|
|
|
35651
35732
|
const y = yGetter(dataView, byteOffset);
|
|
35652
35733
|
const z = zGetter(dataView, byteOffset);
|
|
35653
35734
|
if (this._needsTransform && this._transformer) {
|
|
35654
|
-
const [
|
|
35735
|
+
const [rawLng, rawLat] = this._transformer([x, y]);
|
|
35736
|
+
const [lng, lat] = clampLatLng(rawLng, rawLat, "");
|
|
35655
35737
|
this._positions[pointIndex * 3] = lng - this._coordinateOrigin[0];
|
|
35656
35738
|
this._positions[pointIndex * 3 + 1] = lat - this._coordinateOrigin[1];
|
|
35657
35739
|
this._positions[pointIndex * 3 + 2] = z * this._verticalUnitFactor;
|
|
@@ -38431,10 +38513,14 @@ class LidarControl {
|
|
|
38431
38513
|
});
|
|
38432
38514
|
viewportManager.start();
|
|
38433
38515
|
if (this._options.autoZoom) {
|
|
38516
|
+
const clampedMinY = Math.max(-90, Math.min(90, bounds2.minY));
|
|
38517
|
+
const clampedMaxY = Math.max(-90, Math.min(90, bounds2.maxY));
|
|
38518
|
+
const clampedMinX = Math.max(-180, Math.min(180, bounds2.minX));
|
|
38519
|
+
const clampedMaxX = Math.max(-180, Math.min(180, bounds2.maxX));
|
|
38434
38520
|
(_c = this._map) == null ? void 0 : _c.fitBounds(
|
|
38435
38521
|
[
|
|
38436
|
-
[
|
|
38437
|
-
[
|
|
38522
|
+
[clampedMinX, clampedMinY],
|
|
38523
|
+
[clampedMaxX, clampedMaxY]
|
|
38438
38524
|
],
|
|
38439
38525
|
{
|
|
38440
38526
|
padding: 50,
|
|
@@ -38591,10 +38677,14 @@ class LidarControl {
|
|
|
38591
38677
|
});
|
|
38592
38678
|
viewportManager.start();
|
|
38593
38679
|
if (this._options.autoZoom) {
|
|
38680
|
+
const clampedMinY = Math.max(-90, Math.min(90, bounds2.minY));
|
|
38681
|
+
const clampedMaxY = Math.max(-90, Math.min(90, bounds2.maxY));
|
|
38682
|
+
const clampedMinX = Math.max(-180, Math.min(180, bounds2.minX));
|
|
38683
|
+
const clampedMaxX = Math.max(-180, Math.min(180, bounds2.maxX));
|
|
38594
38684
|
(_d = this._map) == null ? void 0 : _d.fitBounds(
|
|
38595
38685
|
[
|
|
38596
|
-
[
|
|
38597
|
-
[
|
|
38686
|
+
[clampedMinX, clampedMinY],
|
|
38687
|
+
[clampedMaxX, clampedMaxY]
|
|
38598
38688
|
],
|
|
38599
38689
|
{
|
|
38600
38690
|
padding: 50,
|
|
@@ -38975,6 +39065,9 @@ class LidarControl {
|
|
|
38975
39065
|
var _a;
|
|
38976
39066
|
this._state.pickable = pickable;
|
|
38977
39067
|
(_a = this._pointCloudManager) == null ? void 0 : _a.setPickable(pickable);
|
|
39068
|
+
if (!pickable && this._tooltip) {
|
|
39069
|
+
this._tooltip.style.display = "none";
|
|
39070
|
+
}
|
|
38978
39071
|
this._emit("stylechange");
|
|
38979
39072
|
this._emit("statechange");
|
|
38980
39073
|
}
|
|
@@ -39701,4 +39794,4 @@ exports.generateId = generateId;
|
|
|
39701
39794
|
exports.getClassificationName = getClassificationName;
|
|
39702
39795
|
exports.getFilename = getFilename;
|
|
39703
39796
|
exports.throttle = throttle;
|
|
39704
|
-
//# sourceMappingURL=LidarLayerAdapter-
|
|
39797
|
+
//# sourceMappingURL=LidarLayerAdapter-Sw_plY5a.cjs.map
|