From 327bc272e5ef863a74488a2e73a37e8da0d07ac3 Mon Sep 17 00:00:00 2001 From: Neelesh Thakur <NThakur4@slb.com> Date: Sun, 14 Mar 2021 14:28:39 -0500 Subject: [PATCH] add support for featurecollection --- .../osdu/indexer/model/geojson/Feature.java | 26 + .../model/geojson/FeatureCollection.java | 31 + .../indexer/model/geojson/GeoJsonObject.java | 22 + .../osdu/indexer/model/geojson/Geometry.java | 31 + .../model/geojson/GeometryCollection.java | 23 + .../indexer/model/geojson/LineString.java | 11 + .../model/geojson/MultiLineString.java | 13 + .../indexer/model/geojson/MultiPoint.java | 11 + .../indexer/model/geojson/MultiPolygon.java | 18 + .../osdu/indexer/model/geojson/Point.java | 21 + .../osdu/indexer/model/geojson/Polygon.java | 59 ++ .../osdu/indexer/model/geojson/Position.java | 56 + .../jackson/FeatureCollectionSerializer.java | 67 ++ .../geojson/jackson/PositionDeserializer.java | 53 + .../geojson/jackson/PositionSerializer.java | 22 + .../service/AttributeParsingServiceImpl.java | 7 +- .../indexer/util/parser/GeoShapeParser.java | 53 +- .../AttributeParsingServiceImplTest.java | 2 +- .../util/parser/GeoShapeParserTest.java | 62 +- .../resources/testData/index_records_3.json | 977 ++++++++++-------- 20 files changed, 1039 insertions(+), 526 deletions(-) create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java new file mode 100644 index 000000000..7c429e716 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java @@ -0,0 +1,26 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class Feature extends GeoJsonObject { + + @JsonInclude() + private Map<String, Object> properties = new HashMap<String, Object>(); + @JsonInclude() + private GeoJsonObject geometry; + private String id; + + public void setProperty(String key, Object value) { + properties.put(key, value); + } + + @SuppressWarnings("unchecked") + public <T> T getProperty(String key) { + return (T) properties.get(key); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java new file mode 100644 index 000000000..c8c84a76a --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java @@ -0,0 +1,31 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Data; +import org.opengroup.osdu.indexer.model.geojson.jackson.FeatureCollectionSerializer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +@Data +@JsonSerialize(using = FeatureCollectionSerializer.class) +public class FeatureCollection extends GeoJsonObject implements Iterable<Feature> { + + private List<Feature> features = new ArrayList<Feature>(); + + public FeatureCollection add(Feature feature) { + features.add(feature); + return this; + } + + public void addAll(Collection<Feature> features) { + this.features.addAll(features); + } + + @Override + public Iterator<Feature> iterator() { + return features.iterator(); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java new file mode 100644 index 000000000..9ba2ee3f0 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java @@ -0,0 +1,22 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; +import lombok.Data; + +@Data +@JsonTypeInfo(property = "type", use = Id.NAME) +@JsonSubTypes({ @Type(Feature.class), @Type(Polygon.class), @Type(MultiPolygon.class), @Type(FeatureCollection.class), + @Type(Point.class), @Type(MultiPoint.class), @Type(MultiLineString.class), @Type(LineString.class), + @Type(GeometryCollection.class) }) +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class GeoJsonObject implements Serializable { +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java new file mode 100644 index 000000000..f061161d4 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java @@ -0,0 +1,31 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import java.util.ArrayList; +import java.util.List; + +public abstract class Geometry<T> extends GeoJsonObject { + + protected List<T> coordinates = new ArrayList<T>(); + + public Geometry() { + } + + public Geometry(T... elements) { + for (T coordinate : elements) { + coordinates.add(coordinate); + } + } + + public Geometry<T> add(T elements) { + coordinates.add(elements); + return this; + } + + public List<T> getCoordinates() { + return coordinates; + } + + public void setCoordinates(List<T> coordinates) { + this.coordinates = coordinates; + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java new file mode 100644 index 000000000..a4159116a --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java @@ -0,0 +1,23 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Data +public class GeometryCollection extends GeoJsonObject implements Iterable<GeoJsonObject> { + + private List<GeoJsonObject> geometries = new ArrayList<GeoJsonObject>(); + + @Override + public Iterator<GeoJsonObject> iterator() { + return geometries.iterator(); + } + + public GeometryCollection add(GeoJsonObject geometry) { + geometries.add(geometry); + return this; + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java new file mode 100644 index 000000000..a2692ec75 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java @@ -0,0 +1,11 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public class LineString extends MultiPoint { + + public LineString(Position... points) { + super(points); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java new file mode 100644 index 000000000..701dabd59 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java @@ -0,0 +1,13 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +public class MultiLineString extends Geometry<List<Position>> { + + public MultiLineString(List<Position> line) { + add(line); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java new file mode 100644 index 000000000..4c44e0844 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java @@ -0,0 +1,11 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public class MultiPoint extends Geometry<Position> { + + public MultiPoint(Position... points) { + super(points); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java new file mode 100644 index 000000000..f223b2094 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java @@ -0,0 +1,18 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +public class MultiPolygon extends Geometry<List<List<Position>>> { + + public MultiPolygon(Polygon polygon) { + add(polygon); + } + + public MultiPolygon add(Polygon polygon) { + coordinates.add(polygon.getCoordinates()); + return this; + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java new file mode 100644 index 000000000..429b08de2 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java @@ -0,0 +1,21 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Point extends GeoJsonObject { + + private Position coordinates; + + public Point(double longitude, double latitude) { + coordinates = new Position(longitude, latitude); + } + + public Point(double longitude, double latitude, double altitude) { + coordinates = new Position(longitude, latitude, altitude); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java new file mode 100644 index 000000000..f1f9e0011 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java @@ -0,0 +1,59 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.NoArgsConstructor; + +import java.util.Arrays; +import java.util.List; + +@NoArgsConstructor +public class Polygon extends Geometry<List<Position>> { + + public Polygon(List<Position> polygon) { + add(polygon); + } + + public Polygon(Position... polygon) { + add(Arrays.asList(polygon)); + } + + public void setExteriorRing(List<Position> points) { + if (coordinates.isEmpty()) { + coordinates.add(0, points); + } else { + coordinates.set(0, points); + } + } + + @JsonIgnore + public List<Position> getExteriorRing() { + assertExteriorRing(); + return coordinates.get(0); + } + + @JsonIgnore + public List<List<Position>> getInteriorRings() { + assertExteriorRing(); + return coordinates.subList(1, coordinates.size()); + } + + public List<Position> getInteriorRing(int index) { + assertExteriorRing(); + return coordinates.get(1 + index); + } + + public void addInteriorRing(List<Position> points) { + assertExteriorRing(); + coordinates.add(points); + } + + public void addInteriorRing(Position... points) { + assertExteriorRing(); + coordinates.add(Arrays.asList(points)); + } + + private void assertExteriorRing() { + if (coordinates.isEmpty()) + throw new RuntimeException("No exterior ring defined"); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java new file mode 100644 index 000000000..1c9a58409 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java @@ -0,0 +1,56 @@ +package org.opengroup.osdu.indexer.model.geojson; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.opengroup.osdu.indexer.model.geojson.jackson.PositionDeserializer; +import org.opengroup.osdu.indexer.model.geojson.jackson.PositionSerializer; + +import java.io.Serializable; + +@Getter +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +@AllArgsConstructor +@JsonDeserialize(using = PositionDeserializer.class) +@JsonSerialize(using = PositionSerializer.class) +public class Position implements Serializable { + + private double longitude; + private double latitude; + @JsonIgnore + private double altitude = Double.NaN; + + public Position(double longitude, double latitude) { + this.setLongitude(longitude); + this.setLatitude(latitude); + } + + public void setLongitude(double longitude) { + if (Double.isNaN(longitude)) + throw new IllegalArgumentException("latitude must be number"); + if (longitude > 180 || longitude < -180) + throw new IllegalArgumentException("'longitude' value is out of the range [-180, 180]"); + this.longitude = longitude; + } + + public void setLatitude(double latitude) { + if (Double.isNaN(latitude)) + throw new IllegalArgumentException("latitude must be number"); + if (latitude > 90 || latitude < -90) + throw new IllegalArgumentException("latitude value is out of the range [-90, 90]"); + this.latitude = latitude; + } + + public void setAltitude(double altitude) { + this.altitude = altitude; + } + + public boolean hasAltitude() { + return !Double.isNaN(altitude); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java new file mode 100644 index 000000000..248202090 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java @@ -0,0 +1,67 @@ +package org.opengroup.osdu.indexer.model.geojson.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import lombok.Data; +import org.opengroup.osdu.indexer.model.geojson.*; + +import java.io.IOException; + +@Data +public class FeatureCollectionSerializer extends JsonSerializer<FeatureCollection> { + + @Override + public void serialize(FeatureCollection value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField("type", "geometrycollection"); + + jsonGenerator.writeArrayFieldStart("geometries"); + for (Feature feature : value.getFeatures()) { + jsonGenerator.writeStartObject(); + if (feature.getGeometry() instanceof GeometryCollection) { + GeometryCollection geometryCollection = (GeometryCollection) feature.getGeometry(); + for (GeoJsonObject shape : geometryCollection.getGeometries()) { + serializeGeoShape(shape, jsonGenerator); + } + } else { + serializeGeoShape(feature.getGeometry(), jsonGenerator); + } + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + + jsonGenerator.writeEndObject(); + } + + @Override + public void serializeWithType(FeatureCollection value, JsonGenerator jsonGenerator, SerializerProvider provider, TypeSerializer typeSerializer) + throws IOException, JsonProcessingException { + + serialize(value, jsonGenerator, provider); + } + + private void serializeGeoShape(GeoJsonObject geoJsonObject, JsonGenerator jsonGenerator) throws IOException { + if (geoJsonObject instanceof Point) { + jsonGenerator.writeStringField("type", "point"); + jsonGenerator.writeObjectField("coordinates", ((Point) geoJsonObject).getCoordinates()); + } else if (geoJsonObject instanceof LineString) { + jsonGenerator.writeStringField("type", "linestring"); + jsonGenerator.writeObjectField("coordinates", ((LineString) geoJsonObject).getCoordinates()); + } else if (geoJsonObject instanceof Polygon) { + jsonGenerator.writeStringField("type", "polygon"); + jsonGenerator.writeObjectField("coordinates", ((Polygon) geoJsonObject).getCoordinates()); + } else if (geoJsonObject instanceof MultiPoint) { + jsonGenerator.writeStringField("type", "multipoint"); + jsonGenerator.writeObjectField("coordinates", ((MultiPoint) geoJsonObject).getCoordinates()); + } else if (geoJsonObject instanceof MultiLineString) { + jsonGenerator.writeStringField("type", "multilinestring"); + jsonGenerator.writeObjectField("coordinates", ((MultiLineString) geoJsonObject).getCoordinates()); + } else if (geoJsonObject instanceof MultiPolygon) { + jsonGenerator.writeStringField("type", "multipolygon"); + jsonGenerator.writeObjectField("coordinates", ((MultiPolygon) geoJsonObject).getCoordinates()); + } + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java new file mode 100644 index 000000000..d837e09e2 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java @@ -0,0 +1,53 @@ +package org.opengroup.osdu.indexer.model.geojson.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import org.opengroup.osdu.indexer.model.geojson.Position; + +import java.io.IOException; + +public class PositionDeserializer extends JsonDeserializer<Position> { + + @Override + public Position deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException { + if (jsonParser.isExpectedStartArrayToken()) { + return deserializeArray(jsonParser, context); + } + throw context.mappingException(Position.class); + } + + protected Position deserializeArray(JsonParser jsonParser, DeserializationContext context) throws IOException { + Position node = new Position(); + node.setLongitude(extractDouble(jsonParser, context, false)); + node.setLatitude(extractDouble(jsonParser, context, false)); + node.setAltitude(extractDouble(jsonParser, context, true)); + return node; + } + + private double extractDouble(JsonParser jsonParser, DeserializationContext context, boolean optional) throws IOException { + JsonToken token = jsonParser.nextToken(); + if (token == null) { + if (optional) + return Double.NaN; + else + throw context.mappingException("Unexpected end-of-input when binding data into Position"); + } else { + switch (token) { + case END_ARRAY: + if (optional) + return Double.NaN; + else + throw context.mappingException("Unexpected end-of-input when binding data into Position"); + case VALUE_NUMBER_FLOAT: + return jsonParser.getDoubleValue(); + case VALUE_NUMBER_INT: + return jsonParser.getLongValue(); + default: + throw context.mappingException( + "Unexpected token (" + token.name() + ") when binding data into Position"); + } + } + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java new file mode 100644 index 000000000..909482d69 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java @@ -0,0 +1,22 @@ +package org.opengroup.osdu.indexer.model.geojson.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.opengroup.osdu.indexer.model.geojson.Position; + +import java.io.IOException; + +public class PositionSerializer extends JsonSerializer<Position> { + + @Override + public void serialize(Position value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException { + jsonGenerator.writeStartArray(); + jsonGenerator.writeNumber(value.getLongitude()); + jsonGenerator.writeNumber(value.getLatitude()); + if (value.hasAltitude()) { + jsonGenerator.writeNumber(value.getAltitude()); + } + jsonGenerator.writeEndArray(); + } +} diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java index fae0b4e6f..733408ab3 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java @@ -25,6 +25,7 @@ import org.opengroup.osdu.core.common.model.indexer.IndexSchema; import org.opengroup.osdu.core.common.model.indexer.IndexingStatus; import org.opengroup.osdu.core.common.model.indexer.JobStatus; import org.opengroup.osdu.core.common.Constants; +import org.opengroup.osdu.indexer.model.geojson.FeatureCollection; import org.opengroup.osdu.indexer.util.parser.BooleanParser; import org.opengroup.osdu.indexer.util.parser.DateTimeParser; import org.opengroup.osdu.indexer.util.parser.GeoShapeParser; @@ -185,7 +186,7 @@ public class AttributeParsingServiceImpl implements IAttributeParsingService { dataMap.put(DATA_GEOJSON_TAG, geometry); } } catch (JsonSyntaxException | IllegalArgumentException e) { - String parsingError = String.format("geopoint parsing error: %s attribute: %s | value: %s", e.getMessage(), attributeName, attributeVal); + String parsingError = String.format("geo-point parsing error: %s attribute: %s | value: %s", e.getMessage(), attributeName, attributeVal); jobStatus.addOrUpdateRecordStatus(recordId, IndexingStatus.WARN, HttpStatus.SC_BAD_REQUEST, parsingError, String.format("record-id: %s | %s", recordId, parsingError)); } } @@ -199,9 +200,9 @@ public class AttributeParsingServiceImpl implements IAttributeParsingService { if (geoJsonMap == null || geoJsonMap.isEmpty()) return; - this.geoShapeParser.parseGeoJson(geoJsonMap); + Map<String, Object> parsedShape = this.geoShapeParser.parseGeoJson(geoJsonMap); - dataMap.put(attributeName, geoJsonMap); + dataMap.put(attributeName, parsedShape); } catch (JsonSyntaxException | IllegalArgumentException e) { String parsingError = String.format("geo-json shape parsing error: %s attribute: %s", e.getMessage(), attributeName); jobStatus.addOrUpdateRecordStatus(recordId, IndexingStatus.WARN, HttpStatus.SC_BAD_REQUEST, parsingError, String.format("record-id: %s | %s", recordId, parsingError)); diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java index 9532e498b..8bd6ec834 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java @@ -14,55 +14,36 @@ package org.opengroup.osdu.indexer.util.parser; -import org.elasticsearch.ElasticsearchParseException; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.geo.builders.ShapeBuilder; -import org.elasticsearch.common.geo.parsers.ShapeParser; -import org.elasticsearch.common.xcontent.DeprecationHandler; -import org.elasticsearch.common.xcontent.NamedXContentRegistry; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.json.JsonXContent; -import org.locationtech.spatial4j.exception.InvalidShapeException; -import org.locationtech.spatial4j.shape.Shape; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; import org.opengroup.osdu.core.common.search.Preconditions; +import org.opengroup.osdu.indexer.model.geojson.FeatureCollection; import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.RequestScope; -import java.io.IOException; import java.util.Map; @Component @RequestScope public class GeoShapeParser { - public String parseGeoJson(Map<String, Object> geoShapeObject) { + private ObjectMapper mapper = new ObjectMapper(); - Preconditions.checkNotNull(geoShapeObject, "geoShapeObject cannot be null"); + public Map<String, Object> parseGeoJson(Map<String, Object> objectMap) { - try { - // use elasticsearch's ShapeParser to validate shape - ShapeBuilder shapeBuilder = getShapeBuilderFromObject(geoShapeObject); - Shape shape = shapeBuilder.buildS4J(); - if (shape == null) { - throw new IllegalArgumentException("unable to parse shape"); - } + Preconditions.checkNotNull(objectMap, "geoShapeObject cannot be null"); + if (objectMap.isEmpty()) throw new IllegalArgumentException("shape not included"); - return shapeBuilder.toString().replaceAll("\\r", "").replaceAll("\\n", ""); - } catch (ElasticsearchParseException | InvalidShapeException | IOException e) { - throw new IllegalArgumentException(e.getMessage(), e); + try { + FeatureCollection collection = mapper.readValue(mapper.writeValueAsString(objectMap), FeatureCollection.class); + return mapper.readValue(mapper.writeValueAsString(collection), new TypeReference<Map<String, Object>>() { + }); + } catch (InvalidTypeIdException e) { + throw new IllegalArgumentException("must be a valid FeatureCollection"); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("unable to parse FeatureCollection"); } } - - private ShapeBuilder getShapeBuilderFromObject(Map<String, Object> object) throws IOException { - XContentBuilder contentBuilder = JsonXContent.contentBuilder().value(object); - - XContentParser parser = JsonXContent.jsonXContent.createParser( - NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, - BytesReference.bytes(contentBuilder).streamInput() - ); - - parser.nextToken(); - return ShapeParser.parse(parser); - } } \ No newline at end of file diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java index 5db76eb05..67362f02c 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java @@ -321,7 +321,7 @@ public class AttributeParsingServiceImplTest { Map<String, Object> storageData = new HashMap<>(); storageData.put("location", parseJson(shapeJson)); - when(this.geoShapeParser.parseGeoJson(storageData)).thenReturn(""); + when(this.geoShapeParser.parseGeoJson(storageData)).thenReturn(new HashMap<>()); Map<String, Object> dataMap = new HashMap<>(); diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java index 8c1d36fe9..2e34f70c9 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java @@ -29,8 +29,7 @@ import java.util.Map; import java.util.function.Function; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) public class GeoShapeParserTest { @@ -45,124 +44,129 @@ public class GeoShapeParserTest { public void should_throwException_provided_emptyGeoJson() { String shapeJson = "{}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "shape type not included"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "shape not included"); } @Test public void should_throwException_parseInvalidPoint() { - String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-205.01621,39.57422]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-205.01621,39.57422]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "Bad X value -205.01621 is not in boundary Rect(minX=-180.0,maxX=180.0,minY=-90.0,maxY=90.0)"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection"); } @Test public void should_throwException_parseInvalidPoint_NaN() { - String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-205.01621,NaN]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-205.01621,NaN]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "geo coordinates must be numbers"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection"); } @Test public void should_throwException_parseInvalidPoint_missingLatitude() { - String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-205.01621,\"\"]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-105.01621]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "geo coordinates must be numbers"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection"); } @Test public void should_throwException_missingMandatoryAttribute() { - String shapeJson = "{\"mistype\":\"Point\",\"coordinates\":[-205.01621,39.57422]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"mistype\":\"Point\",\"coordinates\":[-205.01621,39.57422]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "shape type not included"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "must be a valid FeatureCollection"); } @Test public void should_throwException_parseInvalidShape() { - String shapeJson = "{\"type\":\"InvalidShape\",\"coordinates\":[-105.01621,39.57422]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"InvalidShape\",\"coordinates\":[-105.01621,39.57422]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "unknown geo_shape [InvalidShape]"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "must be a valid FeatureCollection"); } @Test public void should_parseValidPoint() { - String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-105.01621,39.57422]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-105.01621,39.57422]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_parseValidMultiPoint() { - String shapeJson = "{\"type\":\"MultiPoint\",\"coordinates\":[[-105.01621,39.57422],[-80.666513,35.053994]]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPoint\",\"coordinates\":[[-105.01621,39.57422],[-80.666513,35.053994]]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_parseValidLineString() { - String shapeJson = "{\"type\":\"LineString\",\"coordinates\":[[-101.744384,39.32155],[-101.552124,39.330048],[-101.403808,39.330048],[-101.332397,39.364032],[-101.041259,39.368279],[-100.975341,39.304549],[-100.914916,39.245016],[-100.843505,39.164141],[-100.805053,39.104488],[-100.491943,39.100226],[-100.437011,39.095962],[-100.338134,39.095962],[-100.195312,39.027718],[-100.008544,39.010647],[-99.865722,39.00211],[-99.684448,38.972221],[-99.51416,38.929502],[-99.382324,38.920955],[-99.321899,38.895308],[-99.113159,38.869651],[-99.0802,38.85682],[-98.822021,38.85682],[-98.448486,38.848264],[-98.206787,38.848264],[-98.020019,38.878204],[-97.635498,38.873928]]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-101.744384,39.32155],[-101.552124,39.330048],[-101.403808,39.330048],[-101.332397,39.364032],[-101.041259,39.368279],[-100.975341,39.304549],[-100.914916,39.245016],[-100.843505,39.164141],[-100.805053,39.104488],[-100.491943,39.100226],[-100.437011,39.095962],[-100.338134,39.095962],[-100.195312,39.027718],[-100.008544,39.010647],[-99.865722,39.00211],[-99.684448,38.972221],[-99.51416,38.929502],[-99.382324,38.920955],[-99.321899,38.895308],[-99.113159,38.869651],[-99.0802,38.85682],[-98.822021,38.85682],[-98.448486,38.848264],[-98.206787,38.848264],[-98.020019,38.878204],[-97.635498,38.873928]]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_parseValidMultiLineString() { - String shapeJson = "{\"type\":\"MultiLineString\",\"coordinates\":[[[-105.021443,39.578057],[-105.021507,39.577809],[-105.021572,39.577495],[-105.021572,39.577164],[-105.021572,39.577032],[-105.021529,39.576784]],[[-105.019898,39.574997],[-105.019598,39.574898],[-105.019061,39.574782]],[[-105.017173,39.574402],[-105.01698,39.574385],[-105.016636,39.574385],[-105.016508,39.574402],[-105.01595,39.57427]],[[-105.014276,39.573972],[-105.014126,39.574038],[-105.013825,39.57417],[-105.01331,39.574452]]]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiLineString\",\"coordinates\":[[[-105.021443,39.578057],[-105.021507,39.577809],[-105.021572,39.577495],[-105.021572,39.577164],[-105.021572,39.577032],[-105.021529,39.576784]],[[-105.019898,39.574997],[-105.019598,39.574898],[-105.019061,39.574782]],[[-105.017173,39.574402],[-105.01698,39.574385],[-105.016636,39.574385],[-105.016508,39.574402],[-105.01595,39.57427]],[[-105.014276,39.573972],[-105.014126,39.574038],[-105.013825,39.57417],[-105.01331,39.574452]]]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_parseValidPolygon() { - String shapeJson = "{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]]]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]]]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_throwException_parseInvalidPolygon_malformedLatitude() { - String shapeJson = "{\"type\":\"Polygon\",\"coordinates\":[[[100,\"afgg\"],[101,0],[101,1],[100,1],[100,0]]]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[100,\"afgg\"],[101,0],[101,1],[100,1],[100,0]]]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "geo coordinates must be numbers"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection"); } @Test public void should_parseValidMultiPolygon() { - String shapeJson = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[107,7],[108,7],[108,8],[107,8],[107,7]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]]]]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[107,7],[108,7],[108,8],[107,8],[107,7]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]]]]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_parseValidGeometryCollection() { - String shapeJson = "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[-80.660805,35.049392]},{\"type\":\"Polygon\",\"coordinates\":[[[-80.664582,35.044965],[-80.663874,35.04428],[-80.662586,35.04558],[-80.663444,35.046036],[-80.664582,35.044965]]]},{\"type\":\"LineString\",\"coordinates\":[[-80.662372,35.059509],[-80.662693,35.059263],[-80.662844,35.05893],[-80.66308,35.058332],[-80.663595,35.057753],[-80.663874,35.057401],[-80.66441,35.057033],[-80.664861,35.056787],[-80.665419,35.056506],[-80.665633,35.056312],[-80.666019,35.055891],[-80.666191,35.055452],[-80.666191,35.055171],[-80.666255,35.05489],[-80.666213,35.054222],[-80.666213,35.053924],[-80.665955,35.052905],[-80.665698,35.052044],[-80.665504,35.051482],[-80.665762,35.050481],[-80.66617,35.049725],[-80.666513,35.049286],[-80.666921,35.048531],[-80.667006,35.048215],[-80.667071,35.047775],[-80.667049,35.047389],[-80.666964,35.046985],[-80.666813,35.046353],[-80.666599,35.045966],[-80.666406,35.045615],[-80.665998,35.045193],[-80.665526,35.044877],[-80.664989,35.044543],[-80.664496,35.044174],[-80.663852,35.043876],[-80.663037,35.043717]]}]}"; + String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[-80.660805,35.049392]},{\"type\":\"Polygon\",\"coordinates\":[[[-80.664582,35.044965],[-80.663874,35.04428],[-80.662586,35.04558],[-80.663444,35.046036],[-80.664582,35.044965]]]},{\"type\":\"LineString\",\"coordinates\":[[-80.662372,35.059509],[-80.662693,35.059263],[-80.662844,35.05893],[-80.66308,35.058332],[-80.663595,35.057753],[-80.663874,35.057401],[-80.66441,35.057033],[-80.664861,35.056787],[-80.665419,35.056506],[-80.665633,35.056312],[-80.666019,35.055891],[-80.666191,35.055452],[-80.666191,35.055171],[-80.666255,35.05489],[-80.666213,35.054222],[-80.666213,35.053924],[-80.665955,35.052905],[-80.665698,35.052044],[-80.665504,35.051482],[-80.665762,35.050481],[-80.66617,35.049725],[-80.666513,35.049286],[-80.666921,35.048531],[-80.667006,35.048215],[-80.667071,35.047775],[-80.667049,35.047389],[-80.666964,35.046985],[-80.666813,35.046353],[-80.666599,35.045966],[-80.666406,35.045615],[-80.665998,35.045193],[-80.665526,35.044877],[-80.664989,35.044543],[-80.664496,35.044174],[-80.663852,35.043876],[-80.663037,35.043717]]}]}}]}"; this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test - public void should_throwException_parseUnsupportedType_featureCollection() { + public void should_parseValidFeatureCollection() { String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[1.9496737127045984,58.41415669686543],[1.8237672363511042,58.42946998193435],[1.8422735102001124,58.471472136376455],[1.9683241046247606,58.45614207250076],[1.9496737127045984,58.41415669686543]]]}}]}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "unknown geo_shape [FeatureCollection]"); + this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY); } @Test public void should_throwException_parseUnsupportedType_feature() { String shapeJson = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-80.724878,35.265454],[-80.722646,35.260338],[-80.720329,35.260618],[-80.718698,35.260267],[-80.715093,35.260548],[-80.71681,35.255361],[-80.710887,35.255361],[-80.703248,35.265033],[-80.704793,35.268397],[-80.70857,35.268257],[-80.712518,35.270359],[-80.715179,35.267696],[-80.721359,35.267276],[-80.724878,35.265454]]]},\"properties\":{\"name\":\"Plaza Road Park\"}}"; - this.validateInput(this.sut::parseGeoJson, shapeJson, "unknown geo_shape [Feature]"); + this.validateInput(this.sut::parseGeoJson, shapeJson, "must be a valid FeatureCollection"); } - private void validateInput(Function<Map<String, Object>, String> parser, String shapeJson, String errorMessage) { + private void validateInput(Function<Map<String, Object>, Map<String, Object>> parser, String shapeJson, String errorMessage) { try { Type type = new TypeToken<Map<String, Object>>() {}.getType(); Map<String, Object> shapeObj = new Gson().fromJson(shapeJson, type); - String parsedShape = parser.apply(shapeObj); + Map<String, Object> parsedShape = parser.apply(shapeObj); assertNotNull(parsedShape); + assertTrue(Strings.isNullOrEmpty(errorMessage)); } catch (IllegalArgumentException e) { - assertThat(String.format("Incorrect error message for geo-json parsing [ %s ]", shapeJson), - e.getMessage(), containsString(errorMessage)); + if (Strings.isNullOrEmpty(errorMessage)) { + fail(String.format("error parsing valid geo-json %s", shapeJson)); + } else { + assertThat(String.format("Incorrect error message for geo-json parsing [ %s ]", shapeJson), + e.getMessage(), containsString(errorMessage)); + } } } } diff --git a/testing/indexer-test-core/src/main/resources/testData/index_records_3.json b/testing/indexer-test-core/src/main/resources/testData/index_records_3.json index 983e7bdb9..58a7e0dee 100644 --- a/testing/indexer-test-core/src/main/resources/testData/index_records_3.json +++ b/testing/indexer-test-core/src/main/resources/testData/index_records_3.json @@ -4,10 +4,19 @@ "data": { "WellName": "Data Platform Services - 51", "GeoShape": { - "type": "Point", - "coordinates": [ - -105.01621, - 39.57422 + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + -105.01621, + 39.57422 + ] + } + } ] } } @@ -17,16 +26,25 @@ "data": { "WellName": "Data Platform Services - 52", "GeoShape": { - "type": "MultiPoint", - "coordinates": [ - [ - -105.01621, - 39.57422 - ], - [ - -80.666513, - 35.053994 - ] + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [ + -105.01621, + 39.57422 + ], + [ + -80.666513, + 35.053994 + ] + ] + } + } ] } } @@ -36,112 +54,121 @@ "data": { "WellName": "Data Platform Services - 53", "GeoShape": { - "type": "LineString", - "coordinates": [ - [ - -101.744384, - 39.32155 - ], - [ - -101.552124, - 39.330048 - ], - [ - -101.403808, - 39.330048 - ], - [ - -101.332397, - 39.364032 - ], - [ - -101.041259, - 39.368279 - ], - [ - -100.975341, - 39.304549 - ], - [ - -100.914916, - 39.245016 - ], - [ - -100.843505, - 39.164141 - ], - [ - -100.805053, - 39.104488 - ], - [ - -100.491943, - 39.100226 - ], - [ - -100.437011, - 39.095962 - ], - [ - -100.338134, - 39.095962 - ], - [ - -100.195312, - 39.027718 - ], - [ - -100.008544, - 39.010647 - ], - [ - -99.865722, - 39.00211 - ], - [ - -99.684448, - 38.972221 - ], - [ - -99.51416, - 38.929502 - ], - [ - -99.382324, - 38.920955 - ], - [ - -99.321899, - 38.895308 - ], - [ - -99.113159, - 38.869651 - ], - [ - -99.0802, - 38.85682 - ], - [ - -98.822021, - 38.85682 - ], - [ - -98.448486, - 38.848264 - ], - [ - -98.206787, - 38.848264 - ], - [ - -98.020019, - 38.878204 - ], - [ - -97.635498, - 38.873928 - ] + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -101.744384, + 39.32155 + ], + [ + -101.552124, + 39.330048 + ], + [ + -101.403808, + 39.330048 + ], + [ + -101.332397, + 39.364032 + ], + [ + -101.041259, + 39.368279 + ], + [ + -100.975341, + 39.304549 + ], + [ + -100.914916, + 39.245016 + ], + [ + -100.843505, + 39.164141 + ], + [ + -100.805053, + 39.104488 + ], + [ + -100.491943, + 39.100226 + ], + [ + -100.437011, + 39.095962 + ], + [ + -100.338134, + 39.095962 + ], + [ + -100.195312, + 39.027718 + ], + [ + -100.008544, + 39.010647 + ], + [ + -99.865722, + 39.00211 + ], + [ + -99.684448, + 38.972221 + ], + [ + -99.51416, + 38.929502 + ], + [ + -99.382324, + 38.920955 + ], + [ + -99.321899, + 38.895308 + ], + [ + -99.113159, + 38.869651 + ], + [ + -99.0802, + 38.85682 + ], + [ + -98.822021, + 38.85682 + ], + [ + -98.448486, + 38.848264 + ], + [ + -98.206787, + 38.848264 + ], + [ + -98.020019, + 38.878204 + ], + [ + -97.635498, + 38.873928 + ] + ] + } + } ] } } @@ -151,88 +178,97 @@ "data": { "WellName": "Data Platform Services - 54", "GeoShape": { - "type": "MultiLineString", - "coordinates": [ - [ - [ - -105.021443, - 39.578057 - ], - [ - -105.021507, - 39.577809 - ], - [ - -105.021572, - 39.577495 - ], - [ - -105.021572, - 39.577164 - ], - [ - -105.021572, - 39.577032 - ], - [ - -105.021529, - 39.576784 - ] - ], - [ - [ - -105.019898, - 39.574997 - ], - [ - -105.019598, - 39.574898 - ], - [ - -105.019061, - 39.574782 - ] - ], - [ - [ - -105.017173, - 39.574402 - ], - [ - -105.01698, - 39.574385 - ], - [ - -105.016636, - 39.574385 - ], - [ - -105.016508, - 39.574402 - ], - [ - -105.01595, - 39.57427 - ] - ], - [ - [ - -105.014276, - 39.573972 - ], - [ - -105.014126, - 39.574038 - ], - [ - -105.013825, - 39.57417 - ], - [ - -105.01331, - 39.574452 - ] - ] + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [ + -105.021443, + 39.578057 + ], + [ + -105.021507, + 39.577809 + ], + [ + -105.021572, + 39.577495 + ], + [ + -105.021572, + 39.577164 + ], + [ + -105.021572, + 39.577032 + ], + [ + -105.021529, + 39.576784 + ] + ], + [ + [ + -105.019898, + 39.574997 + ], + [ + -105.019598, + 39.574898 + ], + [ + -105.019061, + 39.574782 + ] + ], + [ + [ + -105.017173, + 39.574402 + ], + [ + -105.01698, + 39.574385 + ], + [ + -105.016636, + 39.574385 + ], + [ + -105.016508, + 39.574402 + ], + [ + -105.01595, + 39.57427 + ] + ], + [ + [ + -105.014276, + 39.573972 + ], + [ + -105.014126, + 39.574038 + ], + [ + -105.013825, + 39.57417 + ], + [ + -105.01331, + 39.574452 + ] + ] + ] + } + } ] } } @@ -242,30 +278,39 @@ "data": { "WellName": "Data Platform Services - 55", "GeoShape": { - "type": "Polygon", - "coordinates": [ - [ - [ - 100, - 0 - ], - [ - 101, - 0 - ], - [ - 101, - 1 - ], - [ - 100, - 1 - ], - [ - 100, - 0 - ] - ] + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 100, + 0 + ], + [ + 101, + 0 + ], + [ + 101, + 1 + ], + [ + 100, + 1 + ], + [ + 100, + 0 + ] + ] + ] + } + } ] } } @@ -275,56 +320,65 @@ "data": { "WellName": "Data Platform Services - 56", "GeoShape": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 107, - 7 - ], - [ - 108, - 7 - ], - [ - 108, - 8 - ], - [ - 107, - 8 - ], - [ - 107, - 7 - ] - ] - ], - [ - [ - [ - 100, - 0 - ], - [ - 101, - 0 - ], - [ - 101, - 1 - ], - [ - 100, - 1 - ], - [ - 100, - 0 + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 107, + 7 + ], + [ + 108, + 7 + ], + [ + 108, + 8 + ], + [ + 107, + 8 + ], + [ + 107, + 7 + ] + ] + ], + [ + [ + [ + 100, + 0 + ], + [ + 101, + 0 + ], + [ + 101, + 1 + ], + [ + 100, + 1 + ], + [ + 100, + 0 + ] + ] + ] ] - ] - ] + } + } ] } } @@ -334,190 +388,199 @@ "data": { "WellName": "Data Platform Services - 57", "GeoShape": { - "type": "GeometryCollection", - "geometries": [ - { - "type": "Point", - "coordinates": [ - -80.660805, - 35.049392 - ] - }, - { - "type": "Polygon", - "coordinates": [ - [ - [ - -80.664582, - 35.044965 - ], - [ - -80.663874, - 35.04428 - ], - [ - -80.662586, - 35.04558 - ], - [ - -80.663444, - 35.046036 - ], - [ - -80.664582, - 35.044965 - ] - ] - ] - }, + "type": "FeatureCollection", + "features": [ { - "type": "LineString", - "coordinates": [ - [ - -80.662372, - 35.059509 - ], - [ - -80.662693, - 35.059263 - ], - [ - -80.662844, - 35.05893 - ], - [ - -80.66308, - 35.058332 - ], - [ - -80.663595, - 35.057753 - ], - [ - -80.663874, - 35.057401 - ], - [ - -80.66441, - 35.057033 - ], - [ - -80.664861, - 35.056787 - ], - [ - -80.665419, - 35.056506 - ], - [ - -80.665633, - 35.056312 - ], - [ - -80.666019, - 35.055891 - ], - [ - -80.666191, - 35.055452 - ], - [ - -80.666191, - 35.055171 - ], - [ - -80.666255, - 35.05489 - ], - [ - -80.666213, - 35.054222 - ], - [ - -80.666213, - 35.053924 - ], - [ - -80.665955, - 35.052905 - ], - [ - -80.665698, - 35.052044 - ], - [ - -80.665504, - 35.051482 - ], - [ - -80.665762, - 35.050481 - ], - [ - -80.66617, - 35.049725 - ], - [ - -80.666513, - 35.049286 - ], - [ - -80.666921, - 35.048531 - ], - [ - -80.667006, - 35.048215 - ], - [ - -80.667071, - 35.047775 - ], - [ - -80.667049, - 35.047389 - ], - [ - -80.666964, - 35.046985 - ], - [ - -80.666813, - 35.046353 - ], - [ - -80.666599, - 35.045966 - ], - [ - -80.666406, - 35.045615 - ], - [ - -80.665998, - 35.045193 - ], - [ - -80.665526, - 35.044877 - ], - [ - -80.664989, - 35.044543 - ], - [ - -80.664496, - 35.044174 - ], - [ - -80.663852, - 35.043876 - ], - [ - -80.663037, - 35.043717 + "type": "Feature", + "properties": {}, + "geometry": { + "type": "GeometryCollection", + "geometries": [ + { + "type": "Point", + "coordinates": [ + -80.660805, + 35.049392 + ] + }, + { + "type": "Polygon", + "coordinates": [ + [ + [ + -80.664582, + 35.044965 + ], + [ + -80.663874, + 35.04428 + ], + [ + -80.662586, + 35.04558 + ], + [ + -80.663444, + 35.046036 + ], + [ + -80.664582, + 35.044965 + ] + ] + ] + }, + { + "type": "LineString", + "coordinates": [ + [ + -80.662372, + 35.059509 + ], + [ + -80.662693, + 35.059263 + ], + [ + -80.662844, + 35.05893 + ], + [ + -80.66308, + 35.058332 + ], + [ + -80.663595, + 35.057753 + ], + [ + -80.663874, + 35.057401 + ], + [ + -80.66441, + 35.057033 + ], + [ + -80.664861, + 35.056787 + ], + [ + -80.665419, + 35.056506 + ], + [ + -80.665633, + 35.056312 + ], + [ + -80.666019, + 35.055891 + ], + [ + -80.666191, + 35.055452 + ], + [ + -80.666191, + 35.055171 + ], + [ + -80.666255, + 35.05489 + ], + [ + -80.666213, + 35.054222 + ], + [ + -80.666213, + 35.053924 + ], + [ + -80.665955, + 35.052905 + ], + [ + -80.665698, + 35.052044 + ], + [ + -80.665504, + 35.051482 + ], + [ + -80.665762, + 35.050481 + ], + [ + -80.66617, + 35.049725 + ], + [ + -80.666513, + 35.049286 + ], + [ + -80.666921, + 35.048531 + ], + [ + -80.667006, + 35.048215 + ], + [ + -80.667071, + 35.047775 + ], + [ + -80.667049, + 35.047389 + ], + [ + -80.666964, + 35.046985 + ], + [ + -80.666813, + 35.046353 + ], + [ + -80.666599, + 35.045966 + ], + [ + -80.666406, + 35.045615 + ], + [ + -80.665998, + 35.045193 + ], + [ + -80.665526, + 35.044877 + ], + [ + -80.664989, + 35.044543 + ], + [ + -80.664496, + 35.044174 + ], + [ + -80.663852, + 35.043876 + ], + [ + -80.663037, + 35.043717 + ] + ] + } ] - ] + } } ] } -- GitLab