From d321950b93f57bdc17ad4b4cebac50f4b8fbbb19 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 12 Jan 2021 13:49:59 -0500 Subject: [PATCH] [Maps] Support geometry-collection (#87867) --- .../elasticsearch_geo_utils.js | 28 ++++++-- .../elasticsearch_geo_utils.test.js | 65 +++++++++++++++++++ .../maps/common/get_centroid_features.ts | 2 + 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js index 813d01ff9086..458e4e0efdd4 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js @@ -172,8 +172,15 @@ export function convertESShapeToGeojsonGeometry(value) { geoJson.type = GEO_JSON_TYPE.MULTI_POLYGON; break; case 'geometrycollection': - geoJson.type = GEO_JSON_TYPE.GEOMETRY_COLLECTION; - break; + case GEO_JSON_TYPE.GEOMETRY_COLLECTION: + // PEBKAC - geometry-collections need to be unrolled to their individual geometries first. + const invalidGeometrycollectionError = i18n.translate( + 'xpack.maps.es_geo_utils.convert.invalidGeometryCollectionErrorMessage', + { + defaultMessage: `Should not pass GeometryCollection to convertESShapeToGeojsonGeometry`, + } + ); + throw new Error(invalidGeometrycollectionError); case 'envelope': // format defined here https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html#_envelope const polygon = formatEnvelopeAsPolygon({ @@ -227,14 +234,21 @@ export function geoShapeToGeometry(value, accumulator) { return; } - let geoJson; if (typeof value === 'string') { - geoJson = convertWKTStringToGeojson(value); + const geoJson = convertWKTStringToGeojson(value); + accumulator.push(geoJson); + } else if ( + // Needs to deal with possible inconsistencies in capitalization + value.type === GEO_JSON_TYPE.GEOMETRY_COLLECTION || + value.type === 'geometrycollection' + ) { + for (let i = 0; i < value.geometries.length; i++) { + geoShapeToGeometry(value.geometries[i], accumulator); + } } else { - geoJson = convertESShapeToGeojsonGeometry(value); + const geoJson = convertESShapeToGeojsonGeometry(value); + accumulator.push(geoJson); } - - accumulator.push(geoJson); } export function makeESBbox({ maxLat, maxLon, minLat, minLon }) { diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js index ccab57dd1833..cc0dce2057cb 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js @@ -147,6 +147,71 @@ describe('hitsToGeoJson', () => { }); }); + it('Should create feature per item when geometry value is a geometry-collection', () => { + const hits = [ + { + _id: 'doc1', + _index: 'index1', + _source: { + [geoFieldName]: { + type: 'GeometryCollection', + geometries: [ + { + type: 'geometrycollection', //explicitly test coercion to proper GeoJson type value + geometries: [ + { + type: 'point', //explicitly test coercion to proper GeoJson type value + coordinates: [0, 0], + }, + ], + }, + { + type: 'LineString', + coordinates: [ + [0, 0], + [1, 1], + ], + }, + ], + }, + myField: 8, + }, + }, + ]; + const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_shape', []); + expect(geojson.type).toBe('FeatureCollection'); + expect(geojson.features.length).toBe(2); + expect(geojson.features[0]).toEqual({ + geometry: { + coordinates: [0, 0], + type: 'Point', + }, + id: 'index1:doc1:0', + properties: { + _id: 'doc1', + _index: 'index1', + myField: 8, + }, + type: 'Feature', + }); + expect(geojson.features[1]).toEqual({ + geometry: { + coordinates: [ + [0, 0], + [1, 1], + ], + type: 'LineString', + }, + id: 'index1:doc1:1', + properties: { + _id: 'doc1', + _index: 'index1', + myField: 8, + }, + type: 'Feature', + }); + }); + it('Should convert epoch_millis value from string to integer', () => { const hits = [ { diff --git a/x-pack/plugins/maps/common/get_centroid_features.ts b/x-pack/plugins/maps/common/get_centroid_features.ts index 9b49b1f7653d..81457266b8e9 100644 --- a/x-pack/plugins/maps/common/get_centroid_features.ts +++ b/x-pack/plugins/maps/common/get_centroid_features.ts @@ -65,6 +65,8 @@ export function getCentroidFeatures(featureCollection: FeatureCollection): Featu } } centroidGeometry = turfCenterOfMass(polygon(largestPolygon)).geometry; + } else if (feature.geometry.type === GEO_JSON_TYPE.GEOMETRY_COLLECTION) { + throw new Error('Should not have features with geometrycollection'); } if (centroidGeometry) {