Skip to content

Commit b14ac9f

Browse files
Merge pull request #6 from sentinel-hub/fix/makeLayers-set-necessary-params
makeLayers add switch to create a specific layer object
2 parents 0458416 + 4227307 commit b14ac9f

File tree

6 files changed

+101
-82
lines changed

6 files changed

+101
-82
lines changed

src/layer/AbstractSentinelHubV3Layer.ts

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import axios from 'axios';
22

3-
import { getAuthToken } from 'src/auth';
3+
import { getAuthToken, isAuthTokenSet } from 'src/auth';
44
import { BBox } from 'src/bbox';
55
import { GetMapParams, ApiType } from 'src/layer/const';
66
import { fetchCached } from 'src/layer/utils';
77
import { wmsGetMapUrl } from 'src/layer/wms';
8-
import { processingGetMap } from 'src/layer/processing';
8+
import { processingGetMap, createProcessingPayload, ProcessingPayload } from 'src/layer/processing';
99
import { AbstractLayer } from 'src/layer/AbstractLayer';
1010

1111
// this class provides any SHv3-specific functionality to the subclasses:
@@ -42,34 +42,39 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
4242
if (this.instanceId === null || this.layerId === null) {
4343
throw new Error('Could not fetch layer params - instanceId and layerId must be set on Layer');
4444
}
45-
const layersParams = await this.fetchLayersParamsFromSentinelHubLayersV3();
46-
const layerParams = layersParams.find((l: any) => l.layerId === this.layerId);
47-
if (!layerParams) {
48-
throw new Error('Layer params could not be found');
49-
}
50-
return layerParams;
51-
}
52-
53-
private async fetchLayersParamsFromSentinelHubLayersV3(forceFetch = false): Promise<object[]> {
54-
const authToken = getAuthToken();
55-
if (authToken === null) {
56-
throw new Error('authToken is not set');
57-
}
5845
if (!this.dataset) {
5946
throw new Error('This layer does not support Processing API (unknown dataset)');
6047
}
48+
if (!isAuthTokenSet) {
49+
throw new Error('authToken is not set');
50+
}
51+
const authToken = getAuthToken();
52+
6153
const url = `${this.dataset.shServiceHostname}configuration/v1/wms/instances/${this.instanceId}/layers`;
6254
const headers = {
6355
Authorization: `Bearer ${authToken}`,
6456
};
65-
const res = await fetchCached(url, { responseType: 'json', headers: headers }, forceFetch);
57+
const res = await fetchCached(url, { responseType: 'json', headers: headers }, false);
6658
const layersParams = res.data.map((l: any) => ({
6759
layerId: l.id,
6860
...l.datasourceDefaults,
6961
evalscript: l.styles[0].evalScript,
7062
dataProduct: l.styles[0].dataProduct,
7163
}));
72-
return layersParams;
64+
65+
const layerParams = layersParams.find((l: any) => l.layerId === this.layerId);
66+
if (!layerParams) {
67+
throw new Error('Layer params could not be found');
68+
}
69+
return layerParams;
70+
}
71+
72+
protected async updateProcessingGetMapPayload(payload: ProcessingPayload): Promise<ProcessingPayload> {
73+
// Subclasses should override this method if they wish to supply additional
74+
// parameters to Processing API.
75+
// Typically, if additional layer data is needed for that, this code will be called:
76+
// const layerParams = await this.fetchLayerParamsFromSHServiceV3();
77+
return payload;
7378
}
7479

7580
public async getMap(params: GetMapParams, api: ApiType): Promise<Blob> {
@@ -91,7 +96,12 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
9196
throw new Error(`Could not fetch evalscript / dataProduct from service for layer ${this.layerId}`);
9297
}
9398
}
94-
return processingGetMap(this.dataset, params, this.evalscript, this.dataProduct);
99+
100+
// allow subclasses to update payload with their own parameters:
101+
const payload = createProcessingPayload(this.dataset, params, this.evalscript, this.dataProduct);
102+
const updatedPayload = await this.updateProcessingGetMapPayload(payload);
103+
104+
return processingGetMap(this.dataset.shServiceHostname, updatedPayload);
95105
}
96106

97107
return super.getMap(params, api);

