@gisatcz/deckgl-geolib 1.12.0-dev.13 → 1.12.0-dev.14
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 +87 -85
- 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 +5 -20
- package/dist/esm/index.js +87 -85
- 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 +5 -20
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -5601,61 +5601,90 @@ class CogTiles {
|
|
|
5601
5601
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5602
5602
|
const imageIndex = this.getImageIndexForZoomLevel(zoom);
|
|
5603
5603
|
const targetImage = yield this.cog.getImage(imageIndex);
|
|
5604
|
-
// Ensure the image is tiled
|
|
5604
|
+
// 1. Validation: Ensure the image is tiled
|
|
5605
5605
|
const tileWidth = targetImage.getTileWidth();
|
|
5606
5606
|
const tileHeight = targetImage.getTileHeight();
|
|
5607
5607
|
if (!tileWidth || !tileHeight) {
|
|
5608
|
-
throw new Error('The image is not tiled.'
|
|
5608
|
+
throw new Error('GeoTIFF Error: The provided image is not tiled. '
|
|
5609
|
+
+ 'Please use "rio cogeo create --web-optimized" to fix this.');
|
|
5609
5610
|
}
|
|
5610
|
-
//
|
|
5611
|
-
// (
|
|
5612
|
-
|
|
5613
|
-
// if Y offset is large and positive (COG is far below global origin — expected)
|
|
5614
|
-
const offsetXMap = this.cogOrigin[0] - webMercatorOrigin[0];
|
|
5615
|
-
const offsetYMap = webMercatorOrigin[1] - this.cogOrigin[1];
|
|
5616
|
-
const tileResolution = (EARTH_CIRCUMFERENCE / tileWidth) / Math.pow(2, zoom);
|
|
5617
|
-
this.cogResolutionLookup[imageIndex];
|
|
5618
|
-
// Convert map offsets into pixel offsets.
|
|
5619
|
-
const offsetXPixel = Math.floor(offsetXMap / tileResolution);
|
|
5620
|
-
const offsetYPixel = Math.floor(offsetYMap / tileResolution);
|
|
5611
|
+
// --- STEP 1: CALCULATE BOUNDS IN METERS ---
|
|
5612
|
+
// 2. Get COG Metadata (image = COG)
|
|
5613
|
+
const imageResolution = this.cogResolutionLookup[imageIndex];
|
|
5621
5614
|
const imageHeight = targetImage.getHeight();
|
|
5622
5615
|
const imageWidth = targetImage.getWidth();
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5616
|
+
const [imgOriginX, imgOriginY] = this.cogOrigin;
|
|
5617
|
+
// 3. Define Web Mercator Constants
|
|
5618
|
+
// We use the class property tileSize (usually 256) as the ground truth for grid calculations
|
|
5619
|
+
const TILE_SIZE = this.tileSize;
|
|
5620
|
+
const ORIGIN_X = webMercatorOrigin[0];
|
|
5621
|
+
const ORIGIN_Y = webMercatorOrigin[1];
|
|
5622
|
+
// 4. Calculate Tile BBox in World Meters
|
|
5623
|
+
// This defines where the map expects the tile to be physically located
|
|
5624
|
+
const tileGridResolution = (EARTH_CIRCUMFERENCE / TILE_SIZE) / (Math.pow(2, zoom));
|
|
5625
|
+
const tileMinXMeters = ORIGIN_X + (tileX * TILE_SIZE * tileGridResolution);
|
|
5626
|
+
const tileMaxYMeters = ORIGIN_Y - (tileY * TILE_SIZE * tileGridResolution);
|
|
5627
|
+
// Note: We don't strictly need MaxX/MinY meters for the start calculation,
|
|
5628
|
+
// but they are useful if debugging the full meter footprint.
|
|
5629
|
+
// --- STEP 2: CONVERT TO PIXEL COORDINATES ---
|
|
5630
|
+
// 5. Calculate precise floating-point start position relative to the image
|
|
5631
|
+
const windowMinX = (tileMinXMeters - imgOriginX) / imageResolution;
|
|
5632
|
+
const windowMinY = (imgOriginY - tileMaxYMeters) / imageResolution;
|
|
5633
|
+
// 6. Snap to Integer Grid (The "Force 256" Fix)
|
|
5634
|
+
// We round the start position to align with the nearest pixel.
|
|
5635
|
+
// Crucially, we calculate endX/endY by adding tileSize to startX/startY.
|
|
5636
|
+
// This guarantees the window is exactly 256x256, preventing "off-by-one" (257px) errors.
|
|
5637
|
+
const startX = Math.round(windowMinX);
|
|
5638
|
+
const startY = Math.round(windowMinY);
|
|
5639
|
+
const endX = startX + TILE_SIZE;
|
|
5640
|
+
const endY = startY + TILE_SIZE;
|
|
5641
|
+
// --- STEP 3: CALCULATE INTERSECTION ---
|
|
5642
|
+
// 7. Clamp the read window to the actual image dimensions
|
|
5643
|
+
// This defines the "Safe" area we can actually read from the file.
|
|
5644
|
+
const validReadX = Math.max(0, startX);
|
|
5645
|
+
const validReadY = Math.max(0, startY);
|
|
5646
|
+
const validReadMaxX = Math.min(imageWidth, endX);
|
|
5647
|
+
const validReadMaxY = Math.min(imageHeight, endY);
|
|
5648
|
+
const readWidth = validReadMaxX - validReadX;
|
|
5649
|
+
const readHeight = validReadMaxY - validReadY;
|
|
5650
|
+
// CHECK: If no overlap, return empty
|
|
5651
|
+
if (readWidth <= 0 || readHeight <= 0) {
|
|
5652
|
+
return [this.createEmptyTile()];
|
|
5653
|
+
}
|
|
5654
|
+
// 8. Calculate Offsets (Padding)
|
|
5655
|
+
// "missingLeft" is how many blank pixels we need to insert before the image data starts.
|
|
5656
|
+
// Logic: If we wanted to read from -50 (startX), but clamped to 0 (validReadX),
|
|
5657
|
+
// we are missing the first 50 pixels.
|
|
5658
|
+
const missingLeft = validReadX - startX;
|
|
5659
|
+
const missingTop = validReadY - startY;
|
|
5660
|
+
const window = [validReadX, validReadY, validReadMaxX, validReadMaxY];
|
|
5661
|
+
// --- STEP 4: READ AND COMPOSITE ---
|
|
5662
|
+
// Case A: Partial Overlap (Padding or Cropping required)
|
|
5663
|
+
// If the tile is hanging off the edge, we need to manually reconstruct it.
|
|
5664
|
+
if (missingLeft > 0 || missingTop > 0 || readWidth < tileWidth || readHeight < tileHeight) {
|
|
5665
|
+
/// Initialize a temporary buffer for a single band (filled with NoData)
|
|
5666
|
+
// We will reuse this buffer for each band to save memory allocations.
|
|
5641
5667
|
const tileBuffer = this.createTileBuffer(this.options.format, tileWidth);
|
|
5642
5668
|
tileBuffer.fill(this.options.noDataValue);
|
|
5643
|
-
// if the valid window is smaller than tile size, it gets the image size width and height, thus validRasterData.width must be used as below
|
|
5669
|
+
// 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
|
|
5644
5670
|
const validRasterData = yield targetImage.readRasters({ window });
|
|
5645
5671
|
// FOR MULTI-BAND - the result is one array with sequentially typed bands, firstly all data for the band 0, then for band 1
|
|
5646
5672
|
// I think this is less practical then the commented solution above, but I do it so it works with the code in GeoImage.ts in deck.gl-geoimage in function getColorValue.
|
|
5647
5673
|
const validImageData = Array(validRasterData.length * validRasterData[0].length);
|
|
5648
5674
|
validImageData.fill(this.options.noDataValue);
|
|
5649
5675
|
// Place the valid pixel data into the tile buffer.
|
|
5650
|
-
for (let band = 0; band < validRasterData.length; band
|
|
5651
|
-
for (let row = 0; row <
|
|
5652
|
-
|
|
5676
|
+
for (let band = 0; band < validRasterData.length; band += 1) {
|
|
5677
|
+
for (let row = 0; row < readHeight; row += 1) {
|
|
5678
|
+
const destRow = missingTop + row;
|
|
5679
|
+
const destRowOffset = destRow * TILE_SIZE;
|
|
5680
|
+
const srcRowOffset = row * validRasterData.width;
|
|
5681
|
+
for (let col = 0; col < readWidth; col += 1) {
|
|
5653
5682
|
// Compute the destination position in the tile buffer.
|
|
5654
5683
|
// We shift by the number of missing pixels (if any) at the top/left.
|
|
5655
|
-
const destRow = missingTop + row;
|
|
5656
5684
|
const destCol = missingLeft + col;
|
|
5685
|
+
// Bounds Check: Ensure we don't write outside the 256x256 buffer
|
|
5657
5686
|
if (destRow < tileWidth && destCol < tileHeight) {
|
|
5658
|
-
tileBuffer[
|
|
5687
|
+
tileBuffer[destRowOffset + destCol] = validRasterData[band][srcRowOffset + col];
|
|
5659
5688
|
}
|
|
5660
5689
|
else {
|
|
5661
5690
|
console.log('error in assigning data to tile buffer');
|
|
@@ -5668,12 +5697,32 @@ class CogTiles {
|
|
|
5668
5697
|
}
|
|
5669
5698
|
return [validImageData];
|
|
5670
5699
|
}
|
|
5671
|
-
//
|
|
5700
|
+
// Case B: Perfect Match (Optimization)
|
|
5701
|
+
// If the read window is exactly 256x256 and aligned, we can read directly interleaved.
|
|
5702
|
+
// console.log("Perfect aligned read");
|
|
5672
5703
|
const tileData = yield targetImage.readRasters({ window, interleave: true });
|
|
5673
5704
|
// console.log(`data that starts at the left top corner of the tile ${tileX}, ${tileY}`);
|
|
5674
5705
|
return [tileData];
|
|
5675
5706
|
});
|
|
5676
5707
|
}
|
|
5708
|
+
/**
|
|
5709
|
+
* Creates a blank tile buffer filled with the "No Data" value.
|
|
5710
|
+
*/
|
|
5711
|
+
createEmptyTile() {
|
|
5712
|
+
// 1. Determine the size
|
|
5713
|
+
// Default to 1 channel (grayscale) if not specified
|
|
5714
|
+
const channels = this.options.numOfChannels || 1;
|
|
5715
|
+
const size = this.tileSize * this.tileSize * channels;
|
|
5716
|
+
// 2. Create the array
|
|
5717
|
+
// Float32 is standard for GeoTIFF data handling in browsers
|
|
5718
|
+
const tileData = new Float32Array(size);
|
|
5719
|
+
// 3. Fill with "No Data" value
|
|
5720
|
+
// If noDataValue is undefined, it defaults to 0
|
|
5721
|
+
if (this.options.noDataValue !== undefined) {
|
|
5722
|
+
tileData.fill(this.options.noDataValue);
|
|
5723
|
+
}
|
|
5724
|
+
return tileData;
|
|
5725
|
+
}
|
|
5677
5726
|
getTile(x, y, z, bounds, meshMaxError) {
|
|
5678
5727
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5679
5728
|
const tileData = yield this.getTileFromImage(x, y, z);
|
|
@@ -5766,53 +5815,6 @@ class CogTiles {
|
|
|
5766
5815
|
getNumberOfChannels(image) {
|
|
5767
5816
|
return image.getSamplesPerPixel();
|
|
5768
5817
|
}
|
|
5769
|
-
/**
|
|
5770
|
-
* Calculates the intersection between a tile bounding box and a COG bounding box,
|
|
5771
|
-
* returning the intersection window in image pixel space (relative to COG offsets),
|
|
5772
|
-
* along with how much blank space (nodata) appears on the left and top of the tile.
|
|
5773
|
-
*
|
|
5774
|
-
* @param {number[]} tileBbox - Tile bounding box: [minX, minY, maxX, maxY]
|
|
5775
|
-
* @param {number[]} cogBbox - COG bounding box: [minX, minY, maxX, maxY]
|
|
5776
|
-
* @param {number} offsetXPixel - X offset of the COG origin in pixel space
|
|
5777
|
-
* @param {number} offsetYPixel - Y offset of the COG origin in pixel space
|
|
5778
|
-
* @param {number} tileSize - Size of the tile in pixels (default: 256)
|
|
5779
|
-
* @returns {[number, number, number[] | null, number, number]}
|
|
5780
|
-
* An array containing:
|
|
5781
|
-
* - width of the intersection
|
|
5782
|
-
* - height of the intersection
|
|
5783
|
-
* - pixel-space window: [startX, startY, endX, endY] or null if no overlap
|
|
5784
|
-
* - missingLeft: padding pixels on the left
|
|
5785
|
-
* - missingTop: padding pixels on the top
|
|
5786
|
-
*/
|
|
5787
|
-
getIntersectionBBox(tileBbox, cogBbox, offsetXPixel = 0, offsetYPixel = 0, tileSize = 256) {
|
|
5788
|
-
const interLeft = Math.max(tileBbox[0], cogBbox[0]);
|
|
5789
|
-
const interTop = Math.max(tileBbox[1], cogBbox[1]);
|
|
5790
|
-
const interRight = Math.min(tileBbox[2], cogBbox[2]);
|
|
5791
|
-
const interBottom = Math.min(tileBbox[3], cogBbox[3]);
|
|
5792
|
-
const width = Math.max(0, interRight - interLeft);
|
|
5793
|
-
const height = Math.max(0, interBottom - interTop);
|
|
5794
|
-
let window = null;
|
|
5795
|
-
let missingLeft = 0;
|
|
5796
|
-
let missingTop = 0;
|
|
5797
|
-
if (width > 0 && height > 0) {
|
|
5798
|
-
window = [
|
|
5799
|
-
interLeft - offsetXPixel,
|
|
5800
|
-
interTop - offsetYPixel,
|
|
5801
|
-
interRight - offsetXPixel,
|
|
5802
|
-
interBottom - offsetYPixel,
|
|
5803
|
-
];
|
|
5804
|
-
// Padding from the tile origin to valid data start
|
|
5805
|
-
missingLeft = interLeft - tileBbox[0];
|
|
5806
|
-
missingTop = interTop - tileBbox[1];
|
|
5807
|
-
}
|
|
5808
|
-
return [
|
|
5809
|
-
width,
|
|
5810
|
-
height,
|
|
5811
|
-
window,
|
|
5812
|
-
missingLeft,
|
|
5813
|
-
missingTop,
|
|
5814
|
-
];
|
|
5815
|
-
}
|
|
5816
5818
|
/**
|
|
5817
5819
|
* Retrieves the PlanarConfiguration value from a GeoTIFF image.
|
|
5818
5820
|
*
|