@gisatcz/deckgl-geolib 2.1.1 → 2.1.2-dev.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/dist/cjs/index.js +67 -49
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.min.js +3 -3
- package/dist/cjs/index.min.js.map +1 -1
- package/dist/cjs/types/core/CogTiles.d.ts +4 -3
- package/dist/esm/index.js +67 -49
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +3 -3
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/types/core/CogTiles.d.ts +4 -3
- package/package.json +2 -4
package/dist/cjs/index.js
CHANGED
|
@@ -4,7 +4,6 @@ var core = require('@deck.gl/core');
|
|
|
4
4
|
var geoLayers = require('@deck.gl/geo-layers');
|
|
5
5
|
var layers = require('@deck.gl/layers');
|
|
6
6
|
var extensions = require('@deck.gl/extensions');
|
|
7
|
-
var webMercator = require('@math.gl/web-mercator');
|
|
8
7
|
var chroma = require('chroma-js');
|
|
9
8
|
var schema = require('@loaders.gl/schema');
|
|
10
9
|
var loaderUtils = require('@loaders.gl/loader-utils');
|
|
@@ -5326,17 +5325,25 @@ class GeoImage {
|
|
|
5326
5325
|
channel = rasters[optionsLocal.useChannelIndex];
|
|
5327
5326
|
}
|
|
5328
5327
|
}
|
|
5329
|
-
const terrain = new Float32Array((width + 1) * (height + 1));
|
|
5328
|
+
const terrain = new Float32Array((width === 257 ? width : width + 1) * (height === 257 ? height : height + 1));
|
|
5330
5329
|
const numOfChannels = channel.length / (width * height);
|
|
5331
5330
|
let pixel = options.useChannelIndex === null ? 0 : options.useChannelIndex;
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5331
|
+
const isStitched = width === 257;
|
|
5332
|
+
for (let y = 0; y < height; y++) {
|
|
5333
|
+
for (let x = 0; x < width; x++) {
|
|
5334
|
+
let elevationValue = (options.noDataValue && channel[pixel] === options.noDataValue) ? options.terrainMinValue : channel[pixel] * options.multiplier;
|
|
5335
|
+
// Validate that the elevation value is within the valid range for Float32.
|
|
5336
|
+
// Extreme values (like -1.79e308) can become -Infinity when cast, causing WebGL errors.
|
|
5337
|
+
if (Number.isNaN(elevationValue) || elevationValue < -3.4e38 || elevationValue > 3.4e38) {
|
|
5338
|
+
elevationValue = options.terrainMinValue;
|
|
5339
|
+
}
|
|
5340
|
+
// If stitched (257), fill linearly. If 256, fill with stride for padding.
|
|
5341
|
+
const index = isStitched ? (y * width + x) : (y * (width + 1) + x);
|
|
5342
|
+
terrain[index] = elevationValue;
|
|
5336
5343
|
pixel += numOfChannels;
|
|
5337
5344
|
}
|
|
5338
5345
|
}
|
|
5339
|
-
if (
|
|
5346
|
+
if (!isStitched) {
|
|
5340
5347
|
// backfill bottom border
|
|
5341
5348
|
for (let i = (width + 1) * width, x = 0; x < width; x++, i++) {
|
|
5342
5349
|
terrain[i] = terrain[i - width - 1];
|
|
@@ -5655,22 +5662,26 @@ class GeoImage {
|
|
|
5655
5662
|
* @returns {{vertices: Uint16Array, triangles: Uint32Array}} vertices and triangles data
|
|
5656
5663
|
*/
|
|
5657
5664
|
function getMartiniTileMesh(meshMaxError, width, terrain) {
|
|
5658
|
-
const gridSize = width + 1;
|
|
5665
|
+
const gridSize = width === 257 ? 257 : width + 1;
|
|
5659
5666
|
const martini = new Martini(gridSize);
|
|
5660
5667
|
const tile = martini.createTile(terrain);
|
|
5661
5668
|
const { vertices, triangles } = tile.getMesh(meshMaxError);
|
|
5662
5669
|
return { vertices, triangles };
|
|
5663
5670
|
}
|
|
5664
5671
|
function getMeshAttributes(vertices, terrain, width, height, bounds) {
|
|
5665
|
-
const gridSize = width + 1;
|
|
5672
|
+
const gridSize = width === 257 ? 257 : width + 1;
|
|
5666
5673
|
const numOfVerticies = vertices.length / 2;
|
|
5667
5674
|
// vec3. x, y in pixels, z in meters
|
|
5668
5675
|
const positions = new Float32Array(numOfVerticies * 3);
|
|
5669
5676
|
// vec2. 1 to 1 relationship with position. represents the uv on the texture image. 0,0 to 1,1.
|
|
5670
5677
|
const texCoords = new Float32Array(numOfVerticies * 2);
|
|
5671
5678
|
const [minX, minY, maxX, maxY] = bounds || [0, 0, width, height];
|
|
5672
|
-
|
|
5673
|
-
|
|
5679
|
+
// If stitched (257), the spatial extent covers 0..256 pixels, so we divide by 256.
|
|
5680
|
+
// If standard (256), the spatial extent covers 0..256 pixels (with backfill), so we divide by 256.
|
|
5681
|
+
const effectiveWidth = width === 257 ? width - 1 : width;
|
|
5682
|
+
const effectiveHeight = height === 257 ? height - 1 : height;
|
|
5683
|
+
const xScale = (maxX - minX) / effectiveWidth;
|
|
5684
|
+
const yScale = (maxY - minY) / effectiveHeight;
|
|
5674
5685
|
for (let i = 0; i < numOfVerticies; i++) {
|
|
5675
5686
|
const x = vertices[i * 2];
|
|
5676
5687
|
const y = vertices[i * 2 + 1];
|
|
@@ -5678,8 +5689,8 @@ function getMeshAttributes(vertices, terrain, width, height, bounds) {
|
|
|
5678
5689
|
positions[3 * i + 0] = x * xScale + minX;
|
|
5679
5690
|
positions[3 * i + 1] = -y * yScale + maxY;
|
|
5680
5691
|
positions[3 * i + 2] = terrain[pixelIdx];
|
|
5681
|
-
texCoords[2 * i + 0] = x /
|
|
5682
|
-
texCoords[2 * i + 1] = y /
|
|
5692
|
+
texCoords[2 * i + 0] = x / effectiveWidth;
|
|
5693
|
+
texCoords[2 * i + 1] = y / effectiveHeight;
|
|
5683
5694
|
}
|
|
5684
5695
|
return {
|
|
5685
5696
|
POSITION: { value: positions, size: 3 },
|
|
@@ -5697,7 +5708,9 @@ function getMeshAttributes(vertices, terrain, width, height, bounds) {
|
|
|
5697
5708
|
* @returns {{vertices: number[], triangles: number[]}} vertices and triangles data
|
|
5698
5709
|
*/
|
|
5699
5710
|
function getDelatinTileMesh(meshMaxError, width, height, terrain) {
|
|
5700
|
-
const
|
|
5711
|
+
const widthPlus = width === 257 ? 257 : width + 1;
|
|
5712
|
+
const heightPlus = height === 257 ? 257 : height + 1;
|
|
5713
|
+
const tin = new Delatin(terrain, widthPlus, heightPlus);
|
|
5701
5714
|
tin.run(meshMaxError);
|
|
5702
5715
|
// @ts-expect-error: Delatin instance properties 'coords' and 'triangles' are not explicitly typed in the library port
|
|
5703
5716
|
const { coords, triangles } = tin;
|
|
@@ -5765,16 +5778,15 @@ class CogTiles {
|
|
|
5765
5778
|
return this.bounds;
|
|
5766
5779
|
}
|
|
5767
5780
|
getLatLon(input) {
|
|
5768
|
-
const
|
|
5769
|
-
const
|
|
5770
|
-
const
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
];
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
}
|
|
5781
|
+
const x = input[0];
|
|
5782
|
+
const y = input[1];
|
|
5783
|
+
const lon = (x / EARTH_HALF_CIRCUMFERENCE) * 180;
|
|
5784
|
+
let lat = (y / EARTH_HALF_CIRCUMFERENCE) * 180;
|
|
5785
|
+
lat = (180 / Math.PI) * (2 * Math.atan(Math.exp((lat * Math.PI) / 180)) - Math.PI / 2);
|
|
5786
|
+
return [lon, lat];
|
|
5787
|
+
}
|
|
5788
|
+
// return cartographicPositionAdjusted;
|
|
5789
|
+
// }
|
|
5778
5790
|
/**
|
|
5779
5791
|
* Builds lookup tables for zoom levels and estimated resolutions from a Cloud Optimized GeoTIFF (COG) object.
|
|
5780
5792
|
*
|
|
@@ -5843,7 +5855,7 @@ class CogTiles {
|
|
|
5843
5855
|
}
|
|
5844
5856
|
return exactMatchIndex;
|
|
5845
5857
|
}
|
|
5846
|
-
async getTileFromImage(tileX, tileY, zoom) {
|
|
5858
|
+
async getTileFromImage(tileX, tileY, zoom, fetchSize) {
|
|
5847
5859
|
const imageIndex = this.getImageIndexForZoomLevel(zoom);
|
|
5848
5860
|
const targetImage = await this.cog.getImage(imageIndex);
|
|
5849
5861
|
// 1. Validation: Ensure the image is tiled
|
|
@@ -5877,12 +5889,11 @@ class CogTiles {
|
|
|
5877
5889
|
const windowMinY = (imgOriginY - tileMaxYMeters) / imageResolution;
|
|
5878
5890
|
// 6. Snap to Integer Grid (The "Force 256" Fix)
|
|
5879
5891
|
// We round the start position to align with the nearest pixel.
|
|
5880
|
-
|
|
5881
|
-
// This guarantees the window is exactly 256x256, preventing "off-by-one" (257px) errors.
|
|
5892
|
+
const FETCH_SIZE = fetchSize || TILE_SIZE; // Default to 256 if not provided
|
|
5882
5893
|
const startX = Math.round(windowMinX);
|
|
5883
5894
|
const startY = Math.round(windowMinY);
|
|
5884
|
-
const endX = startX +
|
|
5885
|
-
const endY = startY +
|
|
5895
|
+
const endX = startX + FETCH_SIZE;
|
|
5896
|
+
const endY = startY + FETCH_SIZE;
|
|
5886
5897
|
// --- STEP 3: CALCULATE INTERSECTION ---
|
|
5887
5898
|
// 7. Clamp the read window to the actual image dimensions
|
|
5888
5899
|
// This defines the "Safe" area we can actually read from the file.
|
|
@@ -5894,7 +5905,7 @@ class CogTiles {
|
|
|
5894
5905
|
const readHeight = validReadMaxY - validReadY;
|
|
5895
5906
|
// CHECK: If no overlap, return empty
|
|
5896
5907
|
if (readWidth <= 0 || readHeight <= 0) {
|
|
5897
|
-
return [this.createEmptyTile()];
|
|
5908
|
+
return [this.createEmptyTile(FETCH_SIZE)];
|
|
5898
5909
|
}
|
|
5899
5910
|
// 8. Calculate Offsets (Padding)
|
|
5900
5911
|
// "missingLeft" is how many blank pixels we need to insert before the image data starts.
|
|
@@ -5906,10 +5917,11 @@ class CogTiles {
|
|
|
5906
5917
|
// --- STEP 4: READ AND COMPOSITE ---
|
|
5907
5918
|
// Case A: Partial Overlap (Padding or Cropping required)
|
|
5908
5919
|
// If the tile is hanging off the edge, we need to manually reconstruct it.
|
|
5909
|
-
|
|
5920
|
+
// We strictly compare against FETCH_SIZE because that is our target buffer dimension.
|
|
5921
|
+
if (missingLeft > 0 || missingTop > 0 || readWidth < FETCH_SIZE || readHeight < FETCH_SIZE) {
|
|
5910
5922
|
/// Initialize a temporary buffer for a single band (filled with NoData)
|
|
5911
5923
|
// We will reuse this buffer for each band to save memory allocations.
|
|
5912
|
-
const tileBuffer = this.createTileBuffer(this.options.format,
|
|
5924
|
+
const tileBuffer = this.createTileBuffer(this.options.format, FETCH_SIZE);
|
|
5913
5925
|
tileBuffer.fill(this.options.noDataValue);
|
|
5914
5926
|
// if the valid window is smaller than the tile size, it gets the image size width and height, thus validRasterData.width must be used as below
|
|
5915
5927
|
const validRasterData = await targetImage.readRasters({ window });
|
|
@@ -5919,21 +5931,26 @@ class CogTiles {
|
|
|
5919
5931
|
validImageData.fill(this.options.noDataValue);
|
|
5920
5932
|
// Place the valid pixel data into the tile buffer.
|
|
5921
5933
|
for (let band = 0; band < validRasterData.length; band += 1) {
|
|
5934
|
+
// We must reset the buffer for each band, otherwise data from previous band persists in padding areas
|
|
5935
|
+
const tileBuffer = this.createTileBuffer(this.options.format, FETCH_SIZE);
|
|
5936
|
+
if (this.options.noDataValue !== undefined) {
|
|
5937
|
+
tileBuffer.fill(this.options.noDataValue);
|
|
5938
|
+
}
|
|
5922
5939
|
for (let row = 0; row < readHeight; row += 1) {
|
|
5923
5940
|
const destRow = missingTop + row;
|
|
5924
|
-
const destRowOffset = destRow *
|
|
5941
|
+
const destRowOffset = destRow * FETCH_SIZE;
|
|
5925
5942
|
const srcRowOffset = row * validRasterData.width;
|
|
5926
5943
|
for (let col = 0; col < readWidth; col += 1) {
|
|
5927
5944
|
// Compute the destination position in the tile buffer.
|
|
5928
5945
|
// We shift by the number of missing pixels (if any) at the top/left.
|
|
5929
5946
|
const destCol = missingLeft + col;
|
|
5930
|
-
// Bounds Check: Ensure we don't write outside the
|
|
5931
|
-
if (destRow <
|
|
5947
|
+
// Bounds Check: Ensure we don't write outside the allocated buffer
|
|
5948
|
+
if (destRow < FETCH_SIZE && destCol < FETCH_SIZE) {
|
|
5932
5949
|
tileBuffer[destRowOffset + destCol] = validRasterData[band][srcRowOffset + col];
|
|
5933
5950
|
}
|
|
5934
5951
|
else {
|
|
5935
5952
|
/* eslint-disable no-console */
|
|
5936
|
-
console.log(
|
|
5953
|
+
console.log(`error in assigning data to tile buffer: destRow ${destRow}, destCol ${destCol}, FETCH_SIZE ${FETCH_SIZE}`);
|
|
5937
5954
|
}
|
|
5938
5955
|
}
|
|
5939
5956
|
}
|
|
@@ -5952,28 +5969,28 @@ class CogTiles {
|
|
|
5952
5969
|
}
|
|
5953
5970
|
/**
|
|
5954
5971
|
* Creates a blank tile buffer filled with the "No Data" value.
|
|
5972
|
+
* @param size The width/height of the square tile (e.g., 256 or 257)
|
|
5955
5973
|
*/
|
|
5956
|
-
createEmptyTile() {
|
|
5957
|
-
|
|
5958
|
-
// Default to 1 channel (grayscale) if not specified
|
|
5974
|
+
createEmptyTile(size) {
|
|
5975
|
+
const s = size || this.tileSize; // Defaults to 256
|
|
5959
5976
|
const channels = this.options.numOfChannels || 1;
|
|
5960
|
-
const
|
|
5961
|
-
|
|
5962
|
-
// Float32 is standard for GeoTIFF data handling in browsers
|
|
5963
|
-
const tileData = new Float32Array(size);
|
|
5964
|
-
// 3. Fill with "No Data" value
|
|
5965
|
-
// If noDataValue is undefined, it defaults to 0
|
|
5977
|
+
const totalSize = s * s * channels;
|
|
5978
|
+
const tileData = new Float32Array(totalSize);
|
|
5966
5979
|
if (this.options.noDataValue !== undefined) {
|
|
5967
5980
|
tileData.fill(this.options.noDataValue);
|
|
5968
5981
|
}
|
|
5969
5982
|
return tileData;
|
|
5970
5983
|
}
|
|
5971
5984
|
async getTile(x, y, z, bounds, meshMaxError) {
|
|
5972
|
-
|
|
5985
|
+
let requiredSize = this.tileSize; // Default 256 for image/bitmap
|
|
5986
|
+
if (this.options.type === 'terrain') {
|
|
5987
|
+
requiredSize = this.tileSize + 1; // 257 for stitching
|
|
5988
|
+
}
|
|
5989
|
+
const tileData = await this.getTileFromImage(x, y, z, requiredSize);
|
|
5973
5990
|
return this.geo.getMap({
|
|
5974
5991
|
rasters: [tileData[0]],
|
|
5975
|
-
width:
|
|
5976
|
-
height:
|
|
5992
|
+
width: requiredSize,
|
|
5993
|
+
height: requiredSize,
|
|
5977
5994
|
bounds,
|
|
5978
5995
|
}, this.options, meshMaxError);
|
|
5979
5996
|
}
|
|
@@ -6078,7 +6095,8 @@ class CogTiles {
|
|
|
6078
6095
|
case 'Float64':
|
|
6079
6096
|
return new Float64Array(length);
|
|
6080
6097
|
default:
|
|
6081
|
-
|
|
6098
|
+
console.warn(`Unsupported data type: ${dataType}, defaulting to Float32`);
|
|
6099
|
+
return new Float32Array(length);
|
|
6082
6100
|
}
|
|
6083
6101
|
}
|
|
6084
6102
|
}
|