Skip to content

Commit f1948db

Browse files
committed
Support for STAC 1.1, datacube subtype and other fixes from dependencies
1 parent 5ecbf8f commit f1948db

File tree

9 files changed

+46
-40
lines changed

9 files changed

+46
-40
lines changed

docs/geotiff.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ What is required by back-ends to give users an ideal experience with GeoTiff ima
1616
5. The [`PhotometricInterpretation`](https://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html) of the image should be set to `1` (BlackIsZero) if an RGB interpretation is not clear. If RGB is set as interpretation (`2`) and you have more than 3 samples per pixel ([`SamplesPerPixel`](https://www.awaresystems.be/imaging/tiff/tifftags/samplesperpixel.html)), the [`ExtraSamples`](https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html) should be set.
1717
6. [`ColorMap`](https://www.awaresystems.be/imaging/tiff/tifftags/colormap.html)s are supported.
1818
7. For batch jobs, the STAC metadata is recommended to contain per asset:
19-
1. The no-data value either in `file:nodata` (deprecated) or in `nodata` in `raster:bands`
20-
2. The `minimum` and `maximum` values per band in the `statistics` object in `raster:bands`
21-
3. A band `name` either in `raster:bands` (unspecified) or `eo:bands`
22-
4. The projection in `proj:epsg` (recommended), `proj:wkt2` (not well suported by OpenLayers) or `proj:proj4` (deprecated by STAC)
19+
1. The no-data value either in `file:nodata` (deprecated) or in `nodata` in `bands`
20+
2. The `minimum` and `maximum` values per band in the `statistics` object in `bands`
21+
3. A band `name` in `bands`
22+
4. The projection in `proj:code` (recommended), `proj:wkt2` (not well suported by OpenLayers) or `proj:proj4` (deprecated by STAC)
2323
5. The `type` must be set to the corresponding media type (see below)
2424
8. For synchronous execution, the `Content-Type` in the header of the response must be set to the corresponding media type (see below)
2525

package.json

+5-3
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@
5050
"@musement/iso-duration": "^1.0.0",
5151
"@openeo/js-client": "^2.6.0",
5252
"@openeo/js-commons": "^1.4.1",
53-
"@openeo/js-processgraphs": "^1.3.0",
54-
"@openeo/vue-components": "^2.16.0",
53+
"@openeo/js-processgraphs": "^1.4.0",
54+
"@openeo/vue-components": "^2.17.0",
55+
"@radiantearth/stac-fields": "^1.5.0-beta.2",
56+
"@radiantearth/stac-migrate": "^2.0.0-beta.1",
5557
"@tmcw/togeojson": "^5.5.0",
5658
"ajv": "^6.12.6",
5759
"axios": "^1.0.0",
@@ -62,7 +64,7 @@
6264
"core-js": "^3.7.0",
6365
"jsonlint-mod": "^1.7.6",
6466
"luxon": "^2.4.0",
65-
"node-polyfill-webpack-plugin": "^2.0.0",
67+
"node-polyfill-webpack-plugin": "^4.0.0",
6668
"ol": "^9.2.0",
6769
"ol-ext": "^4.0.21",
6870
"proj4": "^2.7.5",

src/components/JobPanel.vue

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import Utils from '../utils.js';
2929
import { Job } from '@openeo/js-client';
3030
import { cancellableRequest, showCancellableRequestError, CancellableRequestError } from './cancellableRequest';
3131
import FieldMixin from './FieldMixin';
32+
import StacMigrate from '@radiantearth/stac-migrate';
3233
3334
const WorkPanelMixinInstance = WorkPanelMixin('jobs', 'batch job', 'batch jobs');
3435
@@ -261,6 +262,7 @@ export default {
261262
if (updatedJob.status === 'finished') {
262263
try {
263264
result = await updatedJob.getResultsAsStac();
265+
result = StacMigrate.stac(result, false);
264266
} catch (error) {
265267
Utils.exception(this, error, "Load Results Error: " + Utils.getResourceTitle(updatedJob));
266268
}
@@ -342,6 +344,7 @@ export default {
342344
// Doesn't need to go through job store as it doesn't change job-related data
343345
try {
344346
let stac = await job.getResultsAsStac();
347+
stac = StacMigrate.stac(stac, false);
345348
this.broadcast('viewJobResults', stac, job);
346349
} catch(error) {
347350
Utils.exception(this, error, 'View Result Error: ' + Utils.getResourceTitle(job));
@@ -351,6 +354,7 @@ export default {
351354
// Doesn't need to go through job store as it doesn't change job-related data
352355
try {
353356
let result = await job.getResultsAsStac();
357+
result = StacMigrate.stac(result, false);
354358
if(Utils.size(result.assets) == 0) {
355359
Utils.error(this, 'No results available for job "' + Utils.getResourceTitle(job) + '".');
356360
return;
@@ -363,6 +367,7 @@ export default {
363367
async shareResults(job) {
364368
if (this.canShare) {
365369
let result = await job.getResultsAsStac();
370+
result = StacMigrate.stac(result, false);
366371
let url;
367372
let link;
368373
if (Array.isArray(result.links)) {

src/components/datatypes/SelectBox.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default {
4747
let collection = this.$store.state.collections.find(c => c.id == this.context);
4848
if (Utils.isObject(collection)) {
4949
try {
50-
state = collection.summaries['eo:bands'].map(band => band.name);
50+
state = collection.summaries['bands'].map(band => band.name);
5151
} catch (error) {}
5252
if (state.length === 0 && Utils.isObject(collection['cube:dimensions'])) {
5353
try {

src/components/maps/projManager.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export default class ProjManager {
3737
// Get projection details from STAC (todo: add collection support)
3838
static async addFromStac(stac) {
3939
if (Utils.isObject(stac) && Utils.isObject(stac.properties)) {
40-
if (stac.properties['proj:epsg']) {
41-
return await ProjManager.get(stac.properties['proj:epsg']);
40+
if (stac.properties['proj:code']) {
41+
return await ProjManager.get(stac.properties['proj:code']);
4242
}
4343
else if (stac.properties['proj:wkt2']) {
4444
return ProjManager.add(stac.id, stac.properties['proj:wkt2']);
@@ -68,9 +68,9 @@ export default class ProjManager {
6868
}
6969

7070
// Get projection from database
71-
let proj = await import('../../assets/epsg-proj.json');
72-
if (id in proj) {
73-
return ProjManager.add(code, proj[id][0], proj[id][1]);
71+
let epsg = await import('../../assets/epsg-proj.json');
72+
if (id in epsg) {
73+
return ProjManager.add(code, epsg[id][0], epsg[id][1]);
7474
}
7575

7676
// No projection found

src/components/modals/CollectionModal.vue

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import Modal from './Modal.vue';
2222
import Collection from '../Collection.vue';
2323
import Utils from '../../utils.js';
24+
import StacMigrate from '@radiantearth/stac-migrate';
2425
2526
export default {
2627
name: 'CollectionModal',
@@ -82,7 +83,7 @@ export default {
8283
}
8384
let next = await this.itemsIterator.next();
8485
if (next && next.value && !next.done) {
85-
this.items.push(next.value);
86+
this.items.push(StacMigrate.item(next.value, null, false));
8687
}
8788
}
8889
}

src/components/wizards/SpectralIndices.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export default {
128128
return false;
129129
}
130130
131-
if (c.summaries && !c.summaries["eo:bands"]) {
131+
if (c.summaries && !c.summaries["bands"]) {
132132
// Has summaries (so is likely fully loaded), but has no bands that we can work with
133133
return false;
134134
}
@@ -196,7 +196,7 @@ export default {
196196
return b.toJSON();
197197
},
198198
getAvailableBands(collection) {
199-
let bands = collection?.summaries && collection?.summaries["eo:bands"];
199+
let bands = collection?.summaries && collection?.summaries["bands"];
200200
if (Array.isArray(bands)) {
201201
let availableBands = {};
202202
const stacNames = Object.values(MAPPING);
@@ -206,7 +206,7 @@ export default {
206206
if (!band.name) {
207207
continue; // Ignore bands without a name
208208
}
209-
let i = stacNames.indexOf(band['common_name']);
209+
let i = stacNames.indexOf(band['eo:common_name']);
210210
if (i !== -1) {
211211
availableBands[asiNames[i]] = band;
212212
}

src/formats/geotiff.js

+18-23
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class GeoTIFF extends SupportedFormat {
1616

1717
constructor(asset, stac) {
1818
super(asset, "MapViewer", 'fa-map', { removableLayers: true });
19-
this.bands = [];
20-
this.nodata = [];
19+
this._bands = [];
20+
this._nodata = [];
2121
this.img = null;
2222
this.projection = null;
2323
this.extent = null;
@@ -53,17 +53,12 @@ class GeoTIFF extends SupportedFormat {
5353

5454
// Get nodata from STAC file:nodata
5555
if (Array.isArray(this['file:nodata']) && this['file:nodata'].length > 0) {
56-
this.nodata = Utils.parseNodata(this['file:nodata']);
56+
this._nodata = Utils.parseNodata(this['file:nodata']);
5757
}
5858

59-
// Get band names from STAC eo:bands
60-
if (Array.isArray(this['eo:bands']) && this['eo:bands'].length > 0) {
61-
this['eo:bands'].forEach((band, i) => this.setBandInfo(i, { name: band.name }));
62-
}
63-
64-
// Get min/max/nodata from STAC raster:bands
65-
if (Array.isArray(this['raster:bands']) && this['raster:bands'].length > 0) {
66-
this['raster:bands'].forEach((band, i) => {
59+
// Get min/max/nodata from STAC bands
60+
if (Array.isArray(this.bands) && this.bands.length > 0) {
61+
this.bands.forEach((band, i) => {
6762
// Get name from band
6863
if (band.name) {
6964
this.setBandInfo(i, {
@@ -80,8 +75,8 @@ class GeoTIFF extends SupportedFormat {
8075
}
8176

8277
// per-band no-data values are not supported, simply read the no-data from the first occurance if not defined yet
83-
if (this.nodata.length === 0 && typeof band.nodata !== 'undefined') {
84-
this.nodata.push(Utils.parseNodata(band.nodata));
78+
if (this._nodata.length === 0 && typeof band.nodata !== 'undefined') {
79+
this._nodata.push(Utils.parseNodata(band.nodata));
8580
}
8681
});
8782
}
@@ -103,10 +98,10 @@ class GeoTIFF extends SupportedFormat {
10398
// Use min/max for data type (as fallback)
10499
try {
105100
let dummy = this.img.getArrayForSample(i);
106-
if (!Number.isFinite(this.bands[i].min)) {
101+
if (!Number.isFinite(this._bands[i].min)) {
107102
data.min = this.getMinForDataType(dummy);
108103
}
109-
if (!Number.isFinite(this.bands[i].max)) {
104+
if (!Number.isFinite(this._bands[i].max)) {
110105
data.max = this.getMaxForDataType(dummy);
111106
}
112107
} catch (error) {}
@@ -129,8 +124,8 @@ class GeoTIFF extends SupportedFormat {
129124

130125
// get no-data values if needed
131126
let nodata = this.img.getGDALNoData();
132-
if (this.nodata.length === 0 && nodata !== null) {
133-
this.nodata.push(nodata);
127+
if (this._nodata.length === 0 && nodata !== null) {
128+
this._nodata.push(nodata);
134129
}
135130
}
136131

@@ -176,7 +171,7 @@ class GeoTIFF extends SupportedFormat {
176171
Math.trunc(map[i] / 65536 * 256),
177172
Math.trunc(map[i + greenOffset] / 65536 * 256),
178173
Math.trunc(map[i + blueOffset] / 65536 * 256),
179-
this.nodata.includes(i) ? 0 : 1
174+
this._nodata.includes(i) ? 0 : 1
180175
]);
181176
}
182177
}
@@ -196,11 +191,11 @@ class GeoTIFF extends SupportedFormat {
196191
}
197192

198193
setBandInfo(i, data) {
199-
if (this.bands[i]) {
200-
Object.assign(this.bands[i], data);
194+
if (this._bands[i]) {
195+
Object.assign(this._bands[i], data);
201196
}
202197
else {
203-
this.bands.push(Object.assign({ id: i + 1 }, data));
198+
this._bands.push(Object.assign({ id: i + 1 }, data));
204199
}
205200
}
206201

@@ -209,15 +204,15 @@ class GeoTIFF extends SupportedFormat {
209204
}
210205

211206
getNoData() {
212-
return this.nodata;
207+
return this._nodata;
213208
}
214209

215210
getContext() {
216211
return this.stac;
217212
}
218213

219214
getBands() {
220-
return this.bands;
215+
return this._bands;
221216
}
222217

223218
getProjection() {

src/store/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Vuex from 'vuex';
33

44
import { OpenEO, FileTypes, Formula } from '@openeo/js-client';
55
import { ProcessRegistry } from '@openeo/js-commons';
6+
import StacMigrate from '@radiantearth/stac-migrate';
67
import Utils from '../utils.js';
78
import ProcessRegistryExtension from '../registryExtension.js';
89
import Config from '../../config';
@@ -272,6 +273,7 @@ export default new Vuex.Store({
272273
let collection = cx.state.collections.find(c => c.id === id);
273274
if (!collection || !collection._loaded) {
274275
collection = await cx.state.connection.describeCollection(id);
276+
collection = StacMigrate.collection(collection, false);
275277
cx.commit('fillCollection', collection);
276278
}
277279
return collection;
@@ -384,6 +386,7 @@ export default new Vuex.Store({
384386
},
385387
collections(state, data) {
386388
state.collections = data.collections
389+
.map(c => StacMigrate.collection(c, false))
387390
.filter(c => (typeof c.id === 'string'))
388391
.sort(Utils.sortById);
389392
},

0 commit comments

Comments
 (0)