Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions configure/src/metaconfigs/layer-image-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@
},
{
"name": "Cloud-Optimized GeoTiffs (COG)",
"components": [
{
"field": "cogBands",
"name": "Tile Bands",
"description": "Which bands from the COG from which to generate tiles. Defaults to '1,2,3' as RGB or '1' if it's a Transformed 32-bit COG. Can be a single number or a comma-separated list of numbers. Order matters.",
"type": "textarray",
"width": 4
},
{
"field": "cogBandsQuery",
"name": "Query Bands",
"description": "Which bands from the COG upon which to perform queries. Defaults to value of 'Tile Bands'.",
"type": "textarray",
"width": 4
}
]
},
{
"components": [
{
"field": "cogTransform",
Expand Down
86 changes: 72 additions & 14 deletions src/essence/Basics/Map_/Map_.js
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,36 @@ function makeDataLayer(layerObj) {
allLayersLoaded()
}

function getPixelValue(georaster, values) {
// Default behavior from
// https://github.com/GeoTIFF/georaster-layer-for-leaflet/blob/b57bd2039cd23aca1e4e01efcd6963eb3fc4bbb4/src/georaster-layer-for-leaflet.ts#L888-L910
const numberOfValues = values.length;
if (numberOfValues == 1) {
const value = values[0]
if (georaster.palette) {
const [r, g, b, a] = georaster.palette[value]
return `rgba(${r},${g},${b},${a / 255})`
} else if (georaster.georasters[0].mins) {
const { mins, ranges } = georaster.georasters[0]
return georaster.scale((values[0] - mins[0]) / ranges[0]).hex()
} else if (georaster.currentStats.mins) {
const min = georaster.currentStats.mins[0]
const range = georaster.currentStats.ranges[0]
return georaster.scale((values[0] - min) / range).hex()
}
} else if (numberOfValues === 2) {
return `rgb(${values[0]},${values[1]},0)`
} else if (numberOfValues === 3) {
return `rgb(${values[0]},${values[1]},${values[2]})`
} else if (numberOfValues === 4) {
return `rgba(${values[0]},${values[1]},${values[2]},${values[3] / 255})`
} else if (numberOfValues > 4) {
// Use the first 3 bands by default
return `rgb(${values[0]},${values[1]},${values[2]})`
}
}


function makeImageLayer(layerObj) {
let layerUrl = L_.getUrl(layerObj.type, layerObj.url, layerObj)
if (!F_.isUrlAbsolute(layerUrl)) {
Expand All @@ -1506,22 +1536,11 @@ function makeImageLayer(layerObj) {

const cogColormap = F_.getIn(L_.layers.data[layerObj.name], 'cogColormap')

let b = layerObj.cogBands;

parseGeoraster(layerUrl)
.then((georaster) => {
let pixelValuesToColorFn = null
if (
F_.getIn(
L_.layers.data[layerObj.name],
'variables.hideNoDataValue'
) === true
) {
pixelValuesToColorFn = (values) => {
// https://github.com/GeoTIFF/georaster-layer-for-leaflet/issues/16
return values[0] === georaster.noDataValue
? null
: `rgb(${values[0]},${values[1]},${values[2]})`
}
}

const imageInfo = F_.getIn(
L_.layers.data[layerObj.name],
Expand Down Expand Up @@ -1638,12 +1657,51 @@ function makeImageLayer(layerObj) {
}
}

// Handle the case where we do not want to hide noDataValue
if (
georaster.noDataValue != null &&
georaster.noDataValue === pixelValue
) {
return [0, 0, 0]
}

return evaluate_cmap(
scaledPixelValue,
colormap || IMAGE_DEFAULT_COLOR_RAMP,
reverse
)
}
} else {
if (b != null && Math.max(...b) > georaster.numberOfRasters) {
console.warn(`WARNING - User input band values must be within range of available bands in the image.`
+ ` Ignoring user input bands.`
+ `\nUser input bands: ${b}`
+ `\nAvailable bands in the image: ${georaster.numberOfRasters}`)
}

pixelValuesToColorFn = (values) => {
const updatedValues = [...values];
// If user overrides the band order in the configure page
if (b != null) {
// User input band values must be within the range of available bands in the COG
if (Math.max(...b) <= values.length) {
updatedValues[0] = values[b[0] - 1] || 0
updatedValues[1] = values[b[1] - 1] || 0
updatedValues[2] = values[b[2] - 1] || 0
}
}

const haveDataForAllBands = updatedValues.every(value => value !== undefined && value !== georaster.noDataValue)

// If the user does not want to hide the no data values
if (!hideNoDataValue && !haveDataForAllBands) {
return getPixelValue(georaster, updatedValues)
}

if (haveDataForAllBands) {
return getPixelValue(georaster, updatedValues)
}
}
}

L_.layers.layer[layerObj.name] = new GeoRasterLayer({
Expand All @@ -1667,7 +1725,7 @@ function makeImageLayer(layerObj) {
allLayersLoaded()
})
.catch((e) => {
console.warn(`WARNING - Unable to load image: ${layerUrl}`)
console.warn(`WARNING - Unable to load image: ${layerUrl}\nError: ${e}`)

L_._layersLoaded[L_._layersOrdered.indexOf(layerObj.name)] = true
L_.layers.layer[layerObj.name] = null
Expand Down
43 changes: 41 additions & 2 deletions src/essence/Tools/Identifier/IdentifierTool.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,12 +349,40 @@ var IdentifierTool = {
IdentifierTool.vars.data[
IdentifierTool.activeLayerNames[i]
] || {}

let bands = 1

if (L_.layers.data[IdentifierTool.activeLayerNames[i]].type === 'image') {
let georasters = L_.layers.layer[IdentifierTool.activeLayerNames[i]]?.georasters[0]
let b =
L_.layers.data[IdentifierTool.activeLayerNames[i]].cogBandsQuery ||
L_.layers.data[IdentifierTool.activeLayerNames[i]].cogBands
if (b != null && Math.max(...b) > georasters.numberOfRasters) {
console.warn(`WARNING - User input band values must be within range of available bands in the image.`
+ ` Ignoring user input bands.`
+ `\nUser input bands: ${b}`
+ `\nAvailable bands in the image: ${georasters.numberOfRasters}`)
// Default to maximum of 3 bands
bands = Math.min(georasters.numberOfRasters, 3)
} else if (b != null) {
// If the cog band is overwritten in the settings
bands = [...b]
} else if (georasters && georasters.numberOfRasters > 0) {
let georasters = L_.layers.layer[IdentifierTool.activeLayerNames[i]]?.georasters[0]
if (georasters.numberOfRasters <= 3) {
bands = georasters.numberOfRasters
} else {
// Default to 3 bands if there are more than 3 bands
bands = 3 // georasters.numberOfRasters
}
}
}
IdentifierTool.vars.data[
IdentifierTool.activeLayerNames[i]
].data = [
{
url: IdentifierTool.activeLayerURLs[i],
bands: 1,
bands: bands,
units:
L_.layers.data[IdentifierTool.activeLayerNames[i]]
.cogUnits || '',
Expand Down Expand Up @@ -804,6 +832,17 @@ function queryDataValue(url, lng, lat, numBands, layerUUID, callback) {
dataPath = 'Missions/' + L_.mission + '/' + url
}

let bands = '[[1,' + numBands + ']]'
if (L_.layers.data[layerUUID].type == 'image') {
if (Array.isArray(numBands)) {
if (numBands.length > 1) {
bands = [...numBands]
} else {
bands = '[' + numBands + ']'
}
}
}

dataPath = IdentifierTool.fillURLParameters(dataPath, layerUUID)

calls.api(
Expand All @@ -813,7 +852,7 @@ function queryDataValue(url, lng, lat, numBands, layerUUID, callback) {
x: lat,
y: lng,
xyorll: 'll',
bands: '[[1,' + numBands + ']]',
bands: bands,
path: dataPath,
},
(data) => {
Expand Down