Remove multi-source restrictions and fix alpha
This commit is contained in:
@@ -6,7 +6,8 @@ docs: >
|
|||||||
The GeoTIFF layer in this example calculates the Normalized Difference Vegetation Index (NDVI)
|
The GeoTIFF layer in this example calculates the Normalized Difference Vegetation Index (NDVI)
|
||||||
and Normalized Difference Water Index (NDWI) from two cloud-optimized Sentinel 2 GeoTIFFs: one
|
and Normalized Difference Water Index (NDWI) from two cloud-optimized Sentinel 2 GeoTIFFs: one
|
||||||
with 10 m resolution and red and a near infrared bands, and one with 60 m resolution and a short
|
with 10 m resolution and red and a near infrared bands, and one with 60 m resolution and a short
|
||||||
wave infrared channel. The NDVI is shown as green, the NDWI as blue.
|
wave infrared channel. The NDVI is shown as green, the NDWI as blue. The 4th band is the alpha
|
||||||
|
band, which gets added when a source has a `nodata` value configured.
|
||||||
tags: "cog, ndvi, ndwi, sentinel, geotiff"
|
tags: "cog, ndvi, ndwi, sentinel, geotiff"
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -7,17 +7,16 @@ const source = new GeoTIFF({
|
|||||||
sources: [
|
sources: [
|
||||||
{
|
{
|
||||||
url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R10m.tif',
|
url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R10m.tif',
|
||||||
samples: [2],
|
bands: [2, 3],
|
||||||
max: 65535,
|
min: 0,
|
||||||
},
|
nodata: 0,
|
||||||
{
|
|
||||||
url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R10m.tif',
|
|
||||||
samples: [3],
|
|
||||||
max: 65535,
|
max: 65535,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R60m.tif',
|
url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R60m.tif',
|
||||||
samples: [8],
|
bands: [8],
|
||||||
|
min: 0,
|
||||||
|
nodata: 0,
|
||||||
max: 65535,
|
max: 65535,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -51,6 +50,8 @@ const map = new Map({
|
|||||||
['*', 255, ndvi],
|
['*', 255, ndvi],
|
||||||
// blue: NDWI
|
// blue: NDWI
|
||||||
['*', 255, ndwi],
|
['*', 255, ndwi],
|
||||||
|
// alpha
|
||||||
|
['band', 4],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
source,
|
source,
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ import {toSize} from '../size.js';
|
|||||||
* the configured min and max.
|
* the configured min and max.
|
||||||
* @property {number} [max] The maximum source data value. Rendered values are scaled from 0 to 1 based on
|
* @property {number} [max] The maximum source data value. Rendered values are scaled from 0 to 1 based on
|
||||||
* the configured min and max.
|
* the configured min and max.
|
||||||
* @property {number} [nodata] Values to discard.
|
* @property {number} [nodata] Values to discard. When provided, an additional band (alpha) will be added
|
||||||
* @property {Array<number>} [samples] Indices of the samples to be read from. If not provided, all samples
|
* to the data.
|
||||||
* will be read.
|
* @property {Array<number>} [bands] Indices of the bands to be read from. If not provided, all bands will
|
||||||
|
* be read.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let workerPool;
|
let workerPool;
|
||||||
@@ -179,7 +180,7 @@ class GeoTIFFSource extends DataTile {
|
|||||||
this.resolutionFactors_ = new Array(numSources);
|
this.resolutionFactors_ = new Array(numSources);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {Array<number>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.samplesPerPixel_;
|
this.samplesPerPixel_;
|
||||||
@@ -239,7 +240,7 @@ class GeoTIFFSource extends DataTile {
|
|||||||
let origin;
|
let origin;
|
||||||
let tileSizes;
|
let tileSizes;
|
||||||
let resolutions;
|
let resolutions;
|
||||||
let samplesPerPixel;
|
const samplesPerPixel = new Array(sources.length);
|
||||||
let minZoom = 0;
|
let minZoom = 0;
|
||||||
|
|
||||||
const sourceCount = sources.length;
|
const sourceCount = sources.length;
|
||||||
@@ -254,16 +255,10 @@ class GeoTIFFSource extends DataTile {
|
|||||||
|
|
||||||
for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) {
|
for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) {
|
||||||
const image = images[imageIndex];
|
const image = images[imageIndex];
|
||||||
const wantedSamples = this.sourceInfo_[sourceIndex].samples;
|
const wantedSamples = this.sourceInfo_[sourceIndex].bands;
|
||||||
const imageSamplesPerPixel = wantedSamples
|
samplesPerPixel[sourceIndex] = wantedSamples
|
||||||
? wantedSamples.length
|
? wantedSamples.length
|
||||||
: image.getSamplesPerPixel();
|
: image.getSamplesPerPixel();
|
||||||
if (!samplesPerPixel) {
|
|
||||||
samplesPerPixel = imageSamplesPerPixel;
|
|
||||||
} else {
|
|
||||||
const message = `Band count mismatch for source ${sourceIndex}, got ${imageSamplesPerPixel} but expected ${samplesPerPixel}`;
|
|
||||||
assertEqual(samplesPerPixel, imageSamplesPerPixel, 0, message);
|
|
||||||
}
|
|
||||||
const level = imageCount - (imageIndex + 1);
|
const level = imageCount - (imageIndex + 1);
|
||||||
|
|
||||||
if (!sourceExtent) {
|
if (!sourceExtent) {
|
||||||
@@ -347,12 +342,6 @@ class GeoTIFFSource extends DataTile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceCount > 1 && samplesPerPixel !== 1) {
|
|
||||||
throw new Error(
|
|
||||||
'Expected single band GeoTIFFs when using multiple sources'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.samplesPerPixel_ = samplesPerPixel;
|
this.samplesPerPixel_ = samplesPerPixel;
|
||||||
const sourceInfo = this.sourceInfo_;
|
const sourceInfo = this.sourceInfo_;
|
||||||
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
||||||
@@ -361,15 +350,12 @@ class GeoTIFFSource extends DataTile {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let additionalBands = 0;
|
const additionalBands = this.addAlpha_ ? 1 : 0;
|
||||||
if (this.addAlpha_) {
|
this.bandCount =
|
||||||
if (sourceCount === 2 && samplesPerPixel === 1) {
|
samplesPerPixel.reduce((accumulator, value) => {
|
||||||
additionalBands = 2;
|
accumulator += value;
|
||||||
} else {
|
return accumulator;
|
||||||
additionalBands = 1;
|
}, 0) + additionalBands;
|
||||||
}
|
|
||||||
}
|
|
||||||
this.bandCount = samplesPerPixel * sourceCount + additionalBands;
|
|
||||||
|
|
||||||
const tileGrid = new TileGrid({
|
const tileGrid = new TileGrid({
|
||||||
extent: extent,
|
extent: extent,
|
||||||
@@ -408,7 +394,8 @@ class GeoTIFFSource extends DataTile {
|
|||||||
window: pixelBounds,
|
window: pixelBounds,
|
||||||
width: size[0],
|
width: size[0],
|
||||||
height: size[1],
|
height: size[1],
|
||||||
samples: source.samples,
|
samples: source.bands,
|
||||||
|
fillValue: source.nodata,
|
||||||
pool: getWorkerPool(),
|
pool: getWorkerPool(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -418,9 +405,9 @@ class GeoTIFFSource extends DataTile {
|
|||||||
|
|
||||||
return Promise.all(requests).then(function (sourceSamples) {
|
return Promise.all(requests).then(function (sourceSamples) {
|
||||||
const data = new Uint8ClampedArray(dataLength);
|
const data = new Uint8ClampedArray(dataLength);
|
||||||
|
let dataIndex = 0;
|
||||||
for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) {
|
for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) {
|
||||||
let transparent = addAlpha;
|
let transparent = addAlpha;
|
||||||
const sourceOffset = pixelIndex * bandCount;
|
|
||||||
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
||||||
const source = sourceInfo[sourceIndex];
|
const source = sourceInfo[sourceIndex];
|
||||||
let min = source.min;
|
let min = source.min;
|
||||||
@@ -437,10 +424,9 @@ class GeoTIFFSource extends DataTile {
|
|||||||
|
|
||||||
const nodata = source.nodata;
|
const nodata = source.nodata;
|
||||||
|
|
||||||
const sampleOffset = sourceOffset + sourceIndex * samplesPerPixel;
|
|
||||||
for (
|
for (
|
||||||
let sampleIndex = 0;
|
let sampleIndex = 0;
|
||||||
sampleIndex < samplesPerPixel;
|
sampleIndex < samplesPerPixel[sourceIndex];
|
||||||
++sampleIndex
|
++sampleIndex
|
||||||
) {
|
) {
|
||||||
const sourceValue =
|
const sourceValue =
|
||||||
@@ -448,18 +434,21 @@ class GeoTIFFSource extends DataTile {
|
|||||||
|
|
||||||
const value = gain * sourceValue + bias;
|
const value = gain * sourceValue + bias;
|
||||||
if (!addAlpha) {
|
if (!addAlpha) {
|
||||||
data[sampleOffset + sampleIndex] = value;
|
data[dataIndex] = value;
|
||||||
} else {
|
} else {
|
||||||
if (sourceValue !== nodata) {
|
if (sourceValue !== nodata) {
|
||||||
transparent = false;
|
transparent = false;
|
||||||
data[sampleOffset + sampleIndex] = value;
|
data[dataIndex] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dataIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addAlpha && !transparent) {
|
|
||||||
data[sampleOffset + samplesPerPixel] = 255;
|
|
||||||
}
|
}
|
||||||
|
if (addAlpha) {
|
||||||
|
if (!transparent) {
|
||||||
|
data[dataIndex] = 255;
|
||||||
|
}
|
||||||
|
dataIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user