Commit a9f93e0f authored by Michael Auer's avatar Michael Auer
Browse files

Merge branch '5-support-ratio-groupby-boundary-requests' into 'master'

Resolve "Support ratio/groupBy/boundary requests"

Closes #5

See merge request !5
parents f915e778 909b602e
......@@ -12,6 +12,24 @@ Additionally it includes `ohsome2x-cli`, a command-line tool with a configuratio
This library/tool makes use of the ohsome API (https://api.ohsome.org) as data backend and many other great open-source libraries.
Currently supported ohsome API query types are:
```
//standard
elements/count/groupBy/boundary
elements/length/groupBy/boundary
elements/area/groupBy/boundary
elements/perimeter/groupBy/boundary
//ratio
elements/count/ratio/groupBy/boundary
elements/length/ratio/groupBy/boundary
elements/area/ratio/groupBy/boundary
elements/perimeter/ratio/groupBy/boundary
//contributors
users/count/groupBy/boundary
```
This software is developed by [HeiGIT](https://heigit.org):
<img src="https://heigit.org/wp-content/uploads/2018/01/HeiGIT_Logo_cut-505x100@2x.png" alt="HeiGIT Logo" height="80px" width="404px">
......
......@@ -315,13 +315,28 @@ let configureOhsomeQuery = async () => {
{name: 'elements/length/groupBy/boundary'},
{name: 'elements/area/groupBy/boundary'},
{name: 'elements/perimeter/groupBy/boundary'},
{name: 'elements/count/ratio/groupBy/boundary'},
{name: 'elements/length/ratio/groupBy/boundary'},
{name: 'elements/area/ratio/groupBy/boundary'},
{name: 'elements/perimeter/ratio/groupBy/boundary'},
{name: 'users/count/groupBy/boundary'}
],
default: 'elements/count/groupBy/boundary'
},
{
name: 'filter',
message: 'Specify an ohsome-api filter text (e.g. building=* and building!=no and geometry:polygon):\n More info on syntax: https://docs.ohsome.org/ohsome-api/stable/filter.html \n>'
message: 'filter: Specify an ohsome-api filter text. (Syntax: e.g. building=* and building!=no and geometry:polygon):\n More info on syntax: https://docs.ohsome.org/ohsome-api/stable/filter.html \n>',
when: (answers) => {return !(answers.queryType.includes('/ratio'))}
},
{
name: 'filter',
message: 'filter: Specify an ohsome-api filter text. This will define the denominator value for the ratio result. (Syntax: e.g. building=* and building!=no and geometry:polygon):\n More info on syntax: https://docs.ohsome.org/ohsome-api/stable/filter.html \n>',
when: (answers) => {return answers.queryType.includes('/ratio')}
},
{
name: 'filter2',
message: 'filter2: Specify an ohsome-api filter text. This will define the nominator value for the ratio result. (Syntax: e.g. building=* and building!=no and geometry:polygon):\n More info on syntax: https://docs.ohsome.org/ohsome-api/stable/filter.html \n>',
when: (answers) => {return answers.queryType.includes('/ratio')}
},
{
name: 'time',
......
......@@ -15,6 +15,11 @@ export abstract class FeatureType {
*/
abstract async getFeatureCount(): Promise<number>
/**
* @return string the sourceIdType for usage in JS. Either 'number' or 'string'
*/
abstract async getIdJsType(): Promise<string>
/**
* @return GeoJSON<FeatureCollection>
**/
......
......@@ -54,6 +54,11 @@ export class GeoJsonFeatureType extends FeatureType {
}
};
async getIdJsType(): Promise<string> {
const geojson = await this.getFeatures();
return typeof geojson.features[0].properties!.id
}
/**
* returns the total number of features
*/
......@@ -134,21 +139,52 @@ export class GeoJsonFeatureType extends FeatureType {
return featureCollection;
}
static removeFeaturesByPropertyValues (featureCollection: FeatureCollection, propertyValueMap: {[property:string]: any}) {
let filteredFeatures = featureCollection.features.filter(
(feature) => {
if (feature.properties === null) {
return true; //keep features lacking the indicated property
} else {
const properties = feature.properties;
let allValuesTrue = true;
for (const property in propertyValueMap) {
if (property in properties){
allValuesTrue = allValuesTrue && properties[property] === propertyValueMap[property];
} else{
//not all properties exist, test cannot be made -> keep feature
return true;
}
}
return !allValuesTrue;
}
}
);
featureCollection.features = filteredFeatures;
return featureCollection;
}
/**
* Creates a GeoJSON Feature Collection with either geometry:null, with original geometries from the query if sourceFeatureCollection is provided or with reprojected geometries if sourceFeatureCollection AND transformToWebmercator is given
* @param ohsomeGroupByBoundaryResponse response from ohsome-API, either ohsomeJSON or ohsomeGroupByBoundaryCSV
* @param sourceIdType the data type of the source feature ids. Necessary because in the case that numbers are stored as stings this cannot inferred from the ohsome csv-response.
* @param horizontal boolean if the result featureType should have many or one timestamp column
* @param sourceFeatureCollection if not undefined, will be used to join input geometry (bpolys) and ohsome-API results
* @param transformToWebmercator if sourceFeatureCollection is provided, should output be reprojected from WGS84 to (EPSG:4326) to Webmercator (EPSG:3857)?
**/
static fromOhsome(ohsomeGroupByBoundaryResponse: any, horizontal: boolean, sourceFeatureCollection?: FeatureCollection, transformToWebmercator?: boolean): FeatureCollection {
static fromOhsome(ohsomeGroupByBoundaryResponse: any, sourceIdType: string, horizontal: boolean, sourceFeatureCollection?: FeatureCollection, transformToWebmercator?: boolean): FeatureCollection {
const ohsomeResults = ohsomeGroupByBoundaryResponse;
let ohsomeResults = ohsomeGroupByBoundaryResponse;
const isCSV = (typeof ohsomeResults == 'string');
let isContributionView: boolean = true;
const castId = function(id:number|string){
return (sourceIdType == typeof id)? id: (sourceIdType == 'number')? parseFloat(<string>id) : id.toString();
}
let isContributionView: boolean;
let isRatio: boolean;
if (isCSV) {
......@@ -160,24 +196,36 @@ export class GeoJsonFeatureType extends FeatureType {
// check columnheaders for contributionview column names
const columns = lines[i].trim().split(";");
isContributionView = columns.includes("fromTimestamp") && columns.includes("toTimestamp");
// check isRatio: for non-grouped columnName is "ratio", for grouped response columnName is <someId>_ratio
isRatio = columns.includes("ratio") || columns.some((e: string)=> e.includes("_ratio"));
break;
}
}
} else {
//JSON Response
// JSON Response
// check isContributionView
const hasFromTimestamps = ohsomeResults.groupByResult[0].result[0].fromTimestamp !== undefined;
const hasToTimestamps = ohsomeResults.groupByResult[0].result[0].toTimestamp !== undefined;
isContributionView = hasFromTimestamps && hasToTimestamps;
// check isRatio
isRatio = ohsomeResults.groupByResult[0].result[0].ratio !== undefined;
}
const ohsomeGroupByBoundaryCSV = {
delimiter: ';',
dynamicTyping: (isContributionView) ? (col: any) => (!(col == 0 || col == 1)) : (col: any) => (col != 0), //first (or first two) column is timestamp and should remain string not auto converted to Date
header: false,
skipEmptyLines: true,
comments: '#',
newline: '\n'
};
// PapaParse config
let ohsomeGroupByBoundaryCSV;
ohsomeGroupByBoundaryCSV = {
delimiter: ';',
dynamicTyping: (isContributionView!) ? (col: any) => (!(col == 0 || col == 1)) : (col: any) => (col != 0), //first (or first two) column is timestamp and should remain string not auto converted to Date
header: false,
skipEmptyLines: true,
comments: '#',
newline: '\n',
//harmonize "NaN" strings to propoer null types
transform: ( val: any ) => { return ( typeof val === 'string' && (val === 'NaN' || val === 'Infinity' || val.toLowerCase() ==='null') ) ? null : val; }
};
const shouldCreateGeometry = !!sourceFeatureCollection;
......@@ -224,9 +272,20 @@ export class GeoJsonFeatureType extends FeatureType {
to_timestamp: tv.toTimestamp,
value: tv.value
})
}
};
const getFeatureFromRatioResult = (tv: any) => {
return turfHelpers.feature(geom,
{
id: id,
timestamp: tv.timestamp,
value: tv.value,
value2: tv.value2,
ratio: tv.ratio
})
};
const getFeatureFromResult = (isContributionView)? getFeatureFromContributionViewResult : getFeatureFromSnapshotResult;
const getFeatureFromResult = (isContributionView)? getFeatureFromContributionViewResult : (isRatio)? getFeatureFromRatioResult : getFeatureFromSnapshotResult;
const idFeatures = item.result.map(getFeatureFromResult);
......@@ -237,15 +296,23 @@ export class GeoJsonFeatureType extends FeatureType {
if (isCSV) {
//csv
isContributionView = isContributionView!;
//for proper id parsing remove text-part from column names, e.g. 23_value;23_value2;23_ratio;24_value;....
if(isRatio!){
ohsomeResults = ohsomeResults.replace(/(\.*)_value(2)?/g, "$1");
}
let ohsomeCsv = Papa.parse(ohsomeResults, ohsomeGroupByBoundaryCSV).data;
const nrows = ohsomeCsv.length;
const ncols = (!!ohsomeCsv[0]) ? ohsomeCsv[0].length : 0;
const firstValueColumnIndex = (isContributionView) ? 2 : 1; // for snapshotView start reading values at column index 1, for contributionView start at column index 2
const ncols = (!!ohsomeCsv[0]) ? (isRatio!)? ((ohsomeCsv[0].length - firstValueColumnIndex)/3)+firstValueColumnIndex : ohsomeCsv[0].length : 0;
for (let col = firstValueColumnIndex; col < ncols; col++) {
for (let row = 1; row < nrows; row++) {
let properties;
let properties: any;
if (isContributionView) {
properties = {
id: undefined,
......@@ -255,8 +322,22 @@ export class GeoJsonFeatureType extends FeatureType {
};
properties.from_timestamp = ohsomeCsv[row][0];
properties.to_timestamp = ohsomeCsv[row][1];
properties.id = ohsomeCsv[0][col];
properties.id = castId(ohsomeCsv[0][col]);
properties.value = ohsomeCsv[row][col];
} else if(isRatio!){
properties = {
id: undefined,
timestamp: undefined,
value: undefined,
value2: undefined,
ratio: undefined
};
properties.timestamp = ohsomeCsv[row][0];
let valueIndex = ( ( col-firstValueColumnIndex ) *3 ) + firstValueColumnIndex;
properties.id = castId(ohsomeCsv[0][valueIndex]); //value column
properties.value = ohsomeCsv[row][valueIndex]; //value column
properties.value2 = ohsomeCsv[row][valueIndex+1]; //value2 column
properties.ratio = ohsomeCsv[row][valueIndex+2]; //ratio column
} else {
properties = {
id: undefined,
......@@ -264,7 +345,7 @@ export class GeoJsonFeatureType extends FeatureType {
value: undefined
};
properties.timestamp = ohsomeCsv[row][0];
properties.id = ohsomeCsv[0][col];
properties.id = castId(ohsomeCsv[0][col]);
properties.value = ohsomeCsv[row][col];
}
......@@ -283,7 +364,9 @@ export class GeoJsonFeatureType extends FeatureType {
if (!isCSV) {
//json
if (!isRatio!){
targetFeatures = ohsomeResults.groupByResult.map((item: any) => {
const id = item.groupByObject;
......@@ -300,35 +383,93 @@ export class GeoJsonFeatureType extends FeatureType {
});
return turfHelpers.feature(geom, properties);
});
} else {
//ratio
targetFeatures = ohsomeResults.groupByResult.flatMap((item:any) => {
const id = item.groupByObject;
const geom = (shouldCreateGeometry) ? idGeomMap.get(id) : null;
let propertiesValue: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value'};
let propertiesValue2: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value2'};
let propertiesRatio: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'ratio'};
item.result.forEach((tvv2r: any) => {
propertiesValue[tvv2r.timestamp] = tvv2r.value;
propertiesValue2[tvv2r.timestamp] = tvv2r.value2;
propertiesRatio[tvv2r.timestamp] = tvv2r.ratio;
})
return [
turfHelpers.feature(geom, propertiesValue),
turfHelpers.feature(geom, propertiesValue2),
turfHelpers.feature(geom, propertiesRatio)
];
} );
}
}
if (isCSV) {
//csv
//for proper id parsing remove text-part from column names, e.g. 23_value;23_value2;23_ratio;24_value;....
if(isRatio!){
ohsomeResults = ohsomeResults.replace(/(\.*)_value(2)?/g, "$1");
}
const ohsomeCsv = Papa.parse(ohsomeResults, ohsomeGroupByBoundaryCSV).data;
const nrows = ohsomeCsv.length;
const ncols = (!!ohsomeCsv[0]) ? ohsomeCsv[0].length : 0;
const firstValueColumnIndex = (isContributionView) ? 2 : 1; // for snapshotView start reading values at column indeex 1, for contributionView start at column index 2
// const ncols = (!!ohsomeCsv[0]) ? ohsomeCsv[0].length : 0;
const firstValueColumnIndex = (isContributionView!) ? 2 : 1; // for snapshotView start reading values at column indeex 1, for contributionView start at column index 2
const ncols = (!!ohsomeCsv[0]) ? (isRatio!)? ((ohsomeCsv[0].length - firstValueColumnIndex)/3)+firstValueColumnIndex : ohsomeCsv[0].length : 0;
for (let col = firstValueColumnIndex; col < ncols; col++) {
let properties: { id: number | string | undefined; [timestamp: string]: any } = {
id: undefined
};
properties.id = ohsomeCsv[0][col];
for (let row = 1; row < nrows; row++) {
if (isContributionView) {
properties[`${ohsomeCsv[row][0]}/${ohsomeCsv[row][1]}`] = ohsomeCsv[row][col]; // fromTimestamp/toTimestamp = value
} else {
properties[ohsomeCsv[row][0]] = ohsomeCsv[row][col]; // timestamp = value
if(!isRatio!){
const id = castId(ohsomeCsv[0][col]);
const geom = (shouldCreateGeometry) ? idGeomMap!.get(id) : null;
let properties: { id: number | string | undefined; [timestamp: string]: any } = {
id: id
};
for (let row = 1; row < nrows; row++) {
if (isContributionView!) {
properties[`${ohsomeCsv[row][0]}/${ohsomeCsv[row][1]}`] = ohsomeCsv[row][col]; // fromTimestamp/toTimestamp = value
} else {
properties[ohsomeCsv[row][0]] = ohsomeCsv[row][col]; // timestamp = value
}
}
targetFeatures.push(turfHelpers.feature(geom, properties));
} else {
//ratio
let valueIndex = ( ( col-firstValueColumnIndex ) *3 ) + firstValueColumnIndex;
const id = castId(ohsomeCsv[0][valueIndex]);
const geom = (shouldCreateGeometry) ? idGeomMap!.get(id) : null;
let propertiesValue: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value'};
let propertiesValue2: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value2'};
let propertiesRatio: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'ratio'};
for (let row = 1; row < nrows; row++) {
propertiesValue[ohsomeCsv[row][0]] = ohsomeCsv[row][valueIndex]; //timestamp = value
propertiesValue2[ohsomeCsv[row][0]] = ohsomeCsv[row][valueIndex+1]; //timestamp = value2
propertiesRatio[ohsomeCsv[row][0]] = ohsomeCsv[row][valueIndex+2]; //timestamp = ratio
}
targetFeatures.push(turfHelpers.feature(geom, propertiesValue));
targetFeatures.push(turfHelpers.feature(geom, propertiesValue2));
targetFeatures.push(turfHelpers.feature(geom, propertiesRatio));
}
// @ts-ignore
const geom = (shouldCreateGeometry) ? idGeomMap.get(properties.id) : null;
targetFeatures.push(turfHelpers.feature(geom, properties));
}
}
......
import {
Ohsome2XConfig,
OhsomeQueryConfig,
OhsomeQueryConfigFormat,
OhsomeQueryConfigFormat, OhsomeQueryRatioConfig,
TargetPostgisFeatureTypeConfig
} from './config_types_interfaces';
import normalizeUrl from 'normalize-url';
......@@ -31,6 +31,9 @@ class Ohsome2X extends EventEmitter {
private log_start: Date;
private log_end: Date;
private isContributionView: boolean | undefined;
private isGroupByResponse: boolean | undefined;
private isRatio: boolean | undefined;
private sourceIdType: number | string | undefined;
private totalFeatureCount: number = 0;
private currentFeatureCount: number = 0;
......@@ -80,6 +83,7 @@ class Ohsome2X extends EventEmitter {
this.targetFeatureType = await FeatureTypeFactory.create(this.config.target);
this.totalFeatureCount = await this.sourceFeatureType.getFeatureCount();
this.sourceIdType = await this.sourceFeatureType.getIdJsType();
process.on('SIGINT', async ()=>{
console.log('\nSIGINT signal received. Closing existing connections.');
......@@ -129,7 +133,7 @@ class Ohsome2X extends EventEmitter {
this.targetFeatureType = <PgFeatureType>this.targetFeatureType;
//create iteratively
//check curser type: number or string?
const cursorType = await this.sourceFeatureType.getIdJsTypeFromPg();
const cursorType = this.sourceIdType;
console.log("cursorType", cursorType);
let cursor;
......@@ -155,7 +159,7 @@ class Ohsome2X extends EventEmitter {
this.emit('progress', {type:'progress', processed: this.currentFeatureCount, total: this.totalFeatureCount, cursor: cursor, fetchSize: fetchSize, timestamp: new Date().toISOString()});
const sourceFeatureCollection: any = await this.sourceFeatureType.getFeaturesByCursorAndLimit(cursor, fetchSize);
let targetFeatureCollection;
let targetFeatureCollection: any;
featureCount = sourceFeatureCollection.features.length;
......@@ -242,39 +246,56 @@ class Ohsome2X extends EventEmitter {
}
ohsomeResults = ohsomeResults!;
this.isContributionView = this.checkIsContributionView(ohsomeResults.data);
//temporary until ohsome-api changes
this.harmonizeResponseStructure(ohsomeResults);
let responseFormat = this.checkResponseFormat (ohsomeResults.data);
this.isContributionView = responseFormat.isContributionView;
this.isRatio = responseFormat.isRatio;
this.harmonizeRatio_NaN_and_Infinity(ohsomeResults);
console.log('Start conversion ohsome-result to GeoJSON');
console.time('convert');
if (shouldCreateGeometry) {
if (typeof ohsomeResults.data == 'string') {
console.log('-----------------------------------------');
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log(ohsomeResults.data.substring(0, 500) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
} else {
if (typeof ohsomeResults.data == 'string') {
console.log('-----------------------------------------');
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log(ohsomeResults.data.substring(0, 500) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps);
}
console.timeEnd('convert');
//remove features where value = 0 or ratio = 0
if (!shouldWriteHorizontalTimestamps && !this.storeZeroValues) {
//remove features where value = 0
console.log('Remove Zeros');
console.time('removeZero');
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
console.timeEnd('removeZero');
if(!this.isRatio){
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
} else {
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValues(targetFeatureCollection, {
'value':0,
'value2': 0,
'ratio': null
});
}
}
console.time('computeValuePerArea');
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea) {
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea && !this.isRatio) {
targetFeatureCollection.features.forEach(
// @ts-ignore
......@@ -330,7 +351,16 @@ class Ohsome2X extends EventEmitter {
const ohsomeResults = await this.getOhsomeResults(this.config.ohsomeQuery);
console.timeEnd('query');
this.isContributionView = this.checkIsContributionView(ohsomeResults.data);
// temporary solution until ohsome-api changes
this.harmonizeResponseStructure(ohsomeResults);
let responseFormat = this.checkResponseFormat (ohsomeResults.data);
this.isContributionView = responseFormat.isContributionView;
this.isRatio = responseFormat.isRatio;
if(responseFormat.isRatio){
this.harmonizeRatio_NaN_and_Infinity(ohsomeResults)
}
console.log('Start conversion ohsomeJSON or csv to GeoJSON');
console.time('convert');
......@@ -340,7 +370,7 @@ class Ohsome2X extends EventEmitter {
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
} else {
......@@ -349,26 +379,33 @@ class Ohsome2X extends EventEmitter {
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps);
}
console.timeEnd('convert');
//remove features where value = 0 or ratio = NaN or null
if (!shouldWriteHorizontalTimestamps && !this.storeZeroValues) {
//remove features where value = 0
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
console.log('Remove Zeros...');
if(!this.isRatio){
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
} else {
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValues(targetFeatureCollection, {'value':0, value2:0, 'ratio': null});
}
}
console.time('computeValuePerArea');
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea) {
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea && !this.isRatio) {
console.time('computeValuePerArea');
targetFeatureCollection.features.forEach(
// @ts-ignore
(feature) => feature.properties["value_per_area"] = feature.properties.value / idAreaMap.get(feature.properties.id)
);
console.timeEnd('computeValuePerArea');
}
console.timeEnd('computeValuePerArea');
// console.log(JSON.stringify(targetFeatureCollection, undefined, 2));
await this.targetFeatureType.writeFeatures(targetFeatureCollection);
......@@ -410,9 +447,15 @@ class Ohsome2X extends EventEmitter {
await this.targetFeatureType.clusterTable('timestamp');
}
await this.targetFeatureType.createIndex('value');
if (this.computeValuePerArea) {
if(this.isRatio){
await this.targetFeatureType.createIndex('value2');
await this.targetFeatureType.createIndex('ratio');
}
if (this.computeValuePerArea && !this.isRatio) {
await this.targetFeatureType.createIndex('value_per_area');
}
}
......@@ -452,10 +495,13 @@ class Ohsome2X extends EventEmitter {
///////////// methods
async getOhsomeResults(ohsomeQuery: OhsomeQueryConfig): Promise<AxiosResponse> {
async getOhsomeResults(ohsomeQuery: OhsomeQueryConfig | OhsomeQueryRatioConfig): Promise<AxiosResponse> {
const isRatio = ohsomeQuery.queryType.includes("/ratio");
// set empty strings to null
const filter = (ohsomeQuery.filter != null && ohsomeQuery.filter.trim() != '')? ohsomeQuery.filter.trim() : undefined;
// for ratio requests
const filter2 = (isRatio && ohsomeQuery.filter2 != null && ohsomeQuery.filter2.trim() != '')? ohsomeQuery.filter2.trim() : undefined;
const format: OhsomeQueryConfigFormat = (ohsomeQuery.format != null && ohsomeQuery.format.trim() != '')? ohsomeQuery.format.trim() as 'csv'|'json' : undefined;
try {
......@@ -469,6 +515,7 @@ class Ohsome2X extends EventEmitter {
let dataObject: {} = {
bpolys: bpolyString,
filter: filter,
filter2: filter2,
time: ohsomeQuery.time,
showMetadata: true,
format: format
......@@ -507,11 +554,12 @@ class Ohsome2X extends EventEmitter {
}