@gisatcz/deckgl-geolib 2.6.0-dev.1 → 2.6.0-dev.3

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/dist/cjs/index.js CHANGED
@@ -8260,7 +8260,9 @@ class CogTerrainLayer extends core.CompositeLayer {
8260
8260
  const minZ = Math.min(...ranges.map((x) => x?.[0] ?? 0).filter((n) => Number.isFinite(n)));
8261
8261
  const maxZ = Math.max(...ranges.map((x) => x?.[1] ?? 0).filter((n) => Number.isFinite(n)));
8262
8262
  if (!zRange || minZ < zRange[0] || maxZ > zRange[1]) {
8263
- this.setState({ zRange: [Number.isFinite(minZ) ? minZ : 0, Number.isFinite(maxZ) ? maxZ : 0] });
8263
+ const newZRange = [Number.isFinite(minZ) ? minZ : 0, Number.isFinite(maxZ) ? maxZ : 0];
8264
+ this.setState({ zRange: newZRange });
8265
+ this.props.onZRangeUpdate?.(newZRange);
8264
8266
  }
8265
8267
  }
8266
8268
  renderLayers() {
@@ -8312,6 +8314,151 @@ class CogTerrainLayer extends core.CompositeLayer {
8312
8314
  }
8313
8315
  }
8314
8316
 
