Skip to content

Commit

Permalink
Merge pull request #6 from sentinel-hub/fix/makeLayers-set-necessary-…
Browse files Browse the repository at this point in the history
…params

makeLayers add switch to create a specific layer object
  • Loading branch information
sinergise-anze authored Jan 29, 2020
2 parents 0458416 + 4227307 commit b14ac9f
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 82 deletions.
46 changes: 28 additions & 18 deletions src/layer/AbstractSentinelHubV3Layer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import axios from 'axios';

import { getAuthToken } from 'src/auth';
import { getAuthToken, isAuthTokenSet } from 'src/auth';
import { BBox } from 'src/bbox';
import { GetMapParams, ApiType } from 'src/layer/const';
import { fetchCached } from 'src/layer/utils';
import { wmsGetMapUrl } from 'src/layer/wms';
import { processingGetMap } from 'src/layer/processing';
import { processingGetMap, createProcessingPayload, ProcessingPayload } from 'src/layer/processing';
import { AbstractLayer } from 'src/layer/AbstractLayer';

// this class provides any SHv3-specific functionality to the subclasses:
Expand Down Expand Up @@ -42,34 +42,39 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
if (this.instanceId === null || this.layerId === null) {
throw new Error('Could not fetch layer params - instanceId and layerId must be set on Layer');
}
const layersParams = await this.fetchLayersParamsFromSentinelHubLayersV3();
const layerParams = layersParams.find((l: any) => l.layerId === this.layerId);
if (!layerParams) {
throw new Error('Layer params could not be found');
}
return layerParams;
}

private async fetchLayersParamsFromSentinelHubLayersV3(forceFetch = false): Promise<object[]> {
const authToken = getAuthToken();
if (authToken === null) {
throw new Error('authToken is not set');
}
if (!this.dataset) {
throw new Error('This layer does not support Processing API (unknown dataset)');
}
if (!isAuthTokenSet) {
throw new Error('authToken is not set');
}
const authToken = getAuthToken();

const url = `${this.dataset.shServiceHostname}configuration/v1/wms/instances/${this.instanceId}/layers`;
const headers = {
Authorization: `Bearer ${authToken}`,
};
const res = await fetchCached(url, { responseType: 'json', headers: headers }, forceFetch);
const res = await fetchCached(url, { responseType: 'json', headers: headers }, false);
const layersParams = res.data.map((l: any) => ({
layerId: l.id,
...l.datasourceDefaults,
evalscript: l.styles[0].evalScript,
dataProduct: l.styles[0].dataProduct,
}));
return layersParams;

const layerParams = layersParams.find((l: any) => l.layerId === this.layerId);
if (!layerParams) {
throw new Error('Layer params could not be found');
}
return layerParams;
}

protected async updateProcessingGetMapPayload(payload: ProcessingPayload): Promise<ProcessingPayload> {
// Subclasses should override this method if they wish to supply additional
// parameters to Processing API.
// Typically, if additional layer data is needed for that, this code will be called:
// const layerParams = await this.fetchLayerParamsFromSHServiceV3();
return payload;
}

public async getMap(params: GetMapParams, api: ApiType): Promise<Blob> {
Expand All @@ -91,7 +96,12 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
throw new Error(`Could not fetch evalscript / dataProduct from service for layer ${this.layerId}`);
}
}
return processingGetMap(this.dataset, params, this.evalscript, this.dataProduct);

// allow subclasses to update payload with their own parameters:
const payload = createProcessingPayload(this.dataset, params, this.evalscript, this.dataProduct);
const updatedPayload = await this.updateProcessingGetMapPayload(payload);

return processingGetMap(this.dataset.shServiceHostname, updatedPayload);
}

return super.getMap(params, api);
Expand Down
31 changes: 16 additions & 15 deletions src/layer/LayersFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,24 +154,25 @@ export class LayersFactory {
const layersInfos = await LayersFactory.getLayersListFromBaseUrl(baseUrl);
const filteredLayersInfos =
filterLayers === null ? layersInfos : layersInfos.filter(l => filterLayers(l.layerId, l.dataset));

return filteredLayersInfos.map(({ layerId, dataset, title, description }) => {
if (dataset) {
const SHLayerClass = LayersFactory.LAYER_FROM_DATASET[dataset.id];
if (!SHLayerClass) {
throw new Error(`Dataset ${dataset.id} is not defined in LayersFactory.LAYER_FROM_DATASET`);
}
return new SHLayerClass(
LayersFactory.parseSHInstanceId(baseUrl),
layerId,
null,
null,
null,
title,
description,
);
} else {
if (!dataset) {
return new WmsLayer(baseUrl, layerId, title, description);
}

const SHLayerClass = LayersFactory.LAYER_FROM_DATASET[dataset.id];
if (!SHLayerClass) {
throw new Error(`Dataset ${dataset.id} is not defined in LayersFactory.LAYER_FROM_DATASET`);
}
return new SHLayerClass(
LayersFactory.parseSHInstanceId(baseUrl),
layerId,
null,
null,
null,
title,
description,
);
});
}
}
49 changes: 10 additions & 39 deletions src/layer/S1GRDIWAWSLayer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BBox } from 'src/bbox';
import { BackscatterCoeff, PaginatedTiles } from 'src/layer/const';
import { DATASET_AWS_S1GRD_IW } from 'src/layer/dataset';
import { ProcessingPayload } from 'src/layer/processing';

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