src/layer/LayersFactory.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,24 +154,25 @@ export class LayersFactory {
154154
const layersInfos = await LayersFactory.getLayersListFromBaseUrl(baseUrl);
155155
const filteredLayersInfos =
156156
filterLayers === null ? layersInfos : layersInfos.filter(l => filterLayers(l.layerId, l.dataset));
157+
157158
return filteredLayersInfos.map(({ layerId, dataset, title, description }) => {
158-
if (dataset) {
159-
const SHLayerClass = LayersFactory.LAYER_FROM_DATASET[dataset.id];
160-
if (!SHLayerClass) {
161-
throw new Error(`Dataset ${dataset.id} is not defined in LayersFactory.LAYER_FROM_DATASET`);
162-
}
163-
return new SHLayerClass(
164-
LayersFactory.parseSHInstanceId(baseUrl),
165-
layerId,
166-
null,
167-
null,
168-
null,
169-
title,
170-
description,
171-
);
172-
} else {
159+
if (!dataset) {
173160
return new WmsLayer(baseUrl, layerId, title, description);
174161
}
162+
163+
const SHLayerClass = LayersFactory.LAYER_FROM_DATASET[dataset.id];
164+
if (!SHLayerClass) {
165+
throw new Error(`Dataset ${dataset.id} is not defined in LayersFactory.LAYER_FROM_DATASET`);
166+
}
167+
return new SHLayerClass(
168+
LayersFactory.parseSHInstanceId(baseUrl),
169+
layerId,
170+
null,
171+
null,
172+
null,
173+
title,
174+
description,
175+
);
175176
});
176177
}
177178
}

src/layer/S1GRDIWAWSLayer.ts

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BBox } from 'src/bbox';
22
import { BackscatterCoeff, PaginatedTiles } from 'src/layer/const';
33
import { DATASET_AWS_S1GRD_IW } from 'src/layer/dataset';
4+
import { ProcessingPayload } from 'src/layer/processing';
45

56
import { AbstractSentinelHubV3Layer } from 'src/layer/AbstractSentinelHubV3Layer';
67

@@ -49,52 +50,22 @@ export class S1GRDIWAWSLayer extends AbstractSentinelHubV3Layer {
4950
backscatterCoeff: BackscatterCoeff | null = BackscatterCoeff.GAMMA0_ELLIPSOID,
5051
) {
5152
super(instanceId, layerId, evalscript, evalscriptUrl, dataProduct, title, description);
52-
if (!polarization) {
53-
throw new Error('Polarization should be set');
54-
}
5553
this.polarization = polarization;
5654
this.orthorectify = orthorectify;
5755
this.backscatterCoeff = backscatterCoeff;
5856
}
5957