8317
+ /**
8318
+ * Terrain coordinate extraction utility for CogTerrainLayer
8319
+ * Enables precise lat/lon/elevation extraction from 3D terrain picks
8320
+ */
8321
+ /**
8322
+ * Extracts precise geographic coordinates and elevation from a CogTerrainLayer pick result
8323
+ *
8324
+ * @param pickResult - DeckGL pickObject result from terrain-layer pick
8325
+ * @returns TerrainCoordinate with lon/lat/elevation, or null if extraction fails
8326
+ *
8327
+ * @requires deck.gl >=9.3.0 (for `pickable: '3d'` support)
8328
+ * @note Requires `pickable: '3d'` on CogTerrainLayer. With 3D picking enabled,
8329
+ * deck.gl's terrain layer provides info.coordinate as a 3-element array [lon, lat, elevation]
8330
+ * where elevation is read directly from the terrain mesh at the picked point.
8331
+ * This gives accurate 3D coordinates regardless of camera pitch or bearing.
8332
+ *
8333
+ * @example
8334
+ * ```ts
8335
+ * const cogLayer = new CogTerrainLayer({
8336
+ * // ...
8337
+ * pickable: '3d', // Requires deck.gl >=9.3.0
8338
+ * onClick: (info) => {
8339
+ * const coord = extractTerrainCoordinate(info);
8340
+ * if (coord) {
8341
+ * console.log(`Clicked at ${coord.latitude}, ${coord.longitude}, elevation: ${coord.elevation}m`);
8342
+ * }
8343
+ * }
8344
+ * });
8345
+ * ```
8346
+ */
8347
+ function extractTerrainCoordinate(pickResult) {
8348
+ try {
8349
+ // With pickable: '3d', info.coordinate is a 3-element array [lon, lat, elevation]
8350
+ if (!pickResult?.coordinate || pickResult.coordinate.length < 3) {
8351
+ return null;
8352
+ }
8353
+ const [longitude, latitude, elevation] = pickResult.coordinate;
8354
+ if (longitude === undefined || latitude === undefined || elevation === undefined) {
8355
+ return null;
8356
+ }
8357
+ return {
8358
+ longitude,
8359
+ latitude,
8360
+ elevation,
8361
+ };
8362
+ }
8363
+ catch {
8364
+ // Silently return null on any error
8365
+ return null;
8366
+ }
8367
+ }
8368
+ /**
8369
+ * Samples terrain coordinates in a grid around a pick point for debugging
8370
+ * Useful for understanding terrain data layout and accuracy
8371
+ *
8372
+ * @param pickResult - DeckGL pickObject result from terrain-layer pick
8373
+ * @param gridSize - Odd number for grid dimensions (default: 3 for 3x3 grid).
8374
+ * gridSize=3 → 3×3 grid (offset±1), gridSize=5 → 5×5 grid (offset±2).
8375
+ * Uses WebMercator projection for accurate latitude mapping.
8376
+ * @returns Array of TerrainCoordinate samples, or empty array if extraction fails
8377
+ *
8378
+ * @example
8379
+ * ```ts
8380
+ * const samples = sampleTerrainTileCoordinates(info, 5); // 5x5 grid around click
8381
+ * samples.forEach(coord => {
8382
+ * console.log(`Sample: ${coord.latitude}, ${coord.longitude}, elev: ${coord.elevation}m`);
8383
+ * });
8384
+ * ```
8385
+ */
8386
+ function sampleTerrainTileCoordinates(pickResult, gridSize = 3) {
8387
+ try {
8388
+ // Validate input has required structure
8389
+ if (!pickResult?.tile?.content) {
8390
+ return [];
8391
+ }
8392
+ const tileResult = pickResult.tile.content[0];
8393
+ if (!tileResult?.raw) {
8394
+ return [];
8395
+ }
8396
+ const { raw, width, height } = tileResult;
8397
+ const bbox = pickResult.tile.bbox;
8398
+ if (!bbox) {
8399
+ return [];
8400
+ }
8401
+ const west = bbox.west ?? bbox[0];
8402
+ const south = bbox.south ?? bbox[1];
8403
+ const east = bbox.east ?? bbox[2];
8404
+ const north = bbox.north ?? bbox[3];
8405
+ if (west === undefined || south === undefined || east === undefined || north === undefined) {
8406
+ return [];
8407
+ }
8408
+ const coordinate = pickResult.coordinate;
8409
+ if (!coordinate || coordinate.length < 2) {
8410
+ return [];
8411
+ }
8412
+ const [centerLon, centerLat] = coordinate;
8413
+ // Calculate grid offset (in pixels): gridSize must be odd; gridSize=3 → offset=1, gridSize=5 → offset=2
8414
+ const offset = Math.floor(gridSize / 2);
8415
+ // Get center pixel from clicked coordinate using WebMercator projection
8416
+ const centerNormX = (centerLon - west) / (east - west);
8417
+ // WebMercator non-linear latitude projection
8418
+ const centerLatRad = centerLat * Math.PI / 180;
8419
+ const northRad = north * Math.PI / 180;
8420
+ const southRad = south * Math.PI / 180;
8421
+ const mercatorCenterY = Math.log(Math.tan(Math.PI / 4 + centerLatRad / 2));
8422
+ const mercatorNorth = Math.log(Math.tan(Math.PI / 4 + northRad / 2));
8423
+ const mercatorSouth = Math.log(Math.tan(Math.PI / 4 + southRad / 2));
8424
+ const centerNormY = (mercatorNorth - mercatorCenterY) / (mercatorNorth - mercatorSouth);
8425
+ const centerPixelX = Math.floor(centerNormX * (width - 1));
8426
+ const centerPixelY = Math.floor(centerNormY * (height - 1));
8427
+ const samples = [];
8428
+ // Sample grid around clicked point
8429
+ for (let dy = -offset; dy <= offset; dy++) {
8430
+ for (let dx = -offset; dx <= offset; dx++) {
8431
+ const pixelX = centerPixelX + dx;
8432
+ const pixelY = centerPixelY + dy;
8433
+ // Stay within tile bounds
8434
+ if (pixelX < 0 || pixelX >= width || pixelY < 0 || pixelY >= height) {
8435
+ continue;
8436
+ }
8437
+ const pixelIndex = pixelY * width + pixelX;
8438
+ const elevation = raw[pixelIndex];
8439
+ if (elevation === undefined || elevation === null) {
8440
+ continue;
8441
+ }
8442
+ // Convert pixel to geographic coordinates using WebMercator projection
8443
+ const lon = west + (pixelX / (width - 1)) * (east - west);
8444
+ // Inverse WebMercator transform for latitude
8445
+ const normV = pixelY / (height - 1);
8446
+ const mercatorY = mercatorNorth - normV * (mercatorNorth - mercatorSouth);
8447
+ const lat = (2 * Math.atan(Math.exp(mercatorY)) - Math.PI / 2) * 180 / Math.PI;
8448
+ samples.push({
8449
+ longitude: lon,
8450
+ latitude: lat,
8451
+ elevation,
8452
+ });
8453
+ }
8454
+ }
8455
+ return samples;
8456
+ }
8457
+ catch {
8458
+ return [];
8459
+ }
8460
+ }
8461
+
8315
8462
  // src/index.ts
8316
8463
  // Initialize global error suppression for deck.gl AbortErrors
8317
8464
  suppressGlobalAbortErrors();
@@ -15529,5 +15676,7 @@ exports.CogBitmapLayer = CogBitmapLayer;
15529
15676
  exports.CogTerrainLayer = CogTerrainLayer;
15530
15677
  exports.CogTiles = CogTiles;
15531
15678
  exports.GeoImage = GeoImage;
15679
+ exports.extractTerrainCoordinate = extractTerrainCoordinate;
15680
+ exports.sampleTerrainTileCoordinates = sampleTerrainTileCoordinates;
15532
15681
  exports.suppressGlobalAbortErrors = suppressGlobalAbortErrors;
15533
15682
  //# sourceMappingURL=index.js.map