Expand Down Expand Up @@ -49,52 +50,22 @@ export class S1GRDIWAWSLayer extends AbstractSentinelHubV3Layer {
backscatterCoeff: BackscatterCoeff | null = BackscatterCoeff.GAMMA0_ELLIPSOID,
) {
super(instanceId, layerId, evalscript, evalscriptUrl, dataProduct, title, description);
if (!polarization) {
throw new Error('Polarization should be set');
}
this.polarization = polarization;
this.orthorectify = orthorectify;
this.backscatterCoeff = backscatterCoeff;
}

private async updateParamsViaService(): Promise<void> {
const params = await this.fetchLayerParamsFromSHServiceV3();
this.orthorectify = params['orthorectify'];
this.backscatterCoeff = params['backCoeff'];
}
protected async updateProcessingGetMapPayload(payload: ProcessingPayload): Promise<ProcessingPayload> {
const layerParams = await this.fetchLayerParamsFromSHServiceV3();

public async getOrthorectify(): Promise<boolean> {
if (this.orthorectify) {
return this.orthorectify;
}
try {
await this.updateParamsViaService();
if (this.orthorectify === null) {
throw new Error('orthorectify should not be null!');
}
return this.orthorectify;
} catch (ex) {
throw new Error(
`Parameter 'orthorectify' is not specified and there was an error fetching it: ${ex.message}`,
);
}
}
this.polarization = layerParams['polarization'];
this.backscatterCoeff = layerParams['backCoeff'];
this.orthorectify = layerParams['orthorectify'];

public async getBackscatterCoeff(): Promise<BackscatterCoeff> {
if (this.backscatterCoeff) {
return this.backscatterCoeff;
}
try {
await this.updateParamsViaService();
if (this.backscatterCoeff === null) {
throw new Error('backscatterCoeff should not be null!');
}
return this.backscatterCoeff;
} catch (ex) {
throw new Error(
`Parameter 'backscatterCoeff' is not specified and there was an error fetching it: ${ex.message}`,
);
}
payload.input.data[0].dataFilter.polarization = this.polarization;
payload.input.data[0].processing.backCoeff = this.backscatterCoeff;
payload.input.data[0].processing.orthorectify = this.orthorectify;
return payload;
}

public async findTiles(
Expand Down
2 changes: 1 addition & 1 deletion src/layer/dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const DATASET_AWS_S1GRD_IW: Dataset = {
id: 'AWS_S1GRD_IW',
shJsonGetCapabilitiesDataset: 'S1GRD',
shWmsEvalsource: 'S1GRD',
shProcessingApiDatasourceAbbreviation: 'S1GRDIWAWS',
shProcessingApiDatasourceAbbreviation: 'S1GRD',
shServiceHostname: 'https://services.sentinel-hub.com/',
searchIndexUrl: 'https://services.sentinel-hub.com/index/v3/collections/S1GRD/searchIndex',
};
24 changes: 15 additions & 9 deletions src/layer/processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ enum MosaickingOrder {
LEAST_CC = 'leastCC',
}

type ProcessingPayload = {
export type ProcessingPayload = {
input: {
bounds: {
bbox?: BBoxTurf;
Expand All @@ -36,10 +36,12 @@ type ProcessingPayload = {
maxCloudCoverage: number;
previewMode?: PreviewMode;
mosaickingOrder?: MosaickingOrder;
[key: string]: any;
};
processing?: {
upsampling?: Interpolator;
downsampling?: Interpolator;
[key: string]: any;
};
type: string;
}
Expand All @@ -61,17 +63,12 @@ type ProcessingPayload = {
dataProduct?: string;
};

export async function processingGetMap(
export function createProcessingPayload(
dataset: Dataset,
params: GetMapParams,
evalscript: string | null = null,
dataProduct: string | null = null,
): Promise<Blob> {
const authToken = getAuthToken();
if (!authToken) {
throw new Error('Must be authenticated to use Processing API');
}

): ProcessingPayload {
const { bbox } = params;

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

const response = await axios.post(`${dataset.shServiceHostname}api/v1/process`, payload, {
return payload;
}

export async function processingGetMap(shServiceHostname: string, payload: ProcessingPayload): Promise<Blob> {
const authToken = getAuthToken();
if (!authToken) {
throw new Error('Must be authenticated to use Processing API');
}

const response = await axios.post(`${shServiceHostname}api/v1/process`, payload, {
headers: {
Authorization: 'Bearer ' + authToken,
'Content-Type': 'application/json',
Expand Down
31 changes: 31 additions & 0 deletions stories/index.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,37 @@ export const S2GetMapProcessing = () => {
return img;
};

export const S1GetMapProcessingFromLayer = () => {
if (!process.env.STORYBOOK_AUTH_TOKEN) {
return '<div>Please set auth token for Processing API (STORYBOOK_AUTH_TOKEN env var)</div>';
}
setAuthToken(process.env.STORYBOOK_AUTH_TOKEN);

const img = document.createElement('img');
img.width = '512';
img.height = '512';

// getMap is async:
const perform = async () => {
const layer = new S1GRDIWAWSLayer(instanceId, 'S1GRDIWDV');

const bbox = new BBox(CRS_EPSG4326, 19, 20, 20, 21);
const getMapParams = {
bbox: bbox,
fromTime: new Date(Date.UTC(2018, 11 - 1, 22, 0, 0, 0)),
toTime: new Date(Date.UTC(2018, 12 - 1, 22, 23, 59, 59)),
width: 512,
height: 512,
format: MimeTypes.JPEG,
};
const imageBlob = await layer.getMap(getMapParams, ApiType.PROCESSING);
img.src = URL.createObjectURL(imageBlob);
};
perform().then(() => {});

return img;
};

export const WmsGetMap = () => {
const img = document.createElement('img');
img.width = '512';
Expand Down

0 comments on commit b14ac9f

Please sign in to comment.