60-
private async updateParamsViaService(): Promise<void> {
61-
const params = await this.fetchLayerParamsFromSHServiceV3();
62-
this.orthorectify = params['orthorectify'];
63-
this.backscatterCoeff = params['backCoeff'];
64-
}
58+
protected async updateProcessingGetMapPayload(payload: ProcessingPayload): Promise<ProcessingPayload> {
59+
const layerParams = await this.fetchLayerParamsFromSHServiceV3();
6560

66-
public async getOrthorectify(): Promise<boolean> {
67-
if (this.orthorectify) {
68-
return this.orthorectify;
69-
}
70-
try {
71-
await this.updateParamsViaService();
72-
if (this.orthorectify === null) {
73-
throw new Error('orthorectify should not be null!');
74-
}
75-
return this.orthorectify;
76-
} catch (ex) {
77-
throw new Error(
78-
`Parameter 'orthorectify' is not specified and there was an error fetching it: ${ex.message}`,
79-
);
80-
}
81-
}
61+
this.polarization = layerParams['polarization'];
62+
this.backscatterCoeff = layerParams['backCoeff'];
63+
this.orthorectify = layerParams['orthorectify'];
8264

83-
public async getBackscatterCoeff(): Promise<BackscatterCoeff> {
84-
if (this.backscatterCoeff) {
85-
return this.backscatterCoeff;
86-
}
87-
try {
88-
await this.updateParamsViaService();
89-
if (this.backscatterCoeff === null) {
90-
throw new Error('backscatterCoeff should not be null!');
91-
}
92-
return this.backscatterCoeff;
93-
} catch (ex) {
94-
throw new Error(
95-
`Parameter 'backscatterCoeff' is not specified and there was an error fetching it: ${ex.message}`,
96-
);
97-
}
65+
payload.input.data[0].dataFilter.polarization = this.polarization;
66+
payload.input.data[0].processing.backCoeff = this.backscatterCoeff;
67+
payload.input.data[0].processing.orthorectify = this.orthorectify;
68+
return payload;
9869
}
9970

10071
public async findTiles(

src/layer/dataset.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export const DATASET_AWS_S1GRD_IW: Dataset = {
5656
id: 'AWS_S1GRD_IW',
5757
shJsonGetCapabilitiesDataset: 'S1GRD',
5858
shWmsEvalsource: 'S1GRD',
59-
shProcessingApiDatasourceAbbreviation: 'S1GRDIWAWS',
59+
shProcessingApiDatasourceAbbreviation: 'S1GRD',
6060
shServiceHostname: 'https://services.sentinel-hub.com/',
6161
searchIndexUrl: 'https://services.sentinel-hub.com/index/v3/collections/S1GRD/searchIndex',
6262
};

src/layer/processing.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ enum MosaickingOrder {
1616
LEAST_CC = 'leastCC',
1717
}
1818

19-
type ProcessingPayload = {
19+
export type ProcessingPayload = {
2020
input: {
2121
bounds: {
2222
bbox?: BBoxTurf;
@@ -36,10 +36,12 @@ type ProcessingPayload = {
3636
maxCloudCoverage: number;
3737
previewMode?: PreviewMode;
3838
mosaickingOrder?: MosaickingOrder;
39+
[key: string]: any;
3940
};
4041
processing?: {
4142
upsampling?: Interpolator;
4243
downsampling?: Interpolator;
44+
[key: string]: any;
4345
};
4446
type: string;
4547
}
@@ -61,17 +63,12 @@ type ProcessingPayload = {
6163
dataProduct?: string;
6264
};
6365

64-
export async function processingGetMap(
66+
export function createProcessingPayload(
6567
dataset: Dataset,
6668
params: GetMapParams,
6769
evalscript: string | null = null,
6870
dataProduct: string | null = null,
69-
): Promise<Blob> {
70-
const authToken = getAuthToken();
71-
if (!authToken) {
72-
throw new Error('Must be authenticated to use Processing API');
73-
}
74-
71+
): ProcessingPayload {
7572
const { bbox } = params;
7673

7774
const payload: ProcessingPayload = {
@@ -151,7 +148,16 @@ export async function processingGetMap(
151148
throw new Error('Either evalscript or dataProduct should be defined with Processing API');
152149
}
153150

154-
const response = await axios.post(`${dataset.shServiceHostname}api/v1/process`, payload, {
151+
return payload;
152+
}
153+
154+
export async function processingGetMap(shServiceHostname: string, payload: ProcessingPayload): Promise<Blob> {
155+
const authToken = getAuthToken();
156+
if (!authToken) {
157+
throw new Error('Must be authenticated to use Processing API');
158+
}
159+
160+
const response = await axios.post(`${shServiceHostname}api/v1/process`, payload, {
155161
headers: {
156162
Authorization: 'Bearer ' + authToken,
157163
'Content-Type': 'application/json',

stories/index.stories.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,37 @@ export const S2GetMapProcessing = () => {
123123
return img;
124124
};
125125

126+
export const S1GetMapProcessingFromLayer = () => {
127+
if (!process.env.STORYBOOK_AUTH_TOKEN) {
128+
return '<div>Please set auth token for Processing API (STORYBOOK_AUTH_TOKEN env var)</div>';
129+
}
130+
setAuthToken(process.env.STORYBOOK_AUTH_TOKEN);
131+
132+
const img = document.createElement('img');
133+
img.width = '512';
134+
img.height = '512';
135+
136+
// getMap is async:
137+
const perform = async () => {
138+
const layer = new S1GRDIWAWSLayer(instanceId, 'S1GRDIWDV');
139+
140+
const bbox = new BBox(CRS_EPSG4326, 19, 20, 20, 21);
141+
const getMapParams = {
142+
bbox: bbox,
143+
fromTime: new Date(Date.UTC(2018, 11 - 1, 22, 0, 0, 0)),
144+
toTime: new Date(Date.UTC(2018, 12 - 1, 22, 23, 59, 59)),
145+
width: 512,
146+
height: 512,
147+
format: MimeTypes.JPEG,
148+
};
149+
const imageBlob = await layer.getMap(getMapParams, ApiType.PROCESSING);
150+
img.src = URL.createObjectURL(imageBlob);
151+
};
152+
perform().then(() => {});
153+
154+
return img;
155+
};
156+
126157
export const WmsGetMap = () => {
127158
const img = document.createElement('img');
128159
img.width = '512';

0 commit comments

Comments
 (0)