@gisatcz/deckgl-geolib 1.12.0-dev.3 → 1.12.0-dev.5

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
@@ -5292,6 +5292,8 @@ class GeoImage {
5292
5292
  return [minValue, maxValue];
5293
5293
  }
5294
5294
  getColorValue(dataArray, options, arrayLength, numOfChannels = 1) {
5295
+ // const rgb = chroma.random().rgb(); // [R, G, B]
5296
+ // const randomColor = [...rgb, 120];
5295
5297
  const colorScale = chroma.scale(options.colorScale).domain(options.colorScaleValueRange);
5296
5298
  // channel index is equal to channel number - 1
5297
5299
  let pixel = options.useChannelIndex === null ? 0 : options.useChannelIndex;
@@ -5311,6 +5313,7 @@ class GeoImage {
5311
5313
  }) : undefined;
5312
5314
  for (let i = 0; i < arrayLength; i += 4) {
5313
5315
  let pixelColor = options.nullColor;
5316
+ // let pixelColor = randomColor;
5314
5317
  // FIXME
5315
5318
  // eslint-disable-next-line max-len
5316
5319
  if ((!Number.isNaN(dataArray[pixel])) && (options.noDataValue === undefined || dataArray[pixel] !== options.noDataValue)) {
@@ -5608,36 +5611,30 @@ class CogTiles {
5608
5611
  // Convert map offsets into pixel offsets.
5609
5612
  const offsetXPixel = Math.floor(offsetXMap / tileResolution);
5610
5613
  const offsetYPixel = Math.floor(offsetYMap / tileResolution);
5611
- // Calculate the pixel boundaries for the tile.
5612
- const window = [
5613
- tileX * tileWidth - offsetXPixel,
5614
- tileY * tileHeight - offsetYPixel,
5615
- (tileX + 1) * tileWidth - offsetXPixel,
5616
- (tileY + 1) * tileHeight - offsetYPixel, // endY (exclusive)
5617
- ];
5618
- const [windowStartX, windowStartY, windowEndX, windowEndY] = window;
5619
5614
  const imageHeight = targetImage.getHeight();
5620
5615
  const imageWidth = targetImage.getWidth();
5621
- // Determine the effective (valid) window inside the image:
5622
- const effectiveStartX = Math.max(0, windowStartX);
5623
- const effectiveStartY = Math.max(0, windowStartY);
5624
- const effectiveEndX = windowEndX;
5625
- const effectiveEndY = windowEndY;
5626
- // Calculate how many pixels are missing from the left and top due to negative windowStart.
5627
- const missingLeft = Math.max(0, 0 - windowStartX);
5628
- const missingTop = Math.max(0, 0 - windowStartY);
5629
- // Read only the valid window from the image.
5630
- const validWindow = [effectiveStartX, effectiveStartY, effectiveEndX, effectiveEndY];
5616
+ // approach by comparing bboxes of tile and cog image
5617
+ const tilePixelBbox = [
5618
+ tileX * tileWidth,
5619
+ tileY * tileHeight,
5620
+ (tileX + 1) * tileWidth,
5621
+ (tileY + 1) * tileHeight,
5622
+ ];
5623
+ const cogPixelBBox = [
5624
+ offsetXPixel,
5625
+ offsetYPixel,
5626
+ offsetXPixel + imageWidth,
5627
+ offsetYPixel + imageHeight,
5628
+ ];
5629
+ const intersecion = this.getIntersectionBBox(tilePixelBbox, cogPixelBBox, offsetXPixel, offsetYPixel, tileWidth);
5630
+ const [validWidth, validHeight, window, missingLeft, missingTop] = intersecion;
5631
5631
  // Read the raster data for the tile window with shifted origin.
5632
- if (missingLeft > 0 || missingTop > 0) {
5632
+ if (missingLeft > 0 || missingTop > 0 || validWidth < tileWidth || validHeight < tileHeight) {
5633
5633
  // Prepare the final tile buffer and fill it with noDataValue.
5634
5634
  const tileBuffer = this.createTileBuffer(this.options.format, tileWidth);
5635
5635
  tileBuffer.fill(this.options.noDataValue);
5636
- // Calculate the width of the valid window.
5637
- const validWidth = Math.min(imageWidth, effectiveEndX - effectiveStartX);
5638
- const validHeight = Math.min(imageHeight, effectiveEndY - effectiveStartY);
5639
5636
  // 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
5640
- const validRasterData = yield targetImage.readRasters({ window: validWindow });
5637
+ const validRasterData = yield targetImage.readRasters({ window });
5641
5638
  // FOR MULTI-BAND - the result is one array with sequentially typed bands, firstly all data for the band 0, then for band 1
5642
5639
  // 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.
5643
5640
  const validImageData = Array(validRasterData.length * validRasterData[0].length);
@@ -5725,24 +5722,33 @@ class CogTiles {
5725
5722
  }
5726
5723
  /**
5727
5724
  * Extracts the noData value from a GeoTIFF.js image.
5728
- * Returns the noData value as a number if available, otherwise undefined.
5725
+ * Returns the noData value as a number (including NaN) if available, otherwise undefined.
5729
5726
  *
5730
5727
  * @param {GeoTIFFImage} image - The GeoTIFF.js image.
5731
- * @returns {number|undefined} The noData value as a number, or undefined if not available.
5728
+ * @returns {number|undefined} The noData value, possibly NaN, or undefined if not set or invalid.
5732
5729
  */
5733
5730
  getNoDataValue(image) {
5734
- // Attempt to retrieve the noData value via the GDAL method.
5735
5731
  const noDataRaw = image.getGDALNoData();
5736
5732
  if (noDataRaw === undefined || noDataRaw === null) {
5737
- console.log('noDataValue is undefined or null,raster might be displayed incorrectly.');
5738
- // No noData value is defined
5733
+ console.warn('No noData value defined raster might be rendered incorrectly.');
5734
+ return undefined;
5735
+ }
5736
+ const cleaned = String(noDataRaw).replace(/\0/g, '').trim();
5737
+ if (cleaned === '') {
5738
+ console.warn('noData value is an empty string after cleanup.');
5739
+ return undefined;
5740
+ }
5741
+ const parsed = Number(cleaned);
5742
+ // Allow NaN if explicitly declared
5743
+ if (cleaned.toLowerCase() === 'nan') {
5744
+ return NaN;
5745
+ }
5746
+ // If not declared as "nan" and still parsed to NaN, it's an error
5747
+ if (Number.isNaN(parsed)) {
5748
+ console.warn(`Failed to parse numeric noData value: '${cleaned}'`);
5739
5749
  return undefined;
5740
5750
  }
5741
- // In geotiff.js, the noData value is typically returned as a string.
5742
- // Clean up the string by removing any null characters or extra whitespace.
5743
- const cleanedValue = String(noDataRaw).replace(/\0/g, '').trim();
5744
- const parsedValue = Number(cleanedValue);
5745
- return Number.isNaN(parsedValue) ? undefined : parsedValue;
5751
+ return parsed;
5746
5752
  }
5747
5753
  /**
5748
5754
  * Retrieves the number of channels (samples per pixel) in a GeoTIFF image.
@@ -5753,6 +5759,53 @@ class CogTiles {
5753
5759
  getNumberOfChannels(image) {
5754
5760
  return image.getSamplesPerPixel();
5755
5761
  }
5762
+ /**
5763
+ * Calculates the intersection between a tile bounding box and a COG bounding box,
5764
+ * returning the intersection window in image pixel space (relative to COG offsets),
5765
+ * along with how much blank space (nodata) appears on the left and top of the tile.
5766
+ *
5767
+ * @param {number[]} tileBbox - Tile bounding box: [minX, minY, maxX, maxY]
5768
+ * @param {number[]} cogBbox - COG bounding box: [minX, minY, maxX, maxY]
5769
+ * @param {number} offsetXPixel - X offset of the COG origin in pixel space
5770
+ * @param {number} offsetYPixel - Y offset of the COG origin in pixel space
5771
+ * @param {number} tileSize - Size of the tile in pixels (default: 256)
5772
+ * @returns {[number, number, number[] | null, number, number]}
5773
+ * An array containing:
5774
+ * - width of the intersection
5775
+ * - height of the intersection
5776
+ * - pixel-space window: [startX, startY, endX, endY] or null if no overlap
5777
+ * - missingLeft: padding pixels on the left
5778
+ * - missingTop: padding pixels on the top
5779
+ */
5780
+ getIntersectionBBox(tileBbox, cogBbox, offsetXPixel = 0, offsetYPixel = 0, tileSize = 256) {
5781
+ const interLeft = Math.max(tileBbox[0], cogBbox[0]);
5782
+ const interTop = Math.max(tileBbox[1], cogBbox[1]);
5783
+ const interRight = Math.min(tileBbox[2], cogBbox[2]);
5784
+ const interBottom = Math.min(tileBbox[3], cogBbox[3]);
5785
+ const width = Math.max(0, interRight - interLeft);
5786
+ const height = Math.max(0, interBottom - interTop);
5787
+ let window = null;
5788
+ let missingLeft = 0;
5789
+ let missingTop = 0;
5790
+ if (width > 0 && height > 0) {
5791
+ window = [
5792
+ interLeft - offsetXPixel,
5793
+ interTop - offsetYPixel,
5794
+ interRight - offsetXPixel,
5795
+ interBottom - offsetYPixel,
5796
+ ];
5797
+ // Padding from the tile origin to valid data start
5798
+ missingLeft = interLeft - tileBbox[0];
5799
+ missingTop = interTop - tileBbox[1];
5800
+ }
5801
+ return [
5802
+ width,
5803
+ height,
5804
+ window,
5805
+ missingLeft,
5806
+ missingTop,
5807
+ ];
5808
+ }
5756
5809
  /**
5757
5810
  * Retrieves the PlanarConfiguration value from a GeoTIFF image.
5758
5811
  *
@@ -5956,7 +6009,7 @@ class CogBitmapLayer extends core.CompositeLayer {
5956
6009
  // opacity,
5957
6010
  // cogBitmapOptions,
5958
6011
  clampToTerrain,
5959
- cogBitmapOptions,
6012
+ cogBitmapOptions.useChannel,
5960
6013
  ],
5961
6014
  // renderSubLayers: [cogBitmapOptions],
5962
6015
